diff --git a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java index 423d59b5..39850af6 100644 --- a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java +++ b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java @@ -51,6 +51,8 @@ public interface DataCodes { public static final int TX_RESPONSE = 0x350; + public static final int TX_OP_RESULT = 0x360; + public static final int METADATA = 0x600; public static final int METADATA_INIT_SETTING = 0x610; @@ -81,6 +83,26 @@ public interface DataCodes { public static final int DATA = 0x900; + //contract related; + public static final int CONTRACT = 0xA00; + public static final int CONTRACT_BYTE = 0xA01; + + public static final int CONTRACT_SHORT = 0xA02; + + public static final int CONTRACT_INT = 0xA03; + + public static final int CONTRACT_LONG = 0xA04; + + public static final int CONTRACT_STRING = 0xA05; + + public static final int CONTRACT_BYTES = 0xA06; + + public static final int CONTRACT_BIG_INT = 0xA07; + //...0xA19 + public static final int CONTRACT_BIZ_CONTENT = 0xA20; + + public static final int CONTRACT_ARGS = 0xA21; + public static final int CONTRACT_RETURN = 0xA22; public static final int HASH = 0xB00; 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 fc7bc64e..962c767d 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 @@ -3,6 +3,9 @@ package com.jd.blockchain.contract.engine; import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.utils.Bytes; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + public interface ContractCode { Bytes getAddress(); diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java index b597558e..19822d00 100644 --- a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java +++ b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java @@ -1,6 +1,5 @@ package com.jd.blockchain.contract; -import com.jd.blockchain.ledger.ContractBizContent; import com.jd.blockchain.utils.Bytes; /** diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java index 06af2632..9f5588bb 100644 --- a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java +++ b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java @@ -1,6 +1,5 @@ package com.jd.blockchain.contract; -import com.jd.blockchain.ledger.ContractBizContent; import com.jd.blockchain.ledger.KVDataEntry; import com.jd.blockchain.ledger.KVDataObject; import com.jd.blockchain.utils.Bytes; diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java index 8f97fb10..25bc9aca 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java @@ -9,5 +9,7 @@ public interface ReadContract { @ContractEvent(name = "version-key") Long readVersion(String address, String key); + + int test(); } diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java index da34de03..e3d720a5 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java @@ -42,4 +42,9 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract { } return -1L; } + + @Override + public int test() { + return 0; + } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java index 01ed4d2f..a28a5fb5 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java @@ -162,8 +162,10 @@ public class AccountSet implements Transactional, MerkleProvable { * * 只有最新版本的账户才能可写的,其它都是只读; * - * @param address 账户地址; - * @param version 账户版本;如果指定为 -1,则返回最新版本; + * @param address + * 账户地址; + * @param version + * 账户版本;如果指定为 -1,则返回最新版本; * @return */ public BaseAccount getAccount(Bytes address, long version) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java index 4d23ec27..d7092e63 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java @@ -57,7 +57,7 @@ public class DataAccount implements AccountHeader, MerkleProvable { BytesValue bytesValue = BytesValueEntry.fromBytes(value); return baseAccount.setBytes(key, bytesValue, version); } - + /** * Return the latest version entry associated the specified key; If the key * doesn't exist, then return -1; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java index 6eda929a..33f589c5 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java @@ -1,10 +1,8 @@ package com.jd.blockchain.ledger.core; -import com.jd.blockchain.ledger.TransactionReturnMessage; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.OperationResult; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.ledger.*; + +import java.util.List; /** * 事务上下文; @@ -28,27 +26,45 @@ public interface LedgerTransactionContext { */ TransactionRequest getRequestTX(); + /** + * 提交对账本数据的修改,以指定的交易状态提交交易; + * + * @param txResult + * + * @return + */ + LedgerTransaction commit(TransactionState txResult); + /** * 提交对账本数据的修改,以指定的交易状态提交交易; * * @param txResult - * @param returnMessage + * @param operationResults * * @return */ - LedgerTransaction commit(TransactionState txResult, OperationResult... opResults); - + LedgerTransaction commit(TransactionState txResult, List operationResults); /** * 抛弃对账本数据的修改,以指定的交易状态提交交易;
- * - * 通常来说,当在开启事务之后,修改账本或者尝试提交交易({@link #commit(TransactionState, TransactionReturnMessage)})时发生错误,都应该抛弃数据,通过此方法记录一个表示错误状态的交易; - * + * + * 通常来说,当在开启事务之后,修改账本或者尝试提交交易({@link #commit(TransactionState)})时发生错误,都应该抛弃数据,通过此方法记录一个表示错误状态的交易; + * * @param txResult * @return */ LedgerTransaction discardAndCommit(TransactionState txResult); + /** + * 抛弃对账本数据的修改,以指定的交易状态提交交易;
+ * + * 通常来说,当在开启事务之后,修改账本或者尝试提交交易({@link #commit(TransactionState, List)})时发生错误,都应该抛弃数据,通过此方法记录一个表示错误状态的交易; + * + * @param txResult + * @return + */ + LedgerTransaction discardAndCommit(TransactionState txResult, List operationResults); + /** * 回滚事务,抛弃本次事务的所有数据更新; */ diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java index 9889a457..2a13690b 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java @@ -2,6 +2,8 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; +import com.jd.blockchain.utils.concurrent.AsyncFuture; + public interface OperationHandle { @@ -14,8 +16,9 @@ public interface OperationHandle { boolean support(Class operationType); /** - * 解析和执行操作; - * + * 同步解析和执行操作; + * + * * @param op * 操作实例; * @param newBlockDataset @@ -24,8 +27,28 @@ public interface OperationHandle { * 交易请求上下文; * @param previousBlockDataset * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; + * + * @return 操作执行结果 */ byte[] process(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); +// /** +// * 异步解析和执行操作; +// * TODO 未来规划实现 +// * +// * +// * @param op +// * 操作实例; +// * @param newBlockDataset +// * 需要修改的新区块的数据集; +// * @param requestContext +// * 交易请求上下文; +// * @param previousBlockDataset +// * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; +// * +// * @return 操作执行结果 +// */ +// AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, +// LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java index 66fbda39..2806b5af 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java @@ -276,15 +276,15 @@ public class LedgerQueryService implements BlockchainQueryService { KVDataEntry[] entries = new KVDataEntry[keys.length]; long ver; for (int i = 0; i < entries.length; i++) { - ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); + final String currKey = keys[i]; - dataAccount.getBytes(Bytes.fromString(keys[i]), 1); + ver = dataAccount.getDataVersion(Bytes.fromString(currKey)); if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new KVDataObject(currKey, -1, null); } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); - entries[i] = new KVDataObject(keys[i], ver, value); + BytesValue value = dataAccount.getBytes(Bytes.fromString(currKey), ver); + entries[i] = new KVDataObject(currKey, ver, value); } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java index 0aae1738..af9294bf 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java @@ -1,5 +1,6 @@ package com.jd.blockchain.ledger.core.impl; +import java.util.List; import java.util.Stack; import com.jd.blockchain.binaryproto.BinaryProtocol; @@ -348,9 +349,14 @@ public class LedgerTransactionalEditor implements LedgerEditor { public TransactionRequest getRequestTX() { return txRequest; } - + + @Override + public LedgerTransaction commit(TransactionState txResult) { + return commit(txResult, null); + } + @Override - public LedgerTransaction commit(TransactionState txResult, OperationResult... opResults) { + public LedgerTransaction commit(TransactionState txResult, List operationResults) { checkTxState(); // capture snapshot @@ -359,7 +365,8 @@ public class LedgerTransactionalEditor implements LedgerEditor { // LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, // txResult, txDataSnapshot); - LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null, opResults); + + LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null, operationResultArray(operationResults)); this.txset.add(tx); // this.txset.commit(); @@ -374,9 +381,14 @@ public class LedgerTransactionalEditor implements LedgerEditor { committed = true; return tx; } - + @Override public LedgerTransaction discardAndCommit(TransactionState txResult) { + return discardAndCommit(txResult, null); + } + + @Override + public LedgerTransaction discardAndCommit(TransactionState txResult, List operationResults) { checkTxState(); // 未处理 @@ -385,7 +397,7 @@ public class LedgerTransactionalEditor implements LedgerEditor { // TransactionStagedSnapshot txDataSnapshot = takeSnapshot(); // LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, // txResult, txDataSnapshot); - LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null); + LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null, operationResultArray(operationResults)); this.txset.add(tx); // this.txset.commit(); @@ -410,6 +422,15 @@ public class LedgerTransactionalEditor implements LedgerEditor { return txDataSnapshot; } + private OperationResult[] operationResultArray(List operationResults) { + OperationResult[] operationResultArray = null; + if (operationResults != null && !operationResults.isEmpty()) { + operationResultArray = new OperationResult[operationResults.size()]; + operationResults.toArray(operationResultArray); + } + return operationResultArray; + } + @Override public void rollback() { if (this.rollbacked) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java index c251af2d..bfb8a08d 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java @@ -50,9 +50,12 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { private TransactionBatchResult batchResult; /** - * @param newBlockEditor 新区块的数据编辑器; - * @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; - * @param opHandles 操作处理对象注册表; + * @param newBlockEditor + * 新区块的数据编辑器; + * @param previousBlockDataset + * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; + * @param opHandles + * 操作处理对象注册表; */ public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataSet previousBlockDataset, OperationHandleRegisteration opHandles, LedgerService ledgerService) { @@ -73,9 +76,12 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { public TransactionResponse schedule(TransactionRequest request) { // 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上; LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); - TransactionState txResult; - OperationResult[] opResults = null; + TransactionState result; + + List operationResults = new ArrayList<>(); + try { + LedgerDataSet dataset = txCtx.getDataSet(); TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request); // TODO: 验证签名者的有效性; @@ -95,44 +101,44 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { OperationHandleContext handleContext = new OperationHandleContext() { @Override public void handle(Operation operation) { - // assert; Instance of operation are one of User related operations or - // DataAccount related operations; + //assert; Instance of operation are one of User related operations or DataAccount related operations; OperationHandle hdl = opHandles.getHandle(operation.getClass()); hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService); } }; OperationHandle opHandle; - int contractOpIndex = 0; - List opResultList = new ArrayList(); - int opIdx = 0; + int opIndex = 0; for (Operation op : ops) { opHandle = opHandles.getHandle(op.getClass()); - byte[] retn = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService); - if (op instanceof ContractEventSendOperation) { - // 支持返回值的操作; - opResultList.add(new OperationResultData(opIdx, retn)); + byte[] opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService); + if (opResult != null) { + operationResults.add(new OperationResultData(opIndex, opResult)); } - - opIdx++; + opIndex++; } // 提交交易(事务); - txResult = TransactionState.SUCCESS; - opResults = opResultList.toArray(new OperationResult[opResultList.size()]); - txCtx.commit(txResult, opResults); + result = TransactionState.SUCCESS; + + txCtx.commit(result, operationResults); } catch (LedgerException e) { // TODO: 识别更详细的异常类型以及执行对应的处理; - txResult = TransactionState.LEDGER_ERROR; - txCtx.discardAndCommit(TransactionState.LEDGER_ERROR); + result = TransactionState.LEDGER_ERROR; + txCtx.discardAndCommit(TransactionState.LEDGER_ERROR, operationResults); LOGGER.warn(String.format("Transaction rollback caused by the ledger exception! --[TxHash=%s] --%s", request.getHash().toBase58(), e.getMessage()), e); } catch (Exception e) { - txResult = TransactionState.SYSTEM_ERROR; - txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR); + result = TransactionState.SYSTEM_ERROR; + txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); LOGGER.warn(String.format("Transaction rollback caused by the system exception! --[TxHash=%s] --%s", request.getHash().toBase58(), e.getMessage()), e); } - TxResponseHandle resp = new TxResponseHandle(request, txResult, opResults); + TxResponseHandle resp = new TxResponseHandle(request, result); + + if (!operationResults.isEmpty()) { + OperationResult[] operationResultArray = new OperationResult[operationResults.size()]; + resp.setOperationResults(operationResults.toArray(operationResultArray)); + } responseList.add(resp); @@ -213,12 +219,11 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { private TransactionState result; - private OperationResult[] opResults; + private OperationResult[] operationResults; - public TxResponseHandle(TransactionRequest request, TransactionState result, OperationResult... opResults) { + public TxResponseHandle(TransactionRequest request, TransactionState result) { this.request = request; this.result = result; - this.opResults = opResults; } @Override @@ -247,8 +252,12 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { } @Override - public OperationResult[] getContractReturn() { - return opResults; + public OperationResult[] getOperationResults() { + return operationResults; + } + + public void setOperationResults(OperationResult[] operationResults) { + this.operationResults = operationResults; } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java index a6b2ac85..a71b26d1 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java @@ -1,5 +1,6 @@ package com.jd.blockchain.ledger.core.impl.handles; +import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.LedgerDataSet; @@ -8,8 +9,12 @@ import com.jd.blockchain.ledger.core.OperationHandle; import com.jd.blockchain.ledger.core.TransactionRequestContext; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.concurrent.AsyncFuture; import org.springframework.stereotype.Service; +import java.util.concurrent.Future; + @Service public class ContractCodeDeployOperationHandle implements OperationHandle { @@ -20,12 +25,18 @@ public class ContractCodeDeployOperationHandle implements OperationHandle { // TODO: 校验合约代码的正确性; // TODO: 请求者应该提供合约账户的公钥签名,已确定注册的地址的唯一性; + dataset.getContractAccountSet().deploy(contractOP.getContractID().getAddress(), contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode()); - //No result; + return null; } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { +// return null; +// } + @Override public boolean support(Class operationType) { return ContractCodeDeployOperation.class.isAssignableFrom(operationType); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java index cc1f16b9..9844d4c6 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java @@ -1,5 +1,7 @@ package com.jd.blockchain.ledger.core.impl.handles; +import com.jd.blockchain.binaryproto.BinaryProtocol; +import com.jd.blockchain.utils.concurrent.AsyncFuture; import org.springframework.stereotype.Service; import com.jd.blockchain.binaryproto.DataContractRegistry; @@ -26,15 +28,19 @@ public class DataAccountKVSetOperationHandle implements OperationHandle { LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { DataAccountKVSetOperation kvWriteOp = (DataAccountKVSetOperation) op; DataAccount account = dataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); - KVWriteEntry[] writeset = kvWriteOp.getWriteSet(); - for (KVWriteEntry kvw : writeset) { + KVWriteEntry[] writeSet = kvWriteOp.getWriteSet(); + for (KVWriteEntry kvw : writeSet) { +// byte[] value = BinaryProtocol.encode(kvw.getValue(), BytesValue.class); account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); } - - // No return value; return null; } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { +// return null; +// } + @Override public boolean support(Class operationType) { return DataAccountKVSetOperation.class.isAssignableFrom(operationType); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java index 29178dab..8bce4efd 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java @@ -9,6 +9,7 @@ import com.jd.blockchain.ledger.core.OperationHandle; import com.jd.blockchain.ledger.core.TransactionRequestContext; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; +import com.jd.blockchain.utils.concurrent.AsyncFuture; import org.springframework.stereotype.Service; @Service @@ -20,15 +21,19 @@ public class DataAccountRegisterOperationHandle implements OperationHandle { DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op; BlockchainIdentity bid = dataAccountRegOp.getAccountID(); - // TODO: 校验用户身份; + //TODO: 校验用户身份; - // TODO: 请求者应该提供数据账户的公钥签名,已确定注册的地址的唯一性; + //TODO: 请求者应该提供数据账户的公钥签名,已确定注册的地址的唯一性; dataset.getDataAccountSet().register(bid.getAddress(), bid.getPubKey(), null); - // No return value; return null; } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { +// return null; +// } + @Override public boolean support(Class operationType) { return DataAccountRegisterOperation.class.isAssignableFrom(operationType); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java index ea1b40b7..a5b592ab 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java @@ -5,7 +5,13 @@ import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; 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.Operation; import com.jd.blockchain.ledger.core.ContractAccount; +import com.jd.blockchain.ledger.core.LedgerDataSet; +import com.jd.blockchain.ledger.core.LedgerService; +import com.jd.blockchain.ledger.core.TransactionRequestContext; +import com.jd.blockchain.ledger.core.impl.OperationHandleContext; +import com.jd.blockchain.utils.concurrent.AsyncFuture; public class JVMContractEventSendOperationHandle extends AbtractContractEventHandle { @@ -26,4 +32,12 @@ public class JVMContractEventSendOperationHandle extends AbtractContractEventHan return contractCode; } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, +// TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, +// OperationHandleContext handleContext, LedgerService ledgerService) { +// // TODO Auto-generated method stub +// return null; +// } + } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java index bc6e1cb7..d4072aa7 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java @@ -8,20 +8,32 @@ 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.OperationHandleContext; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.concurrent.AsyncFuture; + public class UserRegisterOperationHandle implements OperationHandle { @Override public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { + + UserRegisterOperation userRegOp = (UserRegisterOperation) op; BlockchainIdentity bid = userRegOp.getUserID(); - dataset.getUserAccountSet().register(bid.getAddress(), bid.getPubKey()); - // No return value; - return null; + Bytes userAddress = bid.getAddress(); + + dataset.getUserAccountSet().register(userAddress, bid.getPubKey()); + + return userAddress.toBytes(); } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { +// return null; +// } + @Override public boolean support(Class operationType) { return UserRegisterOperation.class.isAssignableFrom(operationType); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java index 8191e4d6..1f3fb3ed 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java @@ -116,7 +116,7 @@ public class ContractInvokingTest { TransactionResponse resp = txbatchProcessor.schedule(txReq); verify(contractInstance, times(1)).issue(asset, issueAmount); - OperationResult[] opResults = resp.getContractReturn(); + OperationResult[] opResults = resp.getOperationResults(); assertEquals(1, opResults.length); assertEquals(0, opResults[0].getIndex()); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java new file mode 100644 index 00000000..6214c24e --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -0,0 +1,157 @@ +package com.jd.blockchain.contract; + +import com.jd.blockchain.binaryproto.*; +import com.jd.blockchain.contract.param.*; +import com.jd.blockchain.utils.io.BytesUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ContractSerializeUtils { + + final static int INT_LENGTH = 4; + + static Map, Class> MAP = new HashMap<>(); + + static { + MAP.put(byte[].class, WRAP_BYTES.class); + MAP.put(Short.class, WRAP_SHORT.class); + MAP.put(short.class, WRAP_SHORT.class); + MAP.put(Integer.class, WRAP_INT.class); + MAP.put(int.class, WRAP_INT.class); + MAP.put(Long.class, WRAP_LONG.class); + MAP.put(long.class, WRAP_LONG.class); + MAP.put(String.class, WRAP_STRING.class); + + DataContractRegistry.register(WRAP_BYTES.class); + DataContractRegistry.register(WRAP_SHORT.class); + DataContractRegistry.register(WRAP_INT.class); + DataContractRegistry.register(WRAP_LONG.class); + DataContractRegistry.register(WRAP_STRING.class); + } + + public static boolean support(Class clazz) { + if (clazz.isAnnotationPresent(DataContract.class) || MAP.containsKey(clazz)) { + return true; + } + return false; + } + + public static byte[] serialize(Object data) { + + if (data == null) { + return null; + } + + Class clazz = data.getClass(); + Class serialClass; + Object wrapData = data; + if (clazz.isAnnotationPresent(DataContract.class)) { + serialClass = clazz; + } else { + // 判断类型是否可以序列化 + Class wrapClass = MAP.get(clazz); + if (wrapClass == null) { + throw new IllegalArgumentException("There are Un-Support Type !!!"); + } + serialClass = wrapClass; + + if (wrapClass.equals(WRAP_BYTES.class)) { + wrapData = (WRAP_BYTES) () -> (byte[])data; + } else if (wrapClass.equals(WRAP_INT.class)) { + wrapData = (WRAP_INT) () -> (int)data; + } else if (wrapClass.equals(WRAP_LONG.class)) { + wrapData = (WRAP_LONG) () -> (long)data; + } else if (wrapClass.equals(WRAP_SHORT.class)) { + wrapData = (WRAP_SHORT) () -> (short)data; + } else if (wrapClass.equals(WRAP_STRING.class)) { + wrapData = (WRAP_STRING) () -> (String)data; + } + } + // 按照对应接口进行序列化 + // 生成该接口对应的对象 + return BinaryProtocol.encode(wrapData, serialClass); + } + + public static byte[] serializeArray(Object[] datas) { + if (datas == null || datas.length == 0) { + return null; + } + int contentBytesSize = 0; + byte[] header = new byte[(datas.length + 1) * 4]; + System.arraycopy(BytesUtils.toBytes(datas.length), 0, header, 0, INT_LENGTH); + int offset = INT_LENGTH; + + List serialBytesList = new ArrayList<>(); + for (Object data : datas) { + // 按照对应接口进行序列化 + byte[] currBytes = serialize(data); + // 长度写入 + System.arraycopy(BytesUtils.toBytes(currBytes.length), 0, header, offset, INT_LENGTH); + serialBytesList.add(currBytes); + contentBytesSize += currBytes.length; + offset += INT_LENGTH; + } + + // 填充content + byte[] content = new byte[contentBytesSize]; + offset = 0; + for (byte[] bytes : serialBytesList) { + System.arraycopy(bytes, 0, content, offset, bytes.length); + offset += bytes.length; + } + // 将header和content组装 + return BytesUtils.concat(header, content); + } + + public static Object[] resolveArray(byte[] bytes) { + if (bytes == null || bytes.length == 0) { + return null; + } + byte[] lengthBytes = new byte[INT_LENGTH]; + System.arraycopy(bytes, 0, lengthBytes, 0, INT_LENGTH); + int length = BytesUtils.toInt(lengthBytes); + Object[] datas = new Object[length]; + + int headerOffset = INT_LENGTH; + int contentStart = (length + 1) * INT_LENGTH; + + for (int i = 0 ; i < length; i++) { + byte[] currDataLengthBytes = new byte[INT_LENGTH]; + System.arraycopy(bytes, headerOffset, currDataLengthBytes, 0, INT_LENGTH); + int currDataLength = BytesUtils.toInt(currDataLengthBytes); + // 读取 + byte[] dataBytes = new byte[currDataLength]; + System.arraycopy(bytes, contentStart, dataBytes, 0, currDataLength); + + datas[i] = resolve(dataBytes); + + contentStart += currDataLength; + headerOffset += INT_LENGTH; + } + + return datas; + } + + public static Object resolve(byte[] bytes) { + // 反序列化该接口 + Object currData = BinaryProtocol.decode(bytes); + + // 代理对象类型不能使用class判断,只能使用instanceof + if (currData instanceof WRAP_STRING) { + return ((WRAP_STRING) currData).getValue(); + } else if (currData instanceof WRAP_INT) { + return ((WRAP_INT) currData).getValue(); + } else if (currData instanceof WRAP_LONG) { + return ((WRAP_LONG) currData).getValue(); + } else if (currData instanceof WRAP_BYTES) { + return ((WRAP_BYTES) currData).getValue(); + } else if (currData instanceof WRAP_SHORT) { + return ((WRAP_SHORT) currData).getValue(); + } else { + return currData; + } + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils2.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils2.java new file mode 100644 index 00000000..22bbdb38 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils2.java @@ -0,0 +1,195 @@ +//package com.jd.blockchain.contract; +// +//import com.jd.blockchain.binaryproto.BinaryProtocol; +//import com.jd.blockchain.binaryproto.DataContract; +//import com.jd.blockchain.consts.DataCodes; +//import com.jd.blockchain.ledger.*; +//import com.jd.blockchain.utils.Bytes; +//import com.jd.blockchain.utils.IllegalDataException; +//import org.springframework.util.ReflectionUtils; +// +//import java.nio.ByteBuffer; +//import java.util.Arrays; +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +// +///** +// * @author zhaogw +// * date 2019/5/16 18:05 +// */ +//public class ContractSerializeUtils { +// public static Map> DATA_CONTRACT_MAP = new HashMap<>(); +// public static final Integer[] PRIMITIVE_DATA_CODES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32, +// DataCodes.CONTRACT_INT64, DataCodes.CONTRACT_BIG_INT,DataCodes.CONTRACT_TEXT, DataCodes.CONTRACT_BINARY }; +// +// /** +// * serialize the Object[] by List list; +// * @param objArr +// * @param dataContractList +// * @return +// */ +// public static byte[] serializeMethodParam(Object[] objArr,List dataContractList) { +// byte[][] result = new byte[objArr.length][]; +// //将method中形参转换为实体对象,每个形参都必须为@DataContract类型;每个形参使用系统的BinaryProtocol来进行序列化,如果有5个参数,则使用5次序列化; +// int sum = 0; +// +// for(int i=0;i dataContractList) { +// Object result[] = new Object[dataContractList.size()]; +// ByteBuffer byteBuffer = ByteBuffer.allocate(params.length); +// byteBuffer.put(params); +// int paramNums = byteBuffer.getInt(0); +// +// if(paramNums != dataContractList.size()){ +// throw new IllegalArgumentException("deserialize Method param. params'length in byte[] != method's param length"); +// } +// +// int offsetPosition = (1 + dataContractList.size())*4; //start position of real data; +// for(int i=0; i classObj = getDataIntf().get(dataContract.code()); +// try { +// result[i] = ReflectionUtils.invokeMethod(classObj.getMethod("getValue"),object); +// } catch (NoSuchMethodException e) { +// throw new IllegalStateException("no getValue(). detail="+e.getMessage()); +// } +// }else { +// result[i] = object; +// } +// byteBuffer1.clear(); +// } +// +// return result; +// } +// +// +// /** +// * the param types that we can support; +// * @param +// * @return +// */ +// public static Map > getDataIntf(){ +// DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT8, CONTRACT_INT8.class); +// DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT16, CONTRACT_INT16.class); +// DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT32, CONTRACT_INT32.class); +// DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT64, CONTRACT_INT64.class); +// DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class); +// DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class); +// DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIZ_CONTENT, ContractBizContent.class); +// return DATA_CONTRACT_MAP; +// } +// +// public static boolean isPrimitiveType(int dataContractCode){ +// return Arrays.asList(PRIMITIVE_DATA_CODES).contains(dataContractCode); +// } +// +// private static Object regenObj(DataContract dataContract, Object object){ +// if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT8.class)){ +// +// return (CONTRACT_INT8) () -> Byte.parseByte(object.toString()); +// }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT16.class)){ +// return (CONTRACT_INT16) () -> Short.parseShort(object.toString()); +// }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT32.class)){ +// return (CONTRACT_INT32) () -> Integer.parseInt(object.toString()); +// }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT64.class)){ +// return (CONTRACT_INT64) () -> Long.parseLong(object.toString()); +// }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_TEXT.class)){ +// return (CONTRACT_TEXT) () -> object.toString(); +// }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BINARY.class)){ +// return (CONTRACT_BINARY) () -> (Bytes) object; +// }else if(getDataIntf().get(dataContract.code()).equals(ContractBizContent.class)){ +// ContractBizContent contractBizContent = (ContractBizContent)object; +// return contractBizContent; +// }else { +// throw new IllegalDataException("cann't get new Object by dataContract and object."); +// } +// } +// +// /** +// * get contractType(contain @DataContract) by primitive class type; +// * some class type can be supported default (byte/char/int/long/String/Bytes, and so on). +// * in other words, need not contain the @DataContract in its class for contract param's serialization or deserialization. +// * @param classType +// * @return +// */ +// private static Class getContractTypeByPrimitiveType(Class classType) { +// if(classType.equals(byte.class) || classType.equals(Byte.class)){ +// return CONTRACT_INT8.class; +// }else if(classType.equals(char.class) || classType.equals(Character.class)){ +// return CONTRACT_INT16.class; +// }else if(classType.equals(int.class) || classType.equals(Integer.class)){ +// return CONTRACT_INT32.class; +// }else if(classType.equals(long.class) || classType.equals(Long.class)){ +// return CONTRACT_INT64.class; +// }else if(classType.equals(String.class)){ +// return CONTRACT_TEXT.class; +// }else if(classType.equals(Bytes.class)){ +// return CONTRACT_BINARY.class; +// }else { +// throw new IllegalDataException(String.format("no support the classType=%s, please check @DataContract.",classType.toString())); +// } +// } +// +// public static DataContract parseDataContract(Class classType){ +// DataContract dataContract = classType.getAnnotation(DataContract.class); +// //if the param's class Type don't contain @DataContract, then check parameterAnnotations of this method. +// if(dataContract == null){ +// boolean canPass = false; +// //if parameterAnnotations don't contain @DataContract, is it primitive type? +// Class contractType = getContractTypeByPrimitiveType(classType); +// dataContract = contractType.getAnnotation(DataContract.class); +// } +// if(!getDataIntf().containsKey(dataContract.code())){ +// throw new IllegalArgumentException(String.format( +// "for now, this @dataContract(code=%s) is forbidden in the param list.",dataContract.code())); +// } +// return dataContract; +// } +//} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java index 96ec1fc3..ae5c6e49 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java @@ -1,13 +1,11 @@ package com.jd.blockchain.contract; -import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Set; +import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.utils.IllegalDataException; public class ContractType { @@ -68,45 +66,59 @@ public class ContractType { * @param delaredInterface 声明合约的接口类型; * @return */ - public static ContractType resolve(Class delaredInterface) { - ContractType contractType = new ContractType(); + public static ContractType resolve(Class contractIntf) { + + // 接口上必须有注解 + if (!contractIntf.isAnnotationPresent(Contract.class)) { + throw new IllegalDataException("It is not a Contract Type, because there is not @Contract !"); + } - Annotation annotation = delaredInterface.getDeclaredAnnotation(Contract.class); + Method[] classMethods = contractIntf.getDeclaredMethods(); - // contains: @Contract? - boolean isContractType = annotation != null ? true : false; - if (!isContractType) { - throw new IllegalDataException("The specified type is not annotated by @Contract!"); + if (classMethods.length == 0) { + throw new IllegalDataException("This interface have not any methods !"); } - // contractIntf contains @Contract and @ContractEvent; - Method[] classMethods = delaredInterface.getDeclaredMethods(); + ContractType contractType = new ContractType(); + for (Method method : classMethods) { + // if current method contains @ContractEvent,then put it in this map; ContractEvent contractEvent = method.getAnnotation(ContractEvent.class); + if (contractEvent != null) { - String eventName_ = contractEvent.name(); - // if annoMethodMap has contained the eventName, too many same eventNames exists - // probably, say NO! - if (contractType.events.containsKey(eventName_)) { + String eventName = contractEvent.name(); + //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! + if(contractType.events.containsKey(eventName)){ throw new ContractException("there is repeat definition of contractEvent to @ContractEvent."); } - // check param's type is fit for need. + //check param's type is fit for need. Class[] paramTypes = method.getParameterTypes(); - List dataContractList = new ArrayList(); - for (Class curParamType : paramTypes) { - throw new IllegalStateException("Not implemented!"); -// DataContract dataContract = ContractSerializeUtils.parseDataContract(curParamType); -// dataContractList.add(dataContract); + for(Class currParamType : paramTypes) { + if (!ContractSerializeUtils.support(currParamType)) { + throw new IllegalStateException(String.format("Param Type = %s can not support !!!", currParamType.getName())); + } + } + + // 判断返回值是否可序列化 + Class returnType = method.getReturnType(); + if (!ContractSerializeUtils.support(returnType)) { + throw new IllegalStateException(String.format("Return Type = %s can not support !!!", returnType.getName())); } -// if(dataContractList.size()>0){ -// contractType.dataContractMap.put(method,dataContractList); -// } - contractType.events.put(eventName_, method); - contractType.handleMethods.put(method, eventName_); + contractType.events.put(eventName, method); + contractType.handleMethods.put(method, eventName); } } return contractType; } + + @Override + public String toString() { + return "ContractType{" + + "name='" + name + '\'' + + ", events=" + events + + ", handleMethods=" + handleMethods + + '}'; + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java new file mode 100644 index 00000000..928d5979 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java @@ -0,0 +1,39 @@ +package com.jd.blockchain.contract; + +import com.jd.blockchain.utils.IllegalDataException; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +public class EventResult { + + private static final long MAX_SECONDS = 30; + + private CompletableFuture data = new CompletableFuture<>(); + + private int opIndex; + + public EventResult() { + } + + public EventResult(int opIndex) { + this.opIndex = opIndex; + } + + public void done(T value) { + data.complete(value); + } + + public int opIndex() { + return this.opIndex; + } + + public T get() { + try { + // 防止长时间阻塞 + return data.get(MAX_SECONDS, TimeUnit.SECONDS); + } catch (Exception e) { + throw new IllegalDataException(e.getMessage()); + } + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_BYTES.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_BYTES.java new file mode 100644 index 00000000..b99e6786 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_BYTES.java @@ -0,0 +1,13 @@ +package com.jd.blockchain.contract.param; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code = DataCodes.CONTRACT_BYTES) +public interface WRAP_BYTES { + + @DataField(order = 1, primitiveType = PrimitiveType.BYTES) + byte[] getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_INT.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_INT.java new file mode 100644 index 00000000..48e2d1d9 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_INT.java @@ -0,0 +1,13 @@ +package com.jd.blockchain.contract.param; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code = DataCodes.CONTRACT_INT) +public interface WRAP_INT { + + @DataField(order = 1, primitiveType = PrimitiveType.INT32) + int getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_LONG.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_LONG.java new file mode 100644 index 00000000..8b402b04 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_LONG.java @@ -0,0 +1,13 @@ +package com.jd.blockchain.contract.param; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code = DataCodes.CONTRACT_LONG) +public interface WRAP_LONG { + + @DataField(order = 1, primitiveType = PrimitiveType.INT64) + long getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_SHORT.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_SHORT.java new file mode 100644 index 00000000..d30cc366 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_SHORT.java @@ -0,0 +1,13 @@ +package com.jd.blockchain.contract.param; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code = DataCodes.CONTRACT_SHORT) +public interface WRAP_SHORT { + + @DataField(order = 1, primitiveType = PrimitiveType.INT16) + short getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_STRING.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_STRING.java new file mode 100644 index 00000000..7c475c79 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_STRING.java @@ -0,0 +1,13 @@ +package com.jd.blockchain.contract.param; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code = DataCodes.CONTRACT_STRING) +public interface WRAP_STRING { + + @DataField(order = 1, primitiveType = PrimitiveType.TEXT) + String getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java index 9b0219b0..1530fb0c 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java @@ -44,5 +44,4 @@ public interface ContractEventSendOperation extends Operation { */ @DataField(order = 5, primitiveType = PrimitiveType.INT64) long getTxOpTime(); - } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java index 87ff2bdc..a6b25344 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java @@ -5,13 +5,12 @@ import com.jd.blockchain.binaryproto.DataField; import com.jd.blockchain.binaryproto.PrimitiveType; import com.jd.blockchain.consts.DataCodes; -@DataContract(code = DataCodes.CONTRACT_RETURN) +@DataContract(code = DataCodes.TX_OP_RESULT) public interface OperationResult { - @DataField(order = 1, primitiveType = PrimitiveType.INT32) - int getIndex(); - - @DataField(order = 2, primitiveType = PrimitiveType.BYTES) - byte[] getResult(); + @DataField(order=1, primitiveType = PrimitiveType.INT32) + int getIndex(); + @DataField(order=2, primitiveType = PrimitiveType.BYTES) + byte[] getResult(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java index a96fe407..399596a3 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java @@ -1,26 +1,35 @@ package com.jd.blockchain.ledger; + public class OperationResultData implements OperationResult { - private int index; + private int index; + + private byte[] result; + + public OperationResultData() { + } - private byte[] result; + public OperationResultData(int index, byte[] result) { + this.index = index; + this.result = result; + } - public OperationResultData() { - } + @Override + public int getIndex() { + return index; + } - public OperationResultData(int operationIndex, byte[] result) { - this.index = operationIndex; - this.result = result; - } + @Override + public byte[] getResult() { + return result; + } - @Override - public int getIndex() { - return index; - } + public void setIndex(int index) { + this.index = index; + } - @Override - public byte[] getResult() { - return result; - } + public void setResult(byte[] result) { + this.result = result; + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java index 26b744bd..542a3a49 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java @@ -49,6 +49,6 @@ public interface Transaction extends NodeRequest, HashObject { * * @return */ - @DataField(order = 4, refContract = true, list = true) + @DataField(order=4, list = true, refContract=true) OperationResult[] getOperationResults(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java index 62fc3ebe..3856f668 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java @@ -27,7 +27,7 @@ public class TransactionRespHandle implements TransactionResponse { private TransactionState globalResult; - private OperationResult[] contractReturn; + private OperationResult[] operationResults; public TransactionRespHandle(TransactionRequest request, TransactionState result, TransactionState globalResult) { this.request = request; @@ -51,8 +51,8 @@ public class TransactionRespHandle implements TransactionResponse { this.result = result; } - public void setContractReturn(OperationResult[] contractReturn) { - this.contractReturn = contractReturn; + public void setOperationResults(OperationResult[] operationResults) { + this.operationResults = operationResults; } public LedgerBlock getBlock() { @@ -97,7 +97,7 @@ public class TransactionRespHandle implements TransactionResponse { } @Override - public OperationResult[] getContractReturn() { - return contractReturn; + public OperationResult[] getOperationResults() { + return operationResults; } } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java index 6d6916a0..662d595b 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java @@ -63,6 +63,6 @@ public interface TransactionResponse { * * @return */ - @DataField(order = 6, list = true, refContract = true) - OperationResult[] getContractReturn(); + @DataField(order=6, list=true, refContract = true) + OperationResult[] getOperationResults(); } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionReturnMessage.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionReturnMessage.java deleted file mode 100644 index 94cef8b0..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionReturnMessage.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.consts.DataCodes; - -@DataContract(code= DataCodes.TX_RETURN_MESSAGE) -public interface TransactionReturnMessage { - - /** - * 合约返回值列表 - * - * @return - */ - @DataField(order=1, list = true, refContract=true) - OperationResult[] getContractReturn(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionReturnMessageData.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionReturnMessageData.java deleted file mode 100644 index 7f324158..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionReturnMessageData.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jd.blockchain.ledger; - -import java.util.ArrayList; -import java.util.List; - -public class TransactionReturnMessageData implements TransactionReturnMessage { - - private List contractReturnMessages = new ArrayList<>(); - - public void addContractReturnMessage(OperationResult contractReturnMessage) { - contractReturnMessages.add(contractReturnMessage); - } - - public boolean isContractReturnEmpty() { - return contractReturnMessages.isEmpty(); - } - - @Override - public OperationResult[] getContractReturn() { - if (isContractReturnEmpty()) { - return null; - } - OperationResult[] crms = new OperationResult[contractReturnMessages.size()]; - return contractReturnMessages.toArray(crms); - } -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java index 9f2d97d1..b38d06fa 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.ContractEventSendOperation; @@ -29,7 +30,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe private static final ContractCodeDeployOperationBuilderImpl CONTRACT_CODE_DEPLOY_OP_BUILDER = new ContractCodeDeployOperationBuilderImpl(); - private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); +// private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter(); @@ -89,6 +90,11 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); } + @Override + public EventResult result(ContractEventExecutor execute) { + return contractInvoProxyBuilder.execute(execute); + } + public Collection getOperations() { // TODO: 合并操作列表中可能的重复操作; return operationList; @@ -130,7 +136,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe operationList.add(op); return op; } - } private class DataAccountKVSetOperationBuilderFilter implements DataAccountKVSetOperationBuilder { @@ -235,25 +240,35 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe operationList.add(op); return op; } - } private class ContractEventSendOperationBuilderFilter implements ContractEventSendOperationBuilder { @Override public ContractEventSendOperation send(String address, String event, byte[] args) { - ContractEventSendOperation op = CONTRACT_EVENT_SEND_OP_BUILDER.send(address, event, args); - operationList.add(op); - return op; + return send(Bytes.fromBase58(address), event, args); } @Override public ContractEventSendOperation send(Bytes address, String event, byte[] args) { - ContractEventSendOperation op = CONTRACT_EVENT_SEND_OP_BUILDER.send(address, event, args); + int opIndex = operationList.size(); + ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args, opIndex); operationList.add(op); return op; } + @Override + public ContractEventSendOperation send(String address) { + return send(Bytes.fromBase58(address)); + } + + @Override + public ContractEventSendOperation send(Bytes address) { + int opIndex = operationList.size(); + ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, opIndex); + operationList.add(op); + return op; + } } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java new file mode 100644 index 00000000..4cacf19c --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java @@ -0,0 +1,6 @@ +package com.jd.blockchain.transaction; + +public interface ContractEventExecutor { + + T execute(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java index 7acc42ba..641ea6f2 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java @@ -5,6 +5,7 @@ import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.utils.Bytes; public class ContractEventSendOpTemplate implements ContractEventSendOperation { + static { DataContractRegistry.register(ContractEventSendOperation.class); } @@ -14,17 +15,47 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { private String event; //交易操作时间; private long txOpTime; + // 所属操作Index + private int opIndex; public ContractEventSendOpTemplate() { } + public ContractEventSendOpTemplate(Bytes contractAddress) { + this(contractAddress, -1); + } + + public ContractEventSendOpTemplate(Bytes contractAddress, int opIndex) { + this.contractAddress = contractAddress; + this.opIndex = opIndex; + this.txOpTime = System.currentTimeMillis(); + } + public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args) { + this(contractAddress, event, args, -1); + } + + public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args, int opIndex) { this.contractAddress = contractAddress; this.event = event; this.args = args; + this.opIndex = opIndex; this.txOpTime = System.currentTimeMillis(); } + public void setArgs(byte[] args) { + this.args = args; + } + + public void setEvent(String event) { + this.event = event; + } + + public void setEventAndArgs(String event, byte[] args) { + this.event = event; + this.args = args; + } + @Override public Bytes getContractAddress() { return contractAddress; @@ -44,4 +75,13 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { public long getTxOpTime() { return txOpTime; } + + /** + * 获取所属交易中的序号,该值不需要序列化 + * + * @return + */ + public int getOpIndex() { + return opIndex; + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java index 66f1ec22..5bc2e539 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java @@ -23,4 +23,17 @@ public interface ContractEventSendOperationBuilder { @Deprecated ContractEventSendOperation send(Bytes address, String event, byte[] args); + /** + * + * @param address + * @return + */ + ContractEventSendOperation send(String address); + + /** + * + * @param address + * @return + */ + ContractEventSendOperation send(Bytes address); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java index beccc539..faae0029 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java @@ -1,21 +1,21 @@ -package com.jd.blockchain.transaction; - -import com.jd.blockchain.ledger.ContractEventSendOperation; -import com.jd.blockchain.utils.Bytes; - -@Deprecated -class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { - - @Override - public ContractEventSendOperation send(String address, String event, byte[] args) { - ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); - return op; - } - - @Override - public ContractEventSendOperation send(Bytes address, String event, byte[] args) { - ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); - return op; - } - -} +//package com.jd.blockchain.transaction; +// +//import com.jd.blockchain.ledger.ContractEventSendOperation; +//import com.jd.blockchain.utils.Bytes; +// +//@Deprecated +//class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { +// +// @Override +// public ContractEventSendOperation send(String address, String event, byte[] args) { +// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); +// return op; +// } +// +// @Override +// public ContractEventSendOperation send(Bytes address, String event, byte[] args) { +// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); +// return op; +// } +// +//} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java index d6f223fd..c5820b14 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java @@ -3,7 +3,9 @@ package com.jd.blockchain.transaction; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.contract.ContractType; +import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.IllegalDataException; @@ -11,45 +13,66 @@ public class ContractInvocationProxy implements InvocationHandler { // private String contractMessage; - private Bytes contractAddress; +// private Bytes contractAddress; private ContractType contractType; - private ContractEventSendOperationBuilder sendOpBuilder; +// private ContractEventSendOperationBuilder sendOpBuilder; + + private ContractEventSendOperation sendOperation; public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, ContractEventSendOperationBuilder sendOpBuilder) { - this.contractAddress = contractAddress; +// this.contractAddress = contractAddress; if(contractType == null){ throw new IllegalDataException("contractType == null, no invoke really."); } this.contractType = contractType; - this.sendOpBuilder = sendOpBuilder; +// this.sendOpBuilder = sendOpBuilder; + // Send一个地址,但不涉及Event + this.sendOperation = sendOpBuilder.send(contractAddress); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + // 判断是否是常规方法调用 + if (method.getName().equals("hashCode")) { + // 该处需要使用当前代理类的HashCode + return this.hashCode(); + } + if (method.getName().equals("toString")) { + // 该处使用当前代理类的toString + return this.toString(); + } + + if (sendOperation.getEvent() != null) { + throw new IllegalStateException("Contract Object can only execute method one time !!!"); + } + String event = contractType.getEvent(method); if (event == null) { - // 适配 Object 对象的方法; - // toString 方法; - return String.format("[%s]-%s", contractAddress, contractType.toString()); - - // hashCode 方法; + // 该方法不是合约可执行的方法 + throw new IllegalAccessException(String.format("This Method [%s] is not Contract Event Method !!!", + method.getName())); } // 合约方法; - byte[] argBytes = serializeArgs(args,method); - sendOpBuilder.send(contractAddress, event, argBytes); - - // TODO: 暂时未考虑有返回值的情况; + byte[] argBytes = serializeArgs(args); + if (sendOperation instanceof ContractEventSendOpTemplate) { + ((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes); + } + // 代理操作,返回值类型无法创建 return null; } - private byte[] serializeArgs(Object[] args, Method method) { - if(args == null || args.length==0){ - return null; + private byte[] serializeArgs(Object[] args) { + return ContractSerializeUtils.serializeArray(args); + } + + public int opIndex() { + if (sendOperation instanceof ContractEventSendOpTemplate) { + return ((ContractEventSendOpTemplate) sendOperation).getOpIndex(); } - throw new IllegalStateException("Not implemented!"); - //return ContractSerializeUtils.serializeMethodParam(args,contractType.getDataContractMap().get(method)); + return -1; } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java index 50f13baa..2d0d902a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java @@ -1,18 +1,20 @@ package com.jd.blockchain.transaction; -import java.lang.annotation.Annotation; import java.lang.reflect.Proxy; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.contract.ContractType; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.IllegalDataException; public class ContractInvocationProxyBuilder { private Map, ContractType> contractTypes = new ConcurrentHashMap<>(); + private Map contractOperations = new ConcurrentHashMap<>(); + public T create(String address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); } @@ -23,10 +25,31 @@ public class ContractInvocationProxyBuilder { ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, contractEventBuilder); + T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { contractIntf }, proxyHandler); + // 创建关联关系 + contractOperations.put(proxy, proxyHandler.opIndex()); + return proxy; + } + + public EventResult execute(ContractEventExecutor execute) { + Object contractProxy = execute.execute(); + if (contractProxy == null) { + // 该方法执行必须要有返回值 + throw new IllegalStateException( + String.format("ContractEventExecutor [%s] 's return must be not empty !!!", execute.toString())); + } + if (!(contractProxy instanceof Proxy)) { + throw new IllegalDataException( + String.format("ContractEventExecutor [%s] 's return must from TxTemplate.contract()'s result !!!", execute.toString())); + } - return (T) proxy; + Integer opIndex = contractOperations.get(contractProxy); + if (opIndex != null && opIndex > -1) { + return new EventResult<>(opIndex); + } + return null; } private ContractType resolveContractType(Class contractIntf) { @@ -34,21 +57,8 @@ public class ContractInvocationProxyBuilder { if (contractType != null) { return contractType; } - // TODO 检查返回值类型; - - ContractType contractType1 = ContractType.resolve(contractIntf); - contractTypes.put(contractIntf,contractType1); - return contractType1; - } - - - /** - * is contractType really? identified by @Contract; - * @param contractIntf - * @return - */ - private boolean isContractType(Class contractIntf) { - Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class); - return annotation != null ? true : false; + ContractType ct = ContractType.resolve(contractIntf); + contractTypes.put(contractIntf, ct); + return ct; } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java index fd001fb6..de6e1c0e 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java @@ -1,5 +1,6 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.utils.Bytes; public interface EventOperator { @@ -30,4 +31,11 @@ public interface EventOperator { */ T contract(Bytes address, Class contractIntf); + /** + * 执行合约异步等待应答结果 + * + * @param execute + * @return + */ + EventResult result(ContractEventExecutor execute); } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java index 2b0422c0..f45706f4 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java @@ -1,18 +1,17 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.binaryproto.BinaryProtocol; +import com.jd.blockchain.contract.ContractSerializeUtils; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PrivKey; import com.jd.blockchain.crypto.SignatureDigest; import com.jd.blockchain.crypto.SignatureFunction; -import com.jd.blockchain.ledger.DigitalSignature; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionRequestBuilder; -import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.*; + +import java.util.Map; public class PreparedTx implements PreparedTransaction { @@ -20,9 +19,16 @@ public class PreparedTx implements PreparedTransaction { private TransactionService txProcessor; + private Map eventResults; + public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor) { + this(txReqBuilder, txProcessor, null); + } + + public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, Map eventResults) { this.txReqBuilder = txReqBuilder; this.txProcessor = txProcessor; + this.eventResults = eventResults; } @Override @@ -56,6 +62,20 @@ public class PreparedTx implements PreparedTransaction { TransactionRequest txReq = txReqBuilder.buildRequest(); // 发起交易请求; TransactionResponse txResponse = txProcessor.process(txReq); + // 重新包装操作集合 + OperationResult[] operationResults = txResponse.getOperationResults(); + if (operationResults != null && operationResults.length > 0 && + eventResults != null && !eventResults.isEmpty()) { + for (OperationResult operationResult : operationResults) { + int opIndex = operationResult.getIndex(); + EventResult eventResult = eventResults.get(opIndex); + if (eventResult != null) { + eventResult.done(ContractSerializeUtils.resolve(operationResult.getResult())); + } + } + } return txResponse; } + + } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java index 12fe552f..87cabb3a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java @@ -2,6 +2,7 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.TransactionBuilder; @@ -10,6 +11,9 @@ import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequestBuilder; import com.jd.blockchain.utils.Bytes; +import java.util.HashMap; +import java.util.Map; + public class TxBuilder implements TransactionBuilder { static { @@ -18,6 +22,8 @@ public class TxBuilder implements TransactionBuilder { private BlockchainOperationFactory opFactory = new BlockchainOperationFactory(); + private Map contractProxyMap = new HashMap<>(); + private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; private HashDigest ledgerHash; @@ -88,6 +94,11 @@ public class TxBuilder implements TransactionBuilder { return opFactory.contract(address, contractIntf); } + @Override + public EventResult result(ContractEventExecutor execute) { + return opFactory.result(execute); + } + @Override public T contract(String address, Class contractIntf) { return opFactory.contract(address, contractIntf); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java index a966239b..57107ff3 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java @@ -19,10 +19,19 @@ public class TxResponseMessage implements TransactionResponse { private TransactionState executionState; - private OperationResult[] contractReturn; + private OperationResult[] operationResults; public TxResponseMessage() { } + + // 重新包装operationResults + public TxResponseMessage(TransactionResponse transactionResponse, OperationResult[] operationResults) { + this.contentHash = transactionResponse.getContentHash(); + this.blockHash = transactionResponse.getBlockHash(); + this.blockHeight = transactionResponse.getBlockHeight(); + this.executionState = transactionResponse.getExecutionState(); + this.operationResults = operationResults; + } public TxResponseMessage(HashDigest contentHash) { this.contentHash = contentHash; @@ -60,8 +69,8 @@ public class TxResponseMessage implements TransactionResponse { this.blockHeight = blockHeight; } - public void setContractReturn(OperationResult[] contractReturn) { - this.contractReturn = contractReturn; + public void setOperationResults(OperationResult[] operationResults) { + this.operationResults = operationResults; } @Override @@ -70,8 +79,8 @@ public class TxResponseMessage implements TransactionResponse { } @Override - public OperationResult[] getContractReturn() { - return contractReturn; + public OperationResult[] getOperationResults() { + return operationResults; } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java index 984ecf07..908ee7fc 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java @@ -1,20 +1,27 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionRequestBuilder; import com.jd.blockchain.ledger.TransactionTemplate; import com.jd.blockchain.utils.Bytes; +import java.util.HashMap; +import java.util.Map; + public class TxTemplate implements TransactionTemplate { private TxBuilder txBuilder; private TransactionService txService; + private Map eventResults; + public TxTemplate(HashDigest ledgerHash, TransactionService txService) { this.txBuilder = new TxBuilder(ledgerHash); this.txService = txService; + this.eventResults = new HashMap<>(); } @Override @@ -25,7 +32,7 @@ public class TxTemplate implements TransactionTemplate { @Override public PreparedTransaction prepare() { TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); - return new PreparedTx(txReqBuilder, txService); + return new PreparedTx(txReqBuilder, txService, eventResults); } @Override @@ -62,7 +69,16 @@ public class TxTemplate implements TransactionTemplate { public T contract(Bytes address, Class contractIntf) { return txBuilder.contract(address, contractIntf); } - + + @Override + public EventResult result(ContractEventExecutor execute) { + EventResult eventResult = txBuilder.result(execute); + if (eventResult != null) { + eventResults.put(eventResult.opIndex(), eventResult); + } + return eventResult; + } + @Override public T contract(String address, Class contractIntf) { return txBuilder.contract(address, contractIntf); diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java b/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java index 97d7b9ba..d207d725 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java @@ -310,8 +310,8 @@ public class ConsensusMessageDispatcher implements MessageHandle { } @Override - public OperationResult[] getContractReturn() { - return txResp.getContractReturn(); + public OperationResult[] getOperationResults() { + return txResp.getOperationResults(); } } diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java index 25360ebe..87d886ea 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java @@ -24,6 +24,10 @@ import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicLong; +import com.jd.blockchain.contract.EventResult; +import com.jd.blockchain.contract.ReadContract; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.transaction.ContractEventExecutor; import org.apache.commons.io.FileUtils; import org.springframework.core.io.ClassPathResource; @@ -31,16 +35,6 @@ import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInitOperation; -import com.jd.blockchain.ledger.PreparedTransaction; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.TransactionTemplate; -import com.jd.blockchain.ledger.UserRegisterOperation; import com.jd.blockchain.ledger.core.LedgerRepository; import com.jd.blockchain.ledger.core.impl.LedgerManager; import com.jd.blockchain.sdk.BlockchainService; @@ -446,9 +440,9 @@ public class IntegrationBase { // 合约测试使用的初始化数据; static BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate(); static BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - // 保存资产总数的键; - // 第二个参数; - private static String contractZipName = "contract.jar"; + // 保存资产总数的键; + // 第二个参数; + private static String contractZipName = "contract-read.jar"; static HashDigest txContentHash; public static LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash, @@ -484,7 +478,7 @@ public class IntegrationBase { // execute the contract; // testContractExe(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); // testContractExe1(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); - + testExeReadContract(adminKey, ledgerHash, blockchainService); return block; } @@ -545,6 +539,91 @@ public class IntegrationBase { // assertEquals(888L,kvDataEntries[1].getValue()); // } + private static void testExeReadContract(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainService blockchainService) { + + // 首先注册一个数据账户 + BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + txTpl.dataAccounts().register(newDataAccount.getIdentity()); + + PreparedTransaction ptx = txTpl.prepare(); + ptx.sign(adminKey); + + // 提交并等待共识返回; + ptx.commit(); + + // 再提交一个KV写入 + String key1 = "JingDong", value1 = "www.jd.com"; + String key2 = "JD", value2 = "JingDong"; + + TransactionTemplate txKv = blockchainService.newTransaction(ledgerHash); + txKv.dataAccount(newDataAccount.getAddress()).setText(key1, value1, -1).setText(key2, value2, -1); + PreparedTransaction kvPtx = txKv.prepare(); + kvPtx.sign(adminKey); + + // 提交并等待共识返回; + kvPtx.commit(); + + // 下面才是执行Read交易 + // 定义交易; + TransactionTemplate txContract = blockchainService.newTransaction(ledgerHash); + + ReadContract readContract1 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); + + EventResult read1 = txContract.result((ContractEventExecutor) () -> { + readContract1.read(newDataAccount.getAddress().toBase58(), key1); + return readContract1; + }); + + ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); + + EventResult read2 = txContract.result((ContractEventExecutor) () -> { + readContract2.read(newDataAccount.getAddress().toBase58(), key2); + return readContract2; + }); + + ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); + + EventResult read3 = txContract.result((ContractEventExecutor) () -> { + readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2); + return readContract3; + }); + + // 签名; + PreparedTransaction contractPtx = txContract.prepare(); + contractPtx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse readTxResp = contractPtx.commit(); + + OperationResult[] operationResults = readTxResp.getOperationResults(); + + // 通过EventResult获取结果 + System.out.printf("readContract1.result = %s \r\n", read1.get()); + System.out.printf("readContract2.result = %s \r\n", read2.get()); + System.out.printf("readContract3.result = %s \r\n", read3.get()); + + + // 打印结果 +// for (OperationResult or : operationResults) { +// System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), or.getResult()); +// } +// +// // 验证结果 +// assertNotNull(contractReturn); +// assertEquals(contractReturn.length, 3); +// +// String returnVal1 = contractReturn[0]; +// assertEquals(value1, returnVal1); +// +// String returnVal2 = contractReturn[1]; +// assertEquals(value2, returnVal2); +// +// String returnVal3 = contractReturn[2]; +// assertEquals("0", returnVal3); + } + /** * 根据合约构建字节数组; * diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java index 1d7f91ec..d7daceaf 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java @@ -19,32 +19,7 @@ import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; -import com.jd.blockchain.ledger.AccountHeader; -import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.ContractCodeDeployOperation; -import com.jd.blockchain.ledger.ContractEventSendOperation; -import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.DataAccountRegisterOperation; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVInfoVO; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInfo; -import com.jd.blockchain.ledger.LedgerMetadata; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.NodeRequest; -import com.jd.blockchain.ledger.Operation; -import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionRequestBuilder; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.UserInfo; -import com.jd.blockchain.ledger.UserRegisterOperation; +import com.jd.blockchain.ledger.*; import com.jd.blockchain.ledger.core.CryptoConfig; import com.jd.blockchain.ledger.core.LedgerDataSet; import com.jd.blockchain.ledger.core.LedgerEditor; @@ -427,15 +402,16 @@ public class MockerNodeContext implements BlockchainQueryService { return reqBuilder.buildRequest(); } - public void txProcess(TransactionRequest txRequest) { + public OperationResult[] txProcess(TransactionRequest txRequest) { LedgerEditor newEditor = ledgerRepository.createNextBlock(); LedgerBlock latestBlock = ledgerRepository.getLatestBlock(); LedgerDataSet previousDataSet = ledgerRepository.getDataSet(latestBlock); TransactionBatchProcessor txProc = new TransactionBatchProcessor(newEditor, previousDataSet, opHandler, ledgerManager); - txProc.schedule(txRequest); + TransactionResponse txResp = txProc.schedule(txRequest); TransactionBatchResultHandle handle = txProc.prepare(); handle.commit(); + return txResp.getOperationResults(); } private LedgerRepository registerLedger(HashDigest ledgerHash, DBConnectionConfig dbConnConf) { diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java index 2dbd8ae5..9662dd68 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java @@ -10,5 +10,5 @@ public interface WriteContract { void print(String name); @ContractEvent(name = "writeKv") - void writeKv(String address, String key, String value); + String writeKv(String address, String key, String value); } diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java index 6d0e8be4..83f5521d 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java @@ -15,8 +15,9 @@ public class WriteContractImpl implements EventProcessingAware, WriteContract { } @Override - public void writeKv(String address, String key, String value) { + public String writeKv(String address, String key, String value) { eventContext.getLedger().dataAccount(address).setText(key, value, -1); + return String.format("address = %s, key = %s, value = %s, version = %s", address, key, value, 0); } @Override diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java index 60f61510..ec321728 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java @@ -1,7 +1,12 @@ package com.jd.blockchain.mocker.handler; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.contract.EventProcessingAware; import com.jd.blockchain.contract.LedgerContext; import com.jd.blockchain.crypto.HashDigest; @@ -9,17 +14,16 @@ import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.ledger.core.LedgerDataSet; +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.LedgerManager; import com.jd.blockchain.ledger.core.impl.LedgerQueryService; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext; import com.jd.blockchain.mocker.proxy.ExecutorProxy; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - public class MockerContractExeHandle implements OperationHandle { private Map executorProxyMap = new ConcurrentHashMap<>(); @@ -37,6 +41,7 @@ public class MockerContractExeHandle implements OperationHandle { ExecutorProxy executorProxy = executorProxyMap.get(txHash); + Object result = null; if (executorProxy != null) { LedgerQueryService queryService = new LedgerQueryService(ledgerManager); ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext); @@ -44,26 +49,38 @@ public class MockerContractExeHandle implements OperationHandle { MockerContractEventContext contractEventContext = new MockerContractEventContext(ledgerHash, contractOP.getEvent(), requestContext.getRequest(), ledgerContext); - EventProcessingAware eventProcessingAwire = (EventProcessingAware) executorProxy.getInstance(); - try { - // - // Before处理过程 - eventProcessingAwire.beforeEvent(contractEventContext); - executorProxy.invoke(); + Object instance = executorProxy.getInstance(); + EventProcessingAware awire = null; + + if (instance instanceof EventProcessingAware) { + awire = (EventProcessingAware) instance; + awire.beforeEvent(contractEventContext); + } - // After处理过程 - eventProcessingAwire.postEvent(contractEventContext, null); + try { + result = executorProxy.invoke(); + if (awire != null) { + // After处理过程 + awire.postEvent(contractEventContext, null); + } } catch (Exception e) { - eventProcessingAwire.postEvent(contractEventContext, new ContractException(e.getMessage())); + if (awire != null) { + awire.postEvent(contractEventContext, new ContractException(e.getMessage())); + } } finally { removeExecutorProxy(txHash); } } // No return value; - return null; + return ContractSerializeUtils.serialize(result); } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { +// return null; +// } + @Override public boolean support(Class operationType) { return ContractEventSendOperation.class.isAssignableFrom(operationType); diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java index 69fc305c..c01d4a26 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java @@ -2,8 +2,11 @@ package com.jd.blockchain.mocker.proxy; import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.OperationResult; +import com.jd.blockchain.ledger.OperationResultData; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.mocker.MockerNodeContext; import com.jd.blockchain.mocker.handler.MockerContractExeHandle; @@ -68,9 +71,14 @@ public class ContractProxy implements InvocationHandler { operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args)); // 提交该请求至整个区块链系统 - mockerNodeContext.txProcess(txRequest); - // 不处理返回值 - return null; + OperationResult[] operationResults = mockerNodeContext.txProcess(txRequest); + if (operationResults == null || operationResults.length == 0) { + return null; + } + OperationResult opResult = operationResults[0]; + + // 处理返回值 + return ContractSerializeUtils.resolve(opResult.getResult()); } private boolean isExecuteContractMethod(Method method) { diff --git a/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest_.java b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java similarity index 90% rename from source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest_.java rename to source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java index 68559fa2..19cd34df 100644 --- a/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest_.java +++ b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java @@ -10,7 +10,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; -public class SampleTest_ { +public class SampleTest { MockerNodeContext mockerNodeContext = null; @@ -33,7 +33,9 @@ public class SampleTest_ { writeContract = mockerNodeContext.deployContract(writeContract); - writeContract.writeKv(dataAccountAddress, key, value); + String result = writeContract.writeKv(dataAccountAddress, key, value); + + System.out.println(result); // 查询结果 KVDataEntry[] dataEntries = mockerNodeContext.getDataEntries(ledgerHash, dataAccountAddress, key);