From 0888190efa24b61c9d44419e05cbab6e2d1fd12d Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 19 Jun 2019 02:27:48 +0800 Subject: [PATCH] Completed the processing of the return value of Contract event send operation; --- .../com/jd/blockchain/consts/DataCodes.java | 4 +- .../contract/engine/ContractCode.java | 6 +- .../contract/jvm/AbstractContractCode.java | 7 +- .../contract/jvm/JavaContractCode.java | 7 +- .../ledger/core/OperationHandle.java | 4 +- .../core/impl/TransactionBatchProcessor.java | 4 +- .../handles/AbtractContractEventHandle.java | 7 +- .../ContractCodeDeployOperationHandle.java | 12 +- .../DataAccountKVSetOperationHandle.java | 4 +- .../DataAccountRegisterOperationHandle.java | 8 +- .../handles/UserRegisterOperationHandle.java | 11 +- .../ledger/ContractInvokingTest.java | 10 +- .../contract/ContractSerializeUtils.java | 301 +++++++------ .../jd/blockchain/contract/ContractType.java | 32 +- .../jd/blockchain/ledger/BytesValueList.java | 11 + .../ledger/ContractEventSendOperation.java | 7 - .../com/jd/blockchain/ledger/DataType.java | 23 +- .../jd/blockchain/ledger/OperationResult.java | 8 +- .../ledger/OperationResultData.java | 8 +- .../ledger/PreparedTransaction.java | 24 +- .../BlockchainOperationFactory.java | 90 ++-- .../ContractEventSendOpTemplate.java | 55 +-- .../ContractEventSendOperationBuilder.java | 26 +- .../transaction/ContractInvocation.java | 66 +++ .../ContractInvocationHandler.java | 109 +++++ .../transaction/ContractInvocationProxy.java | 110 ----- .../ContractInvocationProxyBuilder.java | 52 ++- .../transaction/ContractInvocationStub.java | 33 ++ .../transaction/ContractReturns.java | 418 ++++++++++++++++++ .../blockchain/transaction/EventOperator.java | 23 +- .../OperationReturnValueHandler.java | 11 + .../jd/blockchain/transaction/PreparedTx.java | 80 ++-- .../jd/blockchain/transaction/TxBuilder.java | 17 +- .../transaction/TxRequestBuilder.java | 3 +- .../jd/blockchain/transaction/TxTemplate.java | 22 +- .../sdk/samples/SDK_Contract_Demo.java | 303 +++++++------ .../sdk/test/SDKDemo_Contract_Test.java | 282 ++++++------ .../jd/blockchain/intgr/IntegrationBase.java | 35 +- .../handler/MockerContractExeHandle.java | 8 +- 39 files changed, 1366 insertions(+), 875 deletions(-) create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocation.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationHandler.java delete mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationStub.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractReturns.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationReturnValueHandler.java 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 39850af6..e764c3f3 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 @@ -9,6 +9,8 @@ package com.jd.blockchain.consts; public interface DataCodes { public static final int BYTES_VALUE = 0x80; + + public static final int BYTES_VALUE_LIST = 0x81; public static final int BLOCK_CHAIN_IDENTITY = 0x90; @@ -16,8 +18,6 @@ public interface DataCodes { public static final int BLOCK_BODY = 0x110; - // public static final int BLOCK_LEDGER = 0x110; - public static final int BLOCK_GENESIS = 0x120; public static final int DATA_SNAPSHOT = 0x130; 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 962c767d..2f363a55 100644 --- a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java +++ b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java @@ -1,16 +1,14 @@ package com.jd.blockchain.contract.engine; import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.utils.Bytes; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; - public interface ContractCode { Bytes getAddress(); long getVersion(); - byte[] processEvent(ContractEventContext eventContext); + BytesValue processEvent(ContractEventContext eventContext); } diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java index 53aec345..3dfc4c58 100644 --- a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java @@ -10,6 +10,7 @@ import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.contract.EventProcessingAware; import com.jd.blockchain.contract.engine.ContractCode; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.utils.Bytes; /** @@ -44,7 +45,7 @@ public abstract class AbstractContractCode implements ContractCode { } @Override - public byte[] processEvent(ContractEventContext eventContext) { + public BytesValue processEvent(ContractEventContext eventContext) { EventProcessingAware evtProcAwire = null; Object retn = null; Exception error = null; @@ -90,13 +91,13 @@ public abstract class AbstractContractCode implements ContractCode { eventContext.getEvent(), address.toString(), error.getMessage()), error); } - byte[] retnBytes = resolveResult(retn); + BytesValue retnBytes = resolveResult(retn); return retnBytes; } protected abstract Object getContractInstance(); - private byte[] resolveResult(Object retn) { + private BytesValue resolveResult(Object retn) { if (retn == null) { return null; } diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java index 20f97863..c6b7c5b9 100644 --- a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java @@ -9,6 +9,7 @@ import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.contract.ContractType; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.runtime.Module; import com.jd.blockchain.utils.Bytes; @@ -65,7 +66,7 @@ public class JavaContractCode extends AbstractContractCode { } @Override - public byte[] processEvent(ContractEventContext eventContext) { + public BytesValue processEvent(ContractEventContext eventContext) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Start processing event[%s] of contract[%s]...", eventContext.getEvent(), address.toString()); } @@ -91,7 +92,7 @@ public class JavaContractCode extends AbstractContractCode { } } - private class ContractExecution implements Callable { + private class ContractExecution implements Callable { private ContractEventContext eventContext; public ContractExecution(ContractEventContext contractEventContext) { @@ -99,7 +100,7 @@ public class JavaContractCode extends AbstractContractCode { } @Override - public byte[] call() throws Exception { + public BytesValue call() throws Exception { return JavaContractCode.super.processEvent(eventContext); } } 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 2a13690b..e1a0f567 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 @@ -1,8 +1,8 @@ package com.jd.blockchain.ledger.core; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; -import com.jd.blockchain.utils.concurrent.AsyncFuture; public interface OperationHandle { @@ -30,7 +30,7 @@ public interface OperationHandle { * * @return 操作执行结果 */ - byte[] process(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, + BytesValue process(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/TransactionBatchProcessor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java index bfb8a08d..b4795c01 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 @@ -8,7 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.ContractEventSendOperation; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.Operation; @@ -110,7 +110,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { int opIndex = 0; for (Operation op : ops) { opHandle = opHandles.getHandle(op.getClass()); - byte[] opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService); + BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService); if (opResult != null) { operationResults.add(new OperationResultData(opIndex, opResult)); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java index 56a24db1..40f6e2c2 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java @@ -1,13 +1,10 @@ package com.jd.blockchain.ledger.core.impl.handles; -import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; - import org.springframework.stereotype.Service; import com.jd.blockchain.contract.LocalContractEventContext; import com.jd.blockchain.contract.engine.ContractCode; -import com.jd.blockchain.contract.engine.ContractEngine; -import com.jd.blockchain.contract.engine.ContractServiceProviders; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.Operation; @@ -29,7 +26,7 @@ public abstract class AbtractContractEventHandle implements OperationHandle { } @Override - public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { ContractEventSendOperation contractOP = (ContractEventSendOperation) op; // 先从账本校验合约的有效性; 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 a71b26d1..e18c9304 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,6 +1,8 @@ package com.jd.blockchain.ledger.core.impl.handles; -import com.jd.blockchain.binaryproto.BinaryProtocol; +import org.springframework.stereotype.Service; + +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.LedgerDataSet; @@ -9,17 +11,11 @@ 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 { @Override - public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { ContractCodeDeployOperation contractOP = (ContractCodeDeployOperation) op; // TODO: 校验合约代码的正确性; 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 9844d4c6..c07dd628 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,7 +1,5 @@ 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; @@ -24,7 +22,7 @@ public class DataAccountKVSetOperationHandle implements OperationHandle { } @Override - public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { DataAccountKVSetOperation kvWriteOp = (DataAccountKVSetOperation) op; DataAccount account = dataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); 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 8bce4efd..69337dfa 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 @@ -1,6 +1,9 @@ package com.jd.blockchain.ledger.core.impl.handles; +import org.springframework.stereotype.Service; + import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataAccountRegisterOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.LedgerDataSet; @@ -9,14 +12,11 @@ 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 public class DataAccountRegisterOperationHandle implements OperationHandle { @Override - public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op; BlockchainIdentity bid = dataAccountRegOp.getAccountID(); 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 d4072aa7..f583e8cd 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 @@ -1,6 +1,7 @@ package com.jd.blockchain.ledger.core.impl.handles; import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.UserRegisterOperation; import com.jd.blockchain.ledger.core.LedgerDataSet; @@ -9,13 +10,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; public class UserRegisterOperationHandle implements OperationHandle { @Override - public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { @@ -26,14 +26,9 @@ public class UserRegisterOperationHandle implements OperationHandle { dataset.getUserAccountSet().register(userAddress, bid.getPubKey()); - return userAddress.toBytes(); + 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 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 1f3fb3ed..27e234d0 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 @@ -120,8 +120,9 @@ public class ContractInvokingTest { assertEquals(1, opResults.length); assertEquals(0, opResults[0].getIndex()); - byte[] retnBytes = BinaryProtocol.encode(BytesValueEntry.fromInt64(issueAmount), BytesValue.class); - assertArrayEquals(retnBytes, opResults[0].getResult()); + byte[] expectedRetnBytes = BinaryProtocol.encode(BytesValueEntry.fromInt64(issueAmount), BytesValue.class); + byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); + assertArrayEquals(expectedRetnBytes, reallyRetnBytes); // 提交区块; TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare(); @@ -135,7 +136,10 @@ public class ContractInvokingTest { // 再验证一次结果; assertEquals(1, opResults.length); assertEquals(0, opResults[0].getIndex()); - assertArrayEquals(retnBytes, opResults[0].getResult()); + + reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); + assertArrayEquals(expectedRetnBytes, reallyRetnBytes); + } private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) { 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 index 6214c24e..0a637662 100644 --- 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 @@ -1,157 +1,164 @@ 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; +import com.jd.blockchain.binaryproto.BinaryProtocol; +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.contract.param.WRAP_BYTES; +import com.jd.blockchain.contract.param.WRAP_INT; +import com.jd.blockchain.contract.param.WRAP_LONG; +import com.jd.blockchain.contract.param.WRAP_SHORT; +import com.jd.blockchain.contract.param.WRAP_STRING; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.utils.io.BytesUtils; + 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; - } - } + 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 BytesValue 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(BytesValue 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/ContractType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java index bbd967a1..e70b385e 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 @@ -63,24 +63,24 @@ public class ContractType { /** * 解析合约的声明; * - * @param delaredInterface 声明合约的接口类型; + * @param contractIntf 合约的声明接口,必须是 interface ; * @return */ public static ContractType resolve(Class contractIntf) { - + // TODO:方法会检查合约方法声明的类型和返回值类型; // 如果是Class则首先获取其接口 if (!contractIntf.isInterface()) { Class realIntf = null; Class[] interfaces = contractIntf.getInterfaces(); - for (Class intf: interfaces) { + for (Class intf : interfaces) { if (intf.isAnnotationPresent(Contract.class)) { realIntf = intf; break; } } if (realIntf == null) { - throw new IllegalDataException(String.format( - "%s is not a Contract Type, because there is not @Contract !", contractIntf.getName())); + throw new IllegalDataException(String + .format("%s is not a Contract Type, because there is not @Contract !", contractIntf.getName())); } contractIntf = realIntf; } @@ -105,22 +105,25 @@ public class ContractType { 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)){ + // 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(); - for(Class currParamType : paramTypes) { + for (Class currParamType : paramTypes) { if (!ContractSerializeUtils.support(currParamType)) { - throw new IllegalStateException(String.format("Param Type = %s can not support !!!", currParamType.getName())); + 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())); + throw new IllegalStateException( + String.format("Return Type = %s can not support !!!", returnType.getName())); } contractType.events.put(eventName, method); @@ -132,10 +135,7 @@ public class ContractType { @Override public String toString() { - return "ContractType{" + - "name='" + name + '\'' + - ", events=" + events + - ", handleMethods=" + handleMethods + - '}'; + return "ContractType{" + "name='" + name + '\'' + ", events=" + events + ", handleMethods=" + handleMethods + + '}'; } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java new file mode 100644 index 00000000..7f945e22 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java @@ -0,0 +1,11 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code = DataCodes.BYTES_VALUE_LIST) +public interface BytesValueList { + + BytesValue[] getValues(); + +} 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 1530fb0c..1e79ec49 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 @@ -37,11 +37,4 @@ public interface ContractEventSendOperation extends Operation { @DataField(order = 4, primitiveType = PrimitiveType.BYTES) byte[] getArgs(); - /** - * 获得交易操作时间; - * - * @return - */ - @DataField(order = 5, primitiveType = PrimitiveType.INT64) - long getTxOpTime(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java index ac6e4b44..1cb8fce3 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java @@ -36,24 +36,22 @@ public enum DataType { INT32(PrimitiveType.INT32.CODE), INT64(PrimitiveType.INT64.CODE), - + /** * 文本数据; */ TEXT(PrimitiveType.TEXT.CODE), - /** * 二进制数据; */ BYTES(PrimitiveType.BYTES.CODE), - + /** * 时间戳; */ TIMESTAMP((byte) (BaseType.INTEGER | 0x08)), - /** * 文本数据; */ @@ -64,7 +62,6 @@ public enum DataType { */ XML((byte) (BaseType.TEXT | 0x02)), - /** * 大整数; */ @@ -84,28 +81,32 @@ public enum DataType { * 位置坐标; */ LOCATION((byte) (BaseType.BYTES | 0x04)), - + /** * 公钥; */ PUB_KEY((byte) (BaseType.BYTES | 0x05)), - + /** * 签名摘要; */ SIGNATURE_DIGEST((byte) (BaseType.BYTES | 0x06)), - + /** * 哈希摘要; */ HASH_DIGEST((byte) (BaseType.BYTES | 0x07)), - + /** * 加密数据; */ - ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)); + ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)), + + /** + * DataContract 数据; + */ + DATA_CONTRACT((byte) (BaseType.EXT | 0x01)); - @EnumField(type = PrimitiveType.INT8) public final byte CODE; 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 a6b25344..b6c6c3bd 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 @@ -8,9 +8,9 @@ import com.jd.blockchain.consts.DataCodes; @DataContract(code = DataCodes.TX_OP_RESULT) public interface OperationResult { - @DataField(order=1, primitiveType = PrimitiveType.INT32) - int getIndex(); + @DataField(order = 1, primitiveType = PrimitiveType.INT32) + int getIndex(); - @DataField(order=2, primitiveType = PrimitiveType.BYTES) - byte[] getResult(); + @DataField(order = 2, refContract = true) + BytesValue 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 399596a3..336887cf 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 @@ -5,12 +5,12 @@ public class OperationResultData implements OperationResult { private int index; - private byte[] result; + private BytesValue result; public OperationResultData() { } - public OperationResultData(int index, byte[] result) { + public OperationResultData(int index, BytesValue result) { this.index = index; this.result = result; } @@ -21,7 +21,7 @@ public class OperationResultData implements OperationResult { } @Override - public byte[] getResult() { + public BytesValue getResult() { return result; } @@ -29,7 +29,7 @@ public class OperationResultData implements OperationResult { this.index = index; } - public void setResult(byte[] result) { + public void setResult(BytesValue result) { this.result = result; } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java index d73d6091..b7db5b59 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java @@ -2,7 +2,6 @@ package com.jd.blockchain.ledger; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.SignatureFunction; /** * 已就绪的交易; @@ -10,7 +9,7 @@ import com.jd.blockchain.crypto.SignatureFunction; * @author huanghaiquan * */ -public interface PreparedTransaction extends HashObject { +public interface PreparedTransaction extends HashObject { /** * 交易内容的 Hash; @@ -33,10 +32,8 @@ public interface PreparedTransaction extends HashObject { /** * 对交易进行签名; * - * @param address - * 签名账户的地址; - * @param privKey - * 签名账户的私钥; + * @param address 签名账户的地址; + * @param privKey 签名账户的私钥; * @return */ DigitalSignature sign(AsymmetricKeypair keyPair); @@ -44,17 +41,22 @@ public interface PreparedTransaction extends HashObject { /** * 加入签名; * - * @param address - * 签名账户的地址; - * @param digest - * Base64格式的签名摘要; + * @param address 签名账户的地址; + * @param digest Base64格式的签名摘要; * @return */ void addSignature(DigitalSignature signature); /** - * 生成交易请求; + * 提交交易请求到共识节点;
+ * + * 这是同步方法,将阻塞当前线程,直到交易处理完成并返回结果之后,此方法才返回给调用者; * */ TransactionResponse commit(); + + /** + * 取消交易;
+ */ + void cancel(); } 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 b38d06fa..2820393b 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,8 +4,8 @@ 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.BytesValue; import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.ledger.DataAccountKVSetOperation; @@ -44,6 +44,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe private ContractInvocationProxyBuilder contractInvoProxyBuilder = new ContractInvocationProxyBuilder(); + // TODO: 暂时只支持单线程情形,未考虑多线程; private List operationList = new ArrayList<>(); @Override @@ -90,16 +91,43 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); } - @Override - public EventResult result(ContractEventExecutor execute) { - return contractInvoProxyBuilder.execute(execute); - } - + /** + * 返回已经定义的操作列表; + * + * @return + */ public Collection getOperations() { - // TODO: 合并操作列表中可能的重复操作; return operationList; } + /** + * 返回与操作列表对应的返回值处理器; + * + * @return + */ + public Collection getReturnValuetHandlers() { + List resultHandlers = new ArrayList(); + int index = 0; + for (Operation op : operationList) { + if (op instanceof ContractEventSendOperation) { + // 操作具有返回值,创建对应的结果处理器; + ContractEventSendOpTemplate opTemp = (ContractEventSendOpTemplate) op; + ContractInvocation invocation = opTemp.getInvocation(); + OperationReturnValueHandler retnHandler; + if (invocation == null) { + retnHandler = new NullOperationReturnValueHandler(index); + } else { + invocation.setOperationIndex(index); + retnHandler = invocation; + } + resultHandlers.add(retnHandler); + } + index++; + } + + return resultHandlers; + } + public void clear() { operationList.clear(); } @@ -160,13 +188,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe } } -// @Override -// public DataAccountKVSetOperationBuilder set(String key, byte[] value, long expVersion) { -// innerBuilder.set(key, value, expVersion); -// addOperation(); -// return this; -// } - @Override public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { innerBuilder.setText(key, value, expVersion); @@ -202,13 +223,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe return this; } -// @Override -// public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) { -// innerBuilder.setText(key, value, expVersion); -// addOperation(); -// return this; -// } - @Override public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { innerBuilder.setJSON(key, value, expVersion); @@ -233,7 +247,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe } private class ContractCodeDeployOperationBuilderFilter implements ContractCodeDeployOperationBuilder { - @Override public ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode) { ContractCodeDeployOperation op = CONTRACT_CODE_DEPLOY_OP_BUILDER.deploy(id, chainCode); @@ -250,25 +263,38 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe } @Override - public ContractEventSendOperation send(Bytes address, String event, byte[] args) { - int opIndex = operationList.size(); - ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args, opIndex); + public synchronized ContractEventSendOperation send(Bytes address, String event, byte[] args) { + ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); operationList.add(op); return op; } + } + + /** + * 不做任何操作的返回值处理器; + * + * @author huanghaiquan + * + */ + private static class NullOperationReturnValueHandler implements OperationReturnValueHandler { + + private int operationIndex; + + public NullOperationReturnValueHandler(int operationIndex) { + this.operationIndex = operationIndex; + } + @Override - public ContractEventSendOperation send(String address) { - return send(Bytes.fromBase58(address)); + public int getOperationIndex() { + return operationIndex; } @Override - public ContractEventSendOperation send(Bytes address) { - int opIndex = operationList.size(); - ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, opIndex); - operationList.add(op); - return op; + public Object setReturnValue(BytesValue bytesValue) { + return null; } + } } 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 641ea6f2..c6e62933 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 @@ -13,47 +13,13 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { private Bytes contractAddress; private byte[] args; 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(); - } + + private ContractInvocation invocation; 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 @@ -71,17 +37,12 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { return args; } - @Override - public long getTxOpTime() { - return txOpTime; + public ContractInvocation getInvocation() { + return invocation; } - - /** - * 获取所属交易中的序号,该值不需要序列化 - * - * @return - */ - public int getOpIndex() { - return opIndex; + + public void setInvocation(ContractInvocation invocation) { + this.invocation = invocation; } + } 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 5bc2e539..7a80a346 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 @@ -7,33 +7,17 @@ public interface ContractEventSendOperationBuilder { /** * @param address 合约地址; - * @param event 事件名; - * @param args 事件参数; + * @param event 事件名; + * @param args 事件参数; * @return */ - @Deprecated ContractEventSendOperation send(String address, String event, byte[] args); - + /** * @param address 合约地址; - * @param event 事件名; - * @param args 事件参数; + * @param event 事件名; + * @param args 事件参数; * @return */ - @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/ContractInvocation.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocation.java new file mode 100644 index 00000000..100d1a75 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocation.java @@ -0,0 +1,66 @@ +package com.jd.blockchain.transaction; + +import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +import com.jd.blockchain.contract.ContractType; +import com.jd.blockchain.ledger.BytesValue; + +/** + * ContractInvocation 包装了客户端发起的一次合约方法调用的相关信息,用于在客户端交易处理上下文进行共享处理状态; + * + * @author huanghaiquan + * + */ +class ContractInvocation implements OperationReturnValueHandler { + + private Method method; + + private ContractType contractType; + + private int operationIndex = -1; + + private CompletableFuture returnValueFuture; + + public ContractInvocation(ContractType contractType, Method method) { + this.contractType = contractType; + this.method = method; + this.returnValueFuture = new CompletableFuture(); + } + + public ContractType getContractType() { + return contractType; + } + + @Override + public int getOperationIndex() { + return operationIndex; + } + + public void setOperationIndex(int operationIndex) { + this.operationIndex = operationIndex; + } + + public Class getReturnType() { + return method.getReturnType(); + } + + public Future getReturnValue() { + return returnValueFuture; + } + + @Override + public Object setReturnValue(BytesValue bytesValue) { + // Resolve BytesValue to an value object with the return type; + Object returnValue = resolveValue(bytesValue, method.getReturnType()); + returnValueFuture.complete(returnValue); + return returnValue; + } + + private Object resolveValue(BytesValue bytesValue, Class returnType) { + // TODO: Resolve BytesValue to an value object with the return type; + throw new IllegalStateException("Not implemented!"); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationHandler.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationHandler.java new file mode 100644 index 00000000..b005e650 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationHandler.java @@ -0,0 +1,109 @@ +package com.jd.blockchain.transaction; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.Arrays; + +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.contract.ContractSerializeUtils; +import com.jd.blockchain.contract.ContractType; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.IllegalDataException; + +public class ContractInvocationHandler implements InvocationHandler { + + private Bytes contractAddress; + + private ContractType contractType; + + private ContractEventSendOperationBuilder sendOpBuilder; + + private int proxyHashCode; + + public ContractInvocationHandler(Bytes contractAddress, ContractType contractType, + ContractEventSendOperationBuilder sendOpBuilder) { + this.contractAddress = contractAddress; + if (contractType == null) { + throw new IllegalDataException("contractType == null, no invoke really."); + } + this.contractType = contractType; + this.sendOpBuilder = sendOpBuilder; + this.proxyHashCode = Arrays.deepHashCode(new Object[] { this, contractAddress, contractType, sendOpBuilder }); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // 判断是否是常规方法调用 + if (method.getName().equals("hashCode")) { + // 该处需要使用当前代理类的HashCode + return proxyHashCode; + } + if (method.getName().equals("toString")) { + // 该处使用当前代理类的toString + return this.toString(); + } + + String event = contractType.getEvent(method); + if (event == null) { + // 该方法不是合约可执行的方法 + throw new ContractException( + String.format("The invoking method [%s] is not annotated as event handle method by @ContractEvent!", + method.toString())); + } + // 序列化调用参数; + byte[] argBytes = serializeArgs(args); + + // 定义合约调用操作; + @SuppressWarnings("deprecation") + ContractEventSendOpTemplate opTemplate = (ContractEventSendOpTemplate) sendOpBuilder.send(contractAddress, + event, argBytes); + + // 加入合约调用的额外信息; + ContractInvocation invocation = new ContractInvocation(contractType, method); + + // 传递给定义操作的上下文,以便在生成交易时,同步操作在交易中的索引位置; + opTemplate.setInvocation(invocation); + + // 传递给通过代理对象调用合约方法的调用者,以便可以同步操作在交易中的索引位置以及操作的返回值; + ContractInvocationStub.set(invocation); + + // 返回类型的默认值 + return getDefaultValue(method.getReturnType()); + } + + private byte[] serializeArgs(Object[] args) { + return ContractSerializeUtils.serializeArray(args); + } + + private Object getDefaultValue(Class returnType) { + if (returnType == void.class || returnType == Void.class) { + return null; + } + + if (!returnType.isPrimitive()) { + // 非基本类型 + return null; + } else { + // 基本类型需要处理返回值,目前采用枚举遍历方式 + // 八种基本类型:int, double, float, long, short, boolean, byte, char, void + if (returnType.equals(int.class)) { + return 0; + } else if (returnType.equals(double.class)) { + return 0.0D; + } else if (returnType.equals(float.class)) { + return 0F; + } else if (returnType.equals(long.class)) { + return 0L; + } else if (returnType.equals(short.class)) { + return (short) 0; + } else if (returnType.equals(boolean.class)) { + return Boolean.FALSE; + } else if (returnType.equals(byte.class)) { + return (byte) 0; + } else if (returnType.equals(char.class)) { + return (char) 0; + } + return null; + } + } +} 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 deleted file mode 100644 index 00a8edfc..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java +++ /dev/null @@ -1,110 +0,0 @@ -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; - -public class ContractInvocationProxy implements InvocationHandler { - - // private String contractMessage; - -// private Bytes contractAddress; - - private ContractType contractType; - -// private ContractEventSendOperationBuilder sendOpBuilder; - - private ContractEventSendOperation sendOperation; - - public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, - ContractEventSendOperationBuilder sendOpBuilder) { -// this.contractAddress = contractAddress; - if(contractType == null){ - throw new IllegalDataException("contractType == null, no invoke really."); - } - this.contractType = contractType; -// 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) { - // 该方法不是合约可执行的方法 - throw new IllegalAccessException(String.format("This Method [%s] is not Contract Event Method !!!", - method.getName())); - } - // 合约方法; - byte[] argBytes = serializeArgs(args); - if (sendOperation instanceof ContractEventSendOpTemplate) { - ((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes); - } - // 代理操作,返回值类型无法创建 - return returnResult(method.getReturnType()); - } - - private byte[] serializeArgs(Object[] args) { - return ContractSerializeUtils.serializeArray(args); - } - - public int opIndex() { - if (sendOperation instanceof ContractEventSendOpTemplate) { - return ((ContractEventSendOpTemplate) sendOperation).getOpIndex(); - } - return -1; - } - - private Object returnResult(Class clazz) { - if (clazz.equals(Void.TYPE)) { - return null; - } - - if (!clazz.isPrimitive()) { - // 非基本类型 - return null; - } else { - // 基本类型需要处理返回值,目前采用枚举遍历方式 - // 八种基本类型:int, double, float, long, short, boolean, byte, char, void - if (clazz.equals(int.class)) { - return 0; - } else if (clazz.equals(double.class)) { - return 0.0D; - } else if (clazz.equals(float.class)) { - return 0F; - } else if (clazz.equals(long.class)) { - return 0L; - } else if (clazz.equals(short.class)) { - return (short)0; - } else if (clazz.equals(boolean.class)) { - return Boolean.FALSE; - } else if (clazz.equals(byte.class)) { - return (byte)0; - } else if (clazz.equals(char.class)) { - return (char)0; - } - return null; - } - } -} 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 2d0d902a..82c07197 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 @@ -9,11 +9,17 @@ import com.jd.blockchain.contract.ContractType; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.IllegalDataException; +/** + * 合约调用代理的构建器; + * + * @author huanghaiquan + * + */ public class ContractInvocationProxyBuilder { private Map, ContractType> contractTypes = new ConcurrentHashMap<>(); - private Map contractOperations = new ConcurrentHashMap<>(); +// private Map contractOperations = new ConcurrentHashMap<>(); public T create(String address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); @@ -23,34 +29,34 @@ public class ContractInvocationProxyBuilder { public T create(Bytes address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { ContractType contractType = resolveContractType(contractIntf); - ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, - contractEventBuilder); + ContractInvocationHandler proxyHandler = new ContractInvocationHandler(address, contractType, contractEventBuilder); T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { contractIntf }, proxyHandler); - // 创建关联关系 - contractOperations.put(proxy, proxyHandler.opIndex()); +// // 创建关联关系 +// 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())); - } - - Integer opIndex = contractOperations.get(contractProxy); - if (opIndex != null && opIndex > -1) { - return new EventResult<>(opIndex); - } - return null; - } +// 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())); +// } +// +// Integer opIndex = contractOperations.get(contractProxy); +// if (opIndex != null && opIndex > -1) { +// return new EventResult<>(opIndex); +// } +// return null; +// } private ContractType resolveContractType(Class contractIntf) { ContractType contractType = contractTypes.get(contractIntf); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationStub.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationStub.java new file mode 100644 index 00000000..661319b1 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationStub.java @@ -0,0 +1,33 @@ +package com.jd.blockchain.transaction; + +/** + * 用于在上下文中传递合约调用返回值的工具类; + * + * @author huanghaiquan + * + */ +class ContractInvocationStub { + + private static ThreadLocal stub = new ThreadLocal(); + + private ContractInvocationStub() { + } + + public static void set(ContractInvocation invocation) { + if (invocation == null) { + throw new IllegalArgumentException("Null stub value!"); + } + stub.set(invocation); + } + + public static ContractInvocation take() { + ContractInvocation subValue = stub.get(); + if (subValue == null) { + throw new IllegalStateException( + "The latest invocation of contract has not been stubbed! It may be caused by the wrong call sequence from the upper layer!"); + } + stub.remove(); + return subValue; + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractReturns.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractReturns.java new file mode 100644 index 00000000..a4e4bdcd --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractReturns.java @@ -0,0 +1,418 @@ +package com.jd.blockchain.transaction; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ContractReturns { + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * ReturnValue retnHolder = decode(contract.issue(assetKey, amount)); + * + * PreparedTransaction prepTx = tx.prepare(); + * prepTx.sign(userKey); + * prepTx.commit() + * + * String retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果; + * + * + * @param + * @param call + * @return + */ + public static ReturnValue decode(T call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new ReturnValue(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount)); + * + * PreparedTransaction prepTx = tx.prepare(); + * prepTx.sign(userKey); + * prepTx.commit() + * + * long retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果; + * + * + * @param call + * @return + */ + public static ReturnLongValue decode(long call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new ReturnLongValue(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount)); + * + * PreparedTransaction prepTx = tx.prepare(); + * prepTx.sign(userKey); + * prepTx.commit() + * + * int retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果; + * + * + * @param call + * @return + */ + public static ReturnIntValue decode(int call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new ReturnIntValue(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount)); + * + * PreparedTransaction prepTx = tx.prepare(); + * prepTx.sign(userKey); + * prepTx.commit() + * + * short retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果; + * + * + * @param call + * @return + */ + public static ReturnShortValue decode(short call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new ReturnShortValue(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount)); + * + * PreparedTransaction prepTx = tx.prepare(); + * prepTx.sign(userKey); + * prepTx.commit() + * + * byte retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果; + * + * + * @param call + * @return + */ + public static ReturnByteValue decode(byte call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new ReturnByteValue(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount)); + * + * PreparedTransaction prepTx = tx.prepare(); + * prepTx.sign(userKey); + * prepTx.commit() + * + * boolean retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果; + * + * + * @param call + * @return + */ + public static ReturnBooleanValue decode(boolean call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new ReturnBooleanValue(invocation); + } + + + //----------------------- 内部类型 ----------------------- + + + private static class ReturnValueBase { + private ContractInvocation invocation; + + private ReturnValueBase(ContractInvocation invocation) { + this.invocation = invocation; + } + + /** + * 等待结果合约调用的结果返回; + * + * @return + */ + private Object get() { + try { + return invocation.getReturnValue().get(); + } catch (InterruptedException | ExecutionException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @param unit + * @return + * @throws TimeoutException + */ + private Object get(long timeout, TimeUnit unit) throws TimeoutException { + try { + return invocation.getReturnValue().get(timeout, unit); + } catch (InterruptedException | ExecutionException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + } + + public static class ReturnValue extends ReturnValueBase { + + private ReturnValue(ContractInvocation invocation) { + super(invocation); + } + + /** + * 等待结果合约调用的结果返回; + * + * @return + */ + @SuppressWarnings("unchecked") + public T get() { + return (T) super.get(); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @return + * @throws TimeoutException + */ + public T get(long timeout) throws TimeoutException { + return get(timeout, TimeUnit.MILLISECONDS); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @param unit + * @return + * @throws TimeoutException + */ + @SuppressWarnings("unchecked") + public T get(long timeout, TimeUnit unit) throws TimeoutException { + return (T) super.get(timeout, unit); + } + } + + public static class ReturnLongValue extends ReturnValueBase { + + private ReturnLongValue(ContractInvocation invocation) { + super(invocation); + } + + /** + * 等待结果合约调用的结果返回; + * + * @return + */ + public long get() { + return (long) super.get(); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @return + * @throws TimeoutException + */ + public long get(long timeout) throws TimeoutException { + return get(timeout, TimeUnit.MILLISECONDS); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @param unit + * @return + * @throws TimeoutException + */ + public long get(long timeout, TimeUnit unit) throws TimeoutException { + return (long) super.get(timeout, unit); + } + } + + public static class ReturnIntValue extends ReturnValueBase { + + private ReturnIntValue(ContractInvocation invocation) { + super(invocation); + } + + /** + * 等待结果合约调用的结果返回; + * + * @return + */ + public int get() { + return (int) super.get(); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @return + * @throws TimeoutException + */ + public int get(long timeout) throws TimeoutException { + return get(timeout, TimeUnit.MILLISECONDS); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @param unit + * @return + * @throws TimeoutException + */ + public int get(long timeout, TimeUnit unit) throws TimeoutException { + return (int) super.get(timeout, unit); + } + } + + public static class ReturnShortValue extends ReturnValueBase { + + private ReturnShortValue(ContractInvocation invocation) { + super(invocation); + } + + /** + * 等待结果合约调用的结果返回; + * + * @return + */ + public short get() { + return (short) super.get(); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @return + * @throws TimeoutException + */ + public short get(long timeout) throws TimeoutException { + return get(timeout, TimeUnit.MILLISECONDS); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @param unit + * @return + * @throws TimeoutException + */ + public short get(long timeout, TimeUnit unit) throws TimeoutException { + return (short) super.get(timeout, unit); + } + } + + public static class ReturnByteValue extends ReturnValueBase { + + private ReturnByteValue(ContractInvocation invocation) { + super(invocation); + } + + /** + * 等待结果合约调用的结果返回; + * + * @return + */ + public byte get() { + return (byte) super.get(); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @return + * @throws TimeoutException + */ + public byte get(long timeout) throws TimeoutException { + return get(timeout, TimeUnit.MILLISECONDS); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @param unit + * @return + * @throws TimeoutException + */ + public byte get(long timeout, TimeUnit unit) throws TimeoutException { + return (byte) super.get(timeout, unit); + } + } + + public static class ReturnBooleanValue extends ReturnValueBase { + + private ReturnBooleanValue(ContractInvocation invocation) { + super(invocation); + } + + /** + * 等待结果合约调用的结果返回; + * + * @return + */ + public boolean get() { + return (boolean) super.get(); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @return + * @throws TimeoutException + */ + public boolean get(long timeout) throws TimeoutException { + return get(timeout, TimeUnit.MILLISECONDS); + } + + /** + * 等待结果合约调用的结果返回; + * + * @param timeout + * @param unit + * @return + * @throws TimeoutException + */ + public boolean get(long timeout, TimeUnit unit) throws TimeoutException { + return (boolean) super.get(timeout, unit); + } + } +} 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 de6e1c0e..8540a470 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,18 +1,9 @@ package com.jd.blockchain.transaction; -import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.utils.Bytes; public interface EventOperator { - // /** - // * 合约事件; - // * - // * @return - // */ - // @Deprecated - // ContractEventSendOperationBuilder contractEvents(); - /** * 创建调用合约的代理实例; * @@ -31,11 +22,11 @@ public interface EventOperator { */ T contract(Bytes address, Class contractIntf); - /** - * 执行合约异步等待应答结果 - * - * @param execute - * @return - */ - EventResult result(ContractEventExecutor execute); +// /** +// * 执行合约异步等待应答结果 +// * +// * @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/OperationReturnValueHandler.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationReturnValueHandler.java new file mode 100644 index 00000000..c490091a --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationReturnValueHandler.java @@ -0,0 +1,11 @@ +package com.jd.blockchain.transaction; + +import com.jd.blockchain.ledger.BytesValue; + +interface OperationReturnValueHandler { + + int getOperationIndex(); + + Object setReturnValue(BytesValue bytesValue); + +} 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 f45706f4..f9636427 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,17 +1,23 @@ package com.jd.blockchain.transaction; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; + 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.*; - -import java.util.Map; +import com.jd.blockchain.ledger.DigitalSignature; +import com.jd.blockchain.ledger.OperationResult; +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; public class PreparedTx implements PreparedTransaction { @@ -19,16 +25,29 @@ public class PreparedTx implements PreparedTransaction { private TransactionService txProcessor; - private Map eventResults; + private OperationReturnValueHandler[] opReturnValueHandlers; - public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor) { - this(txReqBuilder, txProcessor, null); - } - - public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, Map eventResults) { + /** + * 创建一个“就绪交易”对象; + * + * @param txReqBuilder 交易请求构建器; + * @param txProcessor 交易处理服务; + * @param opReturnValueHandlerList 操作返回值处理器列表; + */ + public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, + Collection opReturnValueHandlerList) { this.txReqBuilder = txReqBuilder; this.txProcessor = txProcessor; - this.eventResults = eventResults; + + this.opReturnValueHandlers = opReturnValueHandlerList + .toArray(new OperationReturnValueHandler[opReturnValueHandlerList.size()]); + // 按照操作索引升序排列; + Arrays.sort(opReturnValueHandlers, new Comparator() { + @Override + public int compare(OperationReturnValueHandler o1, OperationReturnValueHandler o2) { + return o1.getOperationIndex() - o2.getOperationIndex(); + } + }); } @Override @@ -59,23 +78,32 @@ public class PreparedTx implements PreparedTransaction { @Override public TransactionResponse commit() { - 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())); + try { + TransactionRequest txReq = txReqBuilder.buildRequest(); + // 发起交易请求; + TransactionResponse txResponse = txProcessor.process(txReq); + + // 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的; + OperationResult[] opResults = txResponse.getOperationResults(); + if (opResults != null && opResults.length > 0) { + if (opResults.length != opReturnValueHandlers.length) { + throw new IllegalStateException(String.format( + "The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]", + txReq.getTransactionContent().getHash(), opResults.length, opReturnValueHandlers.length)); + } + for (int i = 0; i < opResults.length; i++) { + if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) { + throw new IllegalStateException( + "The operation indexes of the items in the result list and in the handler list don't match!"); + } + opReturnValueHandlers[i].setReturnValue(opResults[i].getResult()); } } + return txResponse; + } catch (Exception e) { + //TODO: 出错时清理交易上下文,释放与交易关联对异步等待资源,避免当前线程死锁; + } - 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 87cabb3a..bf99acdb 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 @@ -1,8 +1,9 @@ package com.jd.blockchain.transaction; +import java.util.Collection; + 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; @@ -11,9 +12,6 @@ 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 { @@ -22,8 +20,6 @@ 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; @@ -55,6 +51,10 @@ public class TxBuilder implements TransactionBuilder { return txContent; } + public Collection getReturnValuehandlers() { + return opFactory.getReturnValuetHandlers(); + } + @Override public LedgerInitOperationBuilder ledgers() { return opFactory.ledgers(); @@ -94,11 +94,6 @@ 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/TxRequestBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java index 5265b4be..7d6701a5 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java @@ -71,8 +71,7 @@ public class TxRequestBuilder implements TransactionRequestBuilder { } public static SignatureDigest sign(TransactionContent txContent, PrivKey privKey) { - return Crypto.getSignatureFunction(privKey.getAlgorithm()).sign(privKey, - txContent.getHash().toBytes()); + return Crypto.getSignatureFunction(privKey.getAlgorithm()).sign(privKey, txContent.getHash().toBytes()); } public static boolean verifySignature(TransactionContent txContent, SignatureDigest signDigest, PubKey pubKey) { 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 908ee7fc..cbe7688f 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,27 +1,21 @@ 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 @@ -32,7 +26,7 @@ public class TxTemplate implements TransactionTemplate { @Override public PreparedTransaction prepare() { TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); - return new PreparedTx(txReqBuilder, txService, eventResults); + return new PreparedTx(txReqBuilder, txService, txBuilder.getReturnValuehandlers()); } @Override @@ -60,25 +54,11 @@ public class TxTemplate implements TransactionTemplate { return txBuilder.contracts(); } -// @Override -// public ContractEventSendOperationBuilder contractEvents() { -// return txBuilder.contractEvents(); -// } - @Override 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/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java index 15a023f4..b6a5444a 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java @@ -1,164 +1,159 @@ package com.jd.blockchain.sdk.samples; +import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; +import static com.jd.blockchain.transaction.ContractReturns.decode; + import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.contract.TransferContract; -import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; import com.jd.blockchain.transaction.ContractEventExecutor; +import com.jd.blockchain.transaction.ContractReturns.ReturnLongValue; +import com.jd.blockchain.transaction.ContractReturns.ReturnValue; import com.jd.blockchain.utils.Bytes; -import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; - public class SDK_Contract_Demo extends SDK_Base_Demo { - public static void main(String[] args) { - SDK_Contract_Demo demo = new SDK_Contract_Demo(); - demo.executeContract(); - } - - public void executeContract() { - - // 发布jar包 - // 定义交易模板 - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - // 将jar包转换为二进制数据 - byte[] contractCode = readChainCodes("transfer.jar"); - - // 生成一个合约账号 - BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - - // 生成发布合约操作 - txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); - - // 生成预发布交易; - PreparedTransaction ptx = txTpl.prepare(); - - // 对交易进行签名 - ptx.sign(adminKey); - - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); - - // 获取合约地址 - Bytes contractAddress = contractDeployKey.getAddress(); - - // 打印交易返回信息 - System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n", - txResp.getContentHash().toBase58(), txResp.getBlockHeight(), - txResp.getBlockHash().toBase58(), txResp.isSuccess(), - txResp.getExecutionState()); - - // 打印合约地址 - System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58()); - - // 注册一个数据账户 - BlockchainKeypair dataAccount = createDataAccount(); - // 获取数据账户地址 - String dataAddress = dataAccount.getAddress().toBase58(); - // 打印数据账户地址 - System.out.printf("DataAccountAddress = %s \r\n", dataAddress); - - // 创建两个账号: - String account0 = "jd_zhangsan", account1 = "jd_lisi"; - long account0Money = 3000L, account1Money = 2000L; - // 创建两个账户 - // 使用KV操作创建一个账户 - System.out.println(create(dataAddress, account0, account0Money, false, null)); - // 使用合约创建一个账户 - System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); - - // 转账,使得双方钱达到一致 - System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); - - // 通过合约读取account0的当前信息 - System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By Contract)\r\n", - dataAddress, account0, readByContract(dataAddress, account0, contractAddress)); - // 通过KV读取account1的当前信息 - System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By KV Operation)\r\n", - dataAddress, account1, readByKvOperation(dataAddress, account1)); - - // 通过合约读取account0的历史信息 - System.out.println(readAll(dataAddress, account0, contractAddress)); - // 通过合约读取account1的历史信息 - System.out.println(readAll(dataAddress, account1, contractAddress)); - } - - private String readAll(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - EventResult eventResult = txTpl.result((ContractEventExecutor) () -> { - transferContract.readAll(address, account); - return transferContract; - }); - commit(txTpl); - return eventResult.get(); - } - - private long readByContract(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - EventResult eventResult = txTpl.result((ContractEventExecutor) () -> { - transferContract.read(address, account); - return transferContract; - }); - commit(txTpl); - return eventResult.get(); - } - - private long readByKvOperation(String address, String account) { - KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); - if (kvDataEntries == null || kvDataEntries.length == 0) { - throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); - } - KVDataEntry kvDataEntry = kvDataEntries[0]; - if (kvDataEntry.getVersion() == -1) { - return 0L; - } - return (long) (kvDataEntry.getValue()); - } - - - private String transfer(String address, String from, String to, long money, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - EventResult eventResult = txTpl.result((ContractEventExecutor) () -> { - transferContract.transfer(address, from, to, money); - return transferContract; - }); - commit(txTpl); - return eventResult.get(); - } - - private BlockchainKeypair createDataAccount() { - // 首先注册一个数据账户 - BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.dataAccounts().register(newDataAccount.getIdentity()); - commit(txTpl); - return newDataAccount; - } - - private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - if (useContract) { - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - EventResult eventResult = txTpl.result((ContractEventExecutor) () -> { - transferContract.create(address, account, money); - return transferContract; - }); - commit(txTpl); - return eventResult.get(); - } else { - // 通过KV创建 - txTpl.dataAccount(address).setInt64(account, money, -1); - TransactionResponse txResp = commit(txTpl); - return String.format("DataAccountAddress[%s] -> Create(By KV Operation) Account = %s and Money = %s Success!!! \r\n", - address, account, money); - } - } + public static void main(String[] args) { + SDK_Contract_Demo demo = new SDK_Contract_Demo(); + demo.executeContract(); + } + + public void executeContract() { + + // 发布jar包 + // 定义交易模板 + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + + // 将jar包转换为二进制数据 + byte[] contractCode = readChainCodes("transfer.jar"); + + // 生成一个合约账号 + BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); + + // 生成发布合约操作 + txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); + + // 生成预发布交易; + PreparedTransaction ptx = txTpl.prepare(); + + // 对交易进行签名 + ptx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse txResp = ptx.commit(); + + // 获取合约地址 + Bytes contractAddress = contractDeployKey.getAddress(); + + // 打印交易返回信息 + System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n", + txResp.getContentHash().toBase58(), txResp.getBlockHeight(), txResp.getBlockHash().toBase58(), + txResp.isSuccess(), txResp.getExecutionState()); + + // 打印合约地址 + System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58()); + + // 注册一个数据账户 + BlockchainKeypair dataAccount = createDataAccount(); + // 获取数据账户地址 + String dataAddress = dataAccount.getAddress().toBase58(); + // 打印数据账户地址 + System.out.printf("DataAccountAddress = %s \r\n", dataAddress); + + // 创建两个账号: + String account0 = "jd_zhangsan", account1 = "jd_lisi"; + long account0Money = 3000L, account1Money = 2000L; + // 创建两个账户 + // 使用KV操作创建一个账户 + System.out.println(create(dataAddress, account0, account0Money, false, null)); + // 使用合约创建一个账户 + System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); + + // 转账,使得双方钱达到一致 + System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); + + // 通过合约读取account0的当前信息 + System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By Contract)\r\n", dataAddress, + account0, readByContract(dataAddress, account0, contractAddress)); + // 通过KV读取account1的当前信息 + System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By KV Operation)\r\n", dataAddress, + account1, readByKvOperation(dataAddress, account1)); + + // 通过合约读取account0的历史信息 + System.out.println(readAll(dataAddress, account0, contractAddress)); + // 通过合约读取account1的历史信息 + System.out.println(readAll(dataAddress, account1, contractAddress)); + } + + private String readAll(String address, String account, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + ReturnValue result = decode(transferContract.readAll(address, account)); + commit(txTpl); + return result.get(); + } + + private long readByContract(String address, String account, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + ReturnLongValue result = decode(transferContract.read(address, account)); + commit(txTpl); + return result.get(); + } + + private long readByKvOperation(String address, String account) { + KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); + if (kvDataEntries == null || kvDataEntries.length == 0) { + throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); + } + KVDataEntry kvDataEntry = kvDataEntries[0]; + if (kvDataEntry.getVersion() == -1) { + return 0L; + } + return (long) (kvDataEntry.getValue()); + } + + private String transfer(String address, String from, String to, long money, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + ReturnValue result = decode(transferContract.transfer(address, from, to, money)); + commit(txTpl); + return result.get(); + } + + private BlockchainKeypair createDataAccount() { + // 首先注册一个数据账户 + BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + txTpl.dataAccounts().register(newDataAccount.getIdentity()); + commit(txTpl); + return newDataAccount; + } + + private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + if (useContract) { + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + ReturnValue result = decode(transferContract.create(address, account, money)); + commit(txTpl); + return result.get(); + } else { + // 通过KV创建 + txTpl.dataAccount(address).setInt64(account, money, -1); + TransactionResponse txResp = commit(txTpl); + return String.format( + "DataAccountAddress[%s] -> Create(By KV Operation) Account = %s and Money = %s Success!!! \r\n", + address, account, money); + } + } } diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test.java index 3aa3035c..3959261e 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test.java @@ -1,171 +1,165 @@ package test.com.jd.blockchain.sdk.test; -import com.jd.blockchain.contract.EventResult; +import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; +import static com.jd.blockchain.transaction.ContractReturns.decode; + +import org.junit.Before; +import org.junit.Test; + import com.jd.blockchain.contract.TransferContract; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PrivKey; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.sdk.client.GatewayServiceFactory; import com.jd.blockchain.sdk.samples.SDKDemo_Constant; import com.jd.blockchain.tools.keygen.KeyGenCommand; -import com.jd.blockchain.transaction.ContractEventExecutor; +import com.jd.blockchain.transaction.ContractReturns.ReturnLongValue; +import com.jd.blockchain.transaction.ContractReturns.ReturnValue; import com.jd.blockchain.utils.Bytes; -import org.junit.Before; -import org.junit.Test; - -import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; public class SDKDemo_Contract_Test { - private BlockchainKeypair adminKey; + private BlockchainKeypair adminKey; - private HashDigest ledgerHash; + private HashDigest ledgerHash; - private BlockchainService blockchainService; + private BlockchainService blockchainService; - @Before - public void init() { - // 生成连接网关的账号 - PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], SDKDemo_Constant.PASSWORD); + @Before + public void init() { + // 生成连接网关的账号 + PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], + SDKDemo_Constant.PASSWORD); - PubKey pubKey = KeyGenCommand.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]); + PubKey pubKey = KeyGenCommand.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]); - adminKey = new BlockchainKeypair(pubKey, privKey); + adminKey = new BlockchainKeypair(pubKey, privKey); - // 连接网关 - GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, - SDKDemo_Constant.GW_PORT, false, adminKey); + // 连接网关 + GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, + SDKDemo_Constant.GW_PORT, false, adminKey); - blockchainService = serviceFactory.getBlockchainService(); + blockchainService = serviceFactory.getBlockchainService(); - HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); + HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); - ledgerHash = ledgerHashs[0]; - } + ledgerHash = ledgerHashs[0]; + } - @Test - public void testContract() { + @Test + public void testContract() { - // 发布jar包 - // 定义交易; - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 发布jar包 + // 定义交易; + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - byte[] contractCode = readChainCodes("transfer.jar"); - - // 生成一个合约账号 - BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - - txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); - - // 签名; - PreparedTransaction ptx = txTpl.prepare(); - - ptx.sign(adminKey); - - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); - - System.out.println(txResp.isSuccess()); - - // 首先注册一个数据账户 - BlockchainKeypair dataAccount = createDataAccount(); - - String dataAddress = dataAccount.getAddress().toBase58(); - - Bytes contractAddress = contractDeployKey.getAddress(); - - // 创建两个账号: - String account0 = "jd_zhangsan", account1 = "jd_lisi"; - long account0Money = 3000L, account1Money = 2000L; - // 创建两个账户 - // 使用KV创建一个账户 - System.out.println(create(dataAddress, account0, account0Money, false, null)); - // 使用合约创建一个账户 - System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); - - // 转账,使得双方钱达到一致 - System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); - - // 读取当前结果 - System.out.println(read(dataAddress, account0, contractAddress)); - System.out.println(read(dataAddress, account1, contractAddress)); - - // 读取账号历史信息 - System.out.println(readAll(dataAddress, account0, contractAddress)); - System.out.println(readAll(dataAddress, account1, contractAddress)); - } - - private String readAll(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - EventResult eventResult = txTpl.result((ContractEventExecutor) () -> { - transferContract.readAll(address, account); - return transferContract; - }); - commit(txTpl); - return eventResult.get(); - } - - private long read(String address, String account, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - EventResult eventResult = txTpl.result((ContractEventExecutor) () -> { - transferContract.read(address, account); - return transferContract; - }); - commit(txTpl); - return eventResult.get(); - } - - private String transfer(String address, String from, String to, long money, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - EventResult eventResult = txTpl.result((ContractEventExecutor) () -> { - transferContract.transfer(address, from, to, money); - return transferContract; - }); - commit(txTpl); - return eventResult.get(); - } - - - private BlockchainKeypair createDataAccount() { - // 首先注册一个数据账户 - BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); - - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.dataAccounts().register(newDataAccount.getIdentity()); - commit(txTpl); - return newDataAccount; - } - - private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - if (useContract) { - // 使用合约创建 - TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); - EventResult eventResult = txTpl.result((ContractEventExecutor) () -> { - transferContract.create(address, account, money); - return transferContract; - }); - commit(txTpl); - return eventResult.get(); - } else { - // 通过KV创建 - txTpl.dataAccount(address).setInt64(account, money, -1); - TransactionResponse txResp = commit(txTpl); - return account + money; - } - } - - private TransactionResponse commit(TransactionTemplate txTpl) { - PreparedTransaction ptx = txTpl.prepare(); - ptx.sign(adminKey); - return ptx.commit(); - } + byte[] contractCode = readChainCodes("transfer.jar"); + + // 生成一个合约账号 + BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); + + txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); + + // 签名; + PreparedTransaction ptx = txTpl.prepare(); + + ptx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse txResp = ptx.commit(); + + System.out.println(txResp.isSuccess()); + + // 首先注册一个数据账户 + BlockchainKeypair dataAccount = createDataAccount(); + + String dataAddress = dataAccount.getAddress().toBase58(); + + Bytes contractAddress = contractDeployKey.getAddress(); + + // 创建两个账号: + String account0 = "jd_zhangsan", account1 = "jd_lisi"; + long account0Money = 3000L, account1Money = 2000L; + // 创建两个账户 + // 使用KV创建一个账户 + System.out.println(create(dataAddress, account0, account0Money, false, null)); + // 使用合约创建一个账户 + System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); + + // 转账,使得双方钱达到一致 + System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); + + // 读取当前结果 + System.out.println(read(dataAddress, account0, contractAddress)); + System.out.println(read(dataAddress, account1, contractAddress)); + + // 读取账号历史信息 + System.out.println(readAll(dataAddress, account0, contractAddress)); + System.out.println(readAll(dataAddress, account1, contractAddress)); + } + + private String readAll(String address, String account, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + ReturnValue result = decode(transferContract.readAll(address, account)); + commit(txTpl); + return result.get(); + } + + private long read(String address, String account, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + ReturnLongValue result = decode(transferContract.read(address, account)); + commit(txTpl); + return result.get(); + } + + private String transfer(String address, String from, String to, long money, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + ReturnValue result = decode(transferContract.transfer(address, from, to, money)); + commit(txTpl); + return result.get(); + } + + private BlockchainKeypair createDataAccount() { + // 首先注册一个数据账户 + BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + txTpl.dataAccounts().register(newDataAccount.getIdentity()); + commit(txTpl); + return newDataAccount; + } + + private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + if (useContract) { + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + ReturnValue result = decode(transferContract.create(address, account, money)); + commit(txTpl); + return result.get(); + } else { + // 通过KV创建 + txTpl.dataAccount(address).setInt64(account, money, -1); + TransactionResponse txResp = commit(txTpl); + return account + money; + } + } + + private TransactionResponse commit(TransactionTemplate txTpl) { + PreparedTransaction ptx = txTpl.prepare(); + ptx.sign(adminKey); + return ptx.commit(); + } } 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 66aa8b5e..034c3a6c 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,24 +24,35 @@ import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicLong; -import com.jd.blockchain.contract.ContractSerializeUtils; -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; import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.contract.ContractSerializeUtils; +import com.jd.blockchain.contract.EventResult; +import com.jd.blockchain.contract.ReadContract; 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.OperationResult; +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; import com.jd.blockchain.storage.service.DbConnection; import com.jd.blockchain.storage.service.DbConnectionFactory; import com.jd.blockchain.tools.initializer.LedgerBindingConfig; +import com.jd.blockchain.transaction.ContractEventExecutor; +import static com.jd.blockchain.transaction.ContractReturns.*; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.concurrent.ThreadInvoker; import com.jd.blockchain.utils.net.NetworkAddress; @@ -576,10 +587,7 @@ public class IntegrationBase { ReadContract readContract1 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); - EventResult read1 = txContract.result((ContractEventExecutor) () -> { - readContract1.read(newDataAccount.getAddress().toBase58(), key1); - return readContract1; - }); + ReturnValue result1 = decode(readContract1.read(newDataAccount.getAddress().toBase58(), key1)); ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); @@ -587,10 +595,7 @@ public class IntegrationBase { ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); - EventResult read3 = txContract.result((ContractEventExecutor) () -> { - readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2); - return readContract3; - }); + ReturnValue result3 = decode(readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2)); // 签名; PreparedTransaction contractPtx = txContract.prepare(); @@ -602,8 +607,8 @@ public class IntegrationBase { OperationResult[] operationResults = readTxResp.getOperationResults(); // 通过EventResult获取结果 - System.out.printf("readContract1.result = %s \r\n", read1.get()); - System.out.printf("readContract3.result = %s \r\n", read3.get()); + System.out.printf("readContract1.result = %s \r\n", result1.get()); + System.out.printf("readContract3.result = %s \r\n", result3.get()); // 打印结果 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 ec321728..8b31a389 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 @@ -11,6 +11,7 @@ import com.jd.blockchain.contract.EventProcessingAware; import com.jd.blockchain.contract.LedgerContext; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.TransactionRequest; @@ -33,7 +34,7 @@ public class MockerContractExeHandle implements OperationHandle { private HashDigest ledgerHash; @Override - public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { ContractEventSendOperation contractOP = (ContractEventSendOperation) op; @@ -76,11 +77,6 @@ public class MockerContractExeHandle implements OperationHandle { 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);