From 9cdda498977cbd16d35080c5203b72eb4a7d6f5d Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Fri, 3 May 2019 11:02:25 +0800 Subject: [PATCH] Optimized contract loading. --- .../contract/engine/ContractCode.java | 3 +- .../contract/engine/ContractEngine.java | 6 +- .../contract/jvm/JVMContractEngine.java | 10 +-- .../contract/jvm/JavaContractCode.java | 7 +- .../ledger/core/ContractAccount.java | 4 - .../ContractEventSendOperationHandle.java | 73 ++++++++++++------- .../contract/LocalContractEventContext.java | 25 +++---- .../java/com/jd/blockchain/utils/Bytes.java | 54 ++++++++------ 8 files changed, 105 insertions(+), 77 deletions(-) diff --git a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java index d75f5b60..891acd4c 100644 --- a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java +++ b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java @@ -1,10 +1,11 @@ package com.jd.blockchain.contract.engine; import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.utils.Bytes; public interface ContractCode { - String getAddress(); + Bytes getAddress(); long getVersion(); diff --git a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java index e047bcc7..3f5a21c1 100644 --- a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java +++ b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java @@ -1,5 +1,7 @@ package com.jd.blockchain.contract.engine; +import com.jd.blockchain.utils.Bytes; + /** * 合约引擎; * @@ -16,7 +18,7 @@ public interface ContractEngine { * @param address * @return */ - ContractCode getContract(String address, long version); + ContractCode getContract(Bytes address, long version); /** * 装入合约代码;
@@ -27,6 +29,6 @@ public interface ContractEngine { * @param code * @return */ - ContractCode setupContract(String address, long version, byte[] code); + ContractCode setupContract(Bytes address, long version, byte[] code); } diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java index e07e5215..ea1ee9fa 100644 --- a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java @@ -4,18 +4,18 @@ import com.jd.blockchain.contract.engine.ContractCode; import com.jd.blockchain.contract.engine.ContractEngine; import com.jd.blockchain.runtime.Module; import com.jd.blockchain.runtime.RuntimeContext; +import com.jd.blockchain.utils.Bytes; public class JVMContractEngine implements ContractEngine { private RuntimeContext runtimeContext = RuntimeContext.get(); -// private RuntimeContext runtimeContext = ModularRuntimeContext.setup(System.getProperty("user.dir")); - private String getCodeName(String address, long version) { - return address + "_" + version; + private String getCodeName(Bytes address, long version) { + return address.toBase58() + "_" + version; } @Override - public ContractCode getContract(String address, long version) { + public ContractCode getContract(Bytes address, long version) { String codeName = getCodeName(address, version); Module module = runtimeContext.getDynamicModule(codeName); if (module == null) { @@ -25,7 +25,7 @@ public class JVMContractEngine implements ContractEngine { } @Override - public ContractCode setupContract(String address, long version, byte[] code) { + public ContractCode setupContract(Bytes address, long version, byte[] code) { //is there the contractCode before setup? if yes ,then return; ContractCode contractCode = getContract(address,version); if(contractCode != null){ diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java index da5d2fb8..90f68d5a 100644 --- a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java @@ -14,6 +14,7 @@ import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.engine.ContractCode; import com.jd.blockchain.runtime.Module; import com.jd.blockchain.utils.BaseConstant; +import com.jd.blockchain.utils.Bytes; /** * contract code based jvm @@ -22,18 +23,18 @@ import com.jd.blockchain.utils.BaseConstant; public class JavaContractCode implements ContractCode { private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); private Module codeModule; - private String address; + private Bytes address; private long version; private ContractEventContext contractEventContext; - public JavaContractCode(String address, long version, Module codeModule) { + public JavaContractCode(Bytes address, long version, Module codeModule) { this.address = address; this.version = version; this.codeModule = codeModule; } @Override - public String getAddress() { + public Bytes getAddress() { return address; } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java index 06817550..323960f3 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java @@ -8,11 +8,8 @@ import com.jd.blockchain.utils.io.BytesUtils; public class ContractAccount implements AccountHeader { - // private static final String CONTRACT_INFO_PREFIX = "INFO" + - // LedgerConsts.KEY_SEPERATOR; private static final Bytes CONTRACT_INFO_PREFIX = Bytes.fromString("INFO" + LedgerConsts.KEY_SEPERATOR); - // private static final String CHAIN_CODE_KEY = "CHAIN-CODE"; private static final Bytes CHAIN_CODE_KEY = Bytes.fromString("CHAIN-CODE"); private BaseAccount accBase; @@ -74,7 +71,6 @@ public class ContractAccount implements AccountHeader { private Bytes encodePropertyKey(Bytes key) { return CONTRACT_INFO_PREFIX.concat(key); -// return key.concatTo(CONTRACT_INFO_PREFIX); } } \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractEventSendOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractEventSendOperationHandle.java index 5c3b67cc..e1930a35 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractEventSendOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractEventSendOperationHandle.java @@ -1,49 +1,72 @@ package com.jd.blockchain.ledger.core.impl.handles; +import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; + +import org.springframework.stereotype.Service; + import com.jd.blockchain.contract.LocalContractEventContext; +import com.jd.blockchain.contract.engine.ContractCode; +import com.jd.blockchain.contract.engine.ContractEngine; import com.jd.blockchain.contract.engine.ContractServiceProviders; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.ledger.Operation; -import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.ledger.core.ContractAccount; +import com.jd.blockchain.ledger.core.ContractAccountSet; +import com.jd.blockchain.ledger.core.LedgerDataSet; +import com.jd.blockchain.ledger.core.LedgerException; +import com.jd.blockchain.ledger.core.LedgerService; +import com.jd.blockchain.ledger.core.OperationHandle; +import com.jd.blockchain.ledger.core.TransactionRequestContext; import com.jd.blockchain.ledger.core.impl.LedgerQueryService; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; -import org.springframework.stereotype.Service; - -import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; @Service public class ContractEventSendOperationHandle implements OperationHandle { + + private static final ContractEngine JVM_ENGINE; + + static { + JVM_ENGINE = ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine(); + } + @Override public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { ContractEventSendOperation contractOP = (ContractEventSendOperation) op; // 先从账本校验合约的有效性; // 注意:必须在前一个区块的数据集中进行校验,因为那是经过共识的数据;从当前新区块链数据集校验则会带来攻击风险:未经共识的合约得到执行; - if (!previousBlockDataset.getContractAccountSet().contains(contractOP.getContractAddress())) { - throw new LedgerException( - String.format("Target contract of ContractEvent was not registered! --[ContractAddress=%s]", - contractOP.getContractAddress())); + ContractAccountSet contractSet = previousBlockDataset.getContractAccountSet(); + if (!contractSet.contains(contractOP.getContractAddress())) { + throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", + contractOP.getContractAddress())); } - - //创建合约的账本上下文实例; - LedgerQueryService queryService = new LedgerQueryService(ledgerService) ; + + // 创建合约的账本上下文实例; + LedgerQueryService queryService = new LedgerQueryService(ledgerService); ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext); - // TODO:从合约引擎加载合约,执行合约代码; - ContractAccount contract = previousBlockDataset.getContractAccountSet() - .getContract(contractOP.getContractAddress()); - try { - // 在调用方法前,需要加载上下文信息; - LocalContractEventContext localContractEventContext = new LocalContractEventContext( - requestContext.getRequest().getTransactionContent().getLedgerHash(),contract.getChainCode(), contractOP.getEvent()); - localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()). - setLedgerContext(ledgerContext); - ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine().setupContract( - contract.getAddress().toBase58(),contract.getChaincodeVersion(),contract.getChainCode()). - processEvent(localContractEventContext); - } catch (Exception e) { - e.printStackTrace(); + // 先检查合约引擎是否已经加载合约;如果未加载,再从账本中读取合约代码并装载到引擎中执行; + ContractAccount contract = contractSet.getContract(contractOP.getContractAddress()); + if (contract == null) { + throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", + contractOP.getContractAddress())); } + + // 创建合约上下文; + LocalContractEventContext localContractEventContext = new LocalContractEventContext( + requestContext.getRequest().getTransactionContent().getLedgerHash(), contractOP.getEvent()); + localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) + .setLedgerContext(ledgerContext); + + ContractCode contractCode = JVM_ENGINE.getContract(contract.getAddress(), contract.getChaincodeVersion()); + if (contractCode == null) { + // 装载合约; + contractCode = JVM_ENGINE.setupContract(contract.getAddress(), contract.getChaincodeVersion(), + contract.getChainCode()); + } + + // 处理合约事件; + contractCode.processEvent(localContractEventContext); } @Override diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java index 7d366d0c..e18d7714 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java @@ -1,11 +1,10 @@ package com.jd.blockchain.contract; +import java.util.Set; + import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.utils.io.ByteArray; - -import java.util.Set; /** * @Author zhaogw @@ -21,10 +20,10 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable private Set contractOwners; private LedgerContext ledgerContext; - public LocalContractEventContext(HashDigest ledgeHash, byte[] chainCode, String event){ + public LocalContractEventContext(HashDigest ledgeHash, String event){ this.ledgeHash = ledgeHash; this.event = event; - this.chainCode = chainCode; +// this.chainCode = chainCode; } @Override @@ -92,14 +91,14 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable return this; } - public byte[] getChainCode() { - return chainCode; - } - - public LocalContractEventContext setChainCode(byte[] chainCode) { - this.chainCode = chainCode; - return this; - } +// public byte[] getChainCode() { +// return chainCode; +// } +// +// public LocalContractEventContext setChainCode(byte[] chainCode) { +// this.chainCode = chainCode; +// return this; +// } public LocalContractEventContext setArgs(byte[] args) { this.args = args; diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Bytes.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Bytes.java index 7b7921b8..2aeb488e 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Bytes.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/Bytes.java @@ -8,6 +8,12 @@ import com.jd.blockchain.utils.io.BytesSerializable; import com.jd.blockchain.utils.io.BytesUtils; import com.jd.blockchain.utils.io.RuntimeIOException; +/** + * Bytes 被设计为不可变对象; + * + * @author huanghaiquan + * + */ public class Bytes implements BytesSerializable { public static final Bytes EMPTY = new Bytes(BytesUtils.EMPTY_BYTES); @@ -38,7 +44,7 @@ public class Bytes implements BytesSerializable { } public Bytes() { - prefix=null; + prefix = null; data = null; hashCode = hashCode(1); } @@ -47,7 +53,7 @@ public class Bytes implements BytesSerializable { if (data == null) { throw new IllegalArgumentException("data is null!"); } - this.prefix=null; + this.prefix = null; this.data = data; hashCode = hashCode(1); } @@ -56,30 +62,30 @@ public class Bytes implements BytesSerializable { if (data == null) { throw new IllegalArgumentException("data is null!"); } - this.prefix=prefix; + this.prefix = prefix; this.data = data; -// setPrefix(prefix); + // setPrefix(prefix); hashCode = hashCode(1); } public Bytes(Bytes prefix, Bytes data) { -// setData(data.toBytes()); -// setPrefix(prefix); + // setData(data.toBytes()); + // setPrefix(prefix); if (data == null) { throw new IllegalArgumentException("data is null!"); } - this.prefix=prefix; + this.prefix = prefix; this.data = data.toBytes(); - + hashCode = hashCode(1); } -// private void setData(byte[] data) { -// if (data == null) { -// throw new IllegalArgumentException("data is null!"); -// } -// this.data = data; -// } + // private void setData(byte[] data) { + // if (data == null) { + // throw new IllegalArgumentException("data is null!"); + // } + // this.data = data; + // } /** * 返回当前的字节数组(不包含前缀对象); @@ -98,16 +104,16 @@ public class Bytes implements BytesSerializable { return new Bytes(Base58Utils.decode(str)); } -// /** -// * 连接指定的前缀后面;此操作并不会更改“prefix”参数; -// * -// * @param prefix -// * @return -// */ -// private Bytes setPrefix(Bytes prefix) { -// this.prefix = prefix; -// return this; -// } + // /** + // * 连接指定的前缀后面;此操作并不会更改“prefix”参数; + // * + // * @param prefix + // * @return + // */ + // private Bytes setPrefix(Bytes prefix) { + // this.prefix = prefix; + // return this; + // } public Bytes concat(Bytes key) { return new Bytes(this, key);