From 713f8471650bee6cd2400585e517dc85197e43f0 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Fri, 14 Jun 2019 18:10:00 +0800 Subject: [PATCH] Modify the way of Contract's return Result ! --- .../jd/blockchain/contract/ReadContract.java | 2 + .../blockchain/contract/ReadContractImpl.java | 5 ++ .../contract/ContractSerializeUtils.java | 12 ++++- .../jd/blockchain/contract/EventResult.java | 39 +++++++++++++++ .../ledger/ContractEventSendOperation.java | 1 - .../jd/blockchain/ledger/OperationResult.java | 2 - .../ledger/OperationResultData.java | 10 ---- .../BlockchainOperationFactory.java | 29 ++++++++--- .../transaction/ContractEventExecutor.java | 6 +++ .../ContractEventSendOpTemplate.java | 40 +++++++++++++++ .../ContractEventSendOperationBuilder.java | 13 +++++ ...ContractEventSendOperationBuilderImpl.java | 42 ++++++++-------- .../transaction/ContractInvocationProxy.java | 50 ++++++++++++++----- .../ContractInvocationProxyBuilder.java | 42 ++++++++++------ .../blockchain/transaction/ContractType.java | 7 +++ .../blockchain/transaction/EventOperator.java | 8 +++ .../jd/blockchain/transaction/PreparedTx.java | 24 +++++++-- .../jd/blockchain/transaction/TxBuilder.java | 11 ++++ .../jd/blockchain/transaction/TxTemplate.java | 20 +++++++- .../jd/blockchain/intgr/IntegrationBase.java | 32 +++++++++--- .../mocker/proxy/ContractProxy.java | 3 +- 21 files changed, 313 insertions(+), 85 deletions(-) create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java index 8f97fb10..25bc9aca 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java @@ -9,5 +9,7 @@ public interface ReadContract { @ContractEvent(name = "version-key") Long readVersion(String address, String key); + + int test(); } diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java index 5bb18b36..83072f7a 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java @@ -42,4 +42,9 @@ public class ReadContractImpl implements EventProcessingAwire, ReadContract { } return -1L; } + + @Override + public int test() { + return 0; + } } 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 ffbd4437..6214c24e 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,7 +1,6 @@ package com.jd.blockchain.contract; -import com.jd.blockchain.binaryproto.BinaryProtocol; -import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.*; import com.jd.blockchain.contract.param.*; import com.jd.blockchain.utils.io.BytesUtils; @@ -19,9 +18,18 @@ public class ContractSerializeUtils { 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) { diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java new file mode 100644 index 00000000..928d5979 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java @@ -0,0 +1,39 @@ +package com.jd.blockchain.contract; + +import com.jd.blockchain.utils.IllegalDataException; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +public class EventResult { + + private static final long MAX_SECONDS = 30; + + private CompletableFuture data = new CompletableFuture<>(); + + private int opIndex; + + public EventResult() { + } + + public EventResult(int opIndex) { + this.opIndex = opIndex; + } + + public void done(T value) { + data.complete(value); + } + + public int opIndex() { + return this.opIndex; + } + + public T get() { + try { + // 防止长时间阻塞 + return data.get(MAX_SECONDS, TimeUnit.SECONDS); + } catch (Exception e) { + throw new IllegalDataException(e.getMessage()); + } + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java index 9b0219b0..1530fb0c 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java @@ -44,5 +44,4 @@ public interface ContractEventSendOperation extends Operation { */ @DataField(order = 5, primitiveType = PrimitiveType.INT64) long getTxOpTime(); - } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java index 49e48be7..a6b25344 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java @@ -13,6 +13,4 @@ public interface OperationResult { @DataField(order=2, primitiveType = PrimitiveType.BYTES) byte[] getResult(); - - T getResultData(); } 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 f8eb0959..399596a3 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java @@ -1,6 +1,5 @@ package com.jd.blockchain.ledger; -import com.jd.blockchain.contract.ContractSerializeUtils; public class OperationResultData implements OperationResult { @@ -11,10 +10,6 @@ public class OperationResultData implements OperationResult { public OperationResultData() { } - public OperationResultData(OperationResult operationResult) { - this(operationResult.getIndex(), operationResult.getResult()); - } - public OperationResultData(int index, byte[] result) { this.index = index; this.result = result; @@ -30,11 +25,6 @@ public class OperationResultData implements OperationResult { return result; } - @Override - public T getResultData() { - return (T) ContractSerializeUtils.resolve(result); - } - public void setIndex(int index) { this.index = index; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java index 9f2d97d1..b38d06fa 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.ContractEventSendOperation; @@ -29,7 +30,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe private static final ContractCodeDeployOperationBuilderImpl CONTRACT_CODE_DEPLOY_OP_BUILDER = new ContractCodeDeployOperationBuilderImpl(); - private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); +// private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter(); @@ -89,6 +90,11 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); } + @Override + public EventResult result(ContractEventExecutor execute) { + return contractInvoProxyBuilder.execute(execute); + } + public Collection getOperations() { // TODO: 合并操作列表中可能的重复操作; return operationList; @@ -130,7 +136,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe operationList.add(op); return op; } - } private class DataAccountKVSetOperationBuilderFilter implements DataAccountKVSetOperationBuilder { @@ -235,25 +240,35 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe operationList.add(op); return op; } - } private class ContractEventSendOperationBuilderFilter implements ContractEventSendOperationBuilder { @Override public ContractEventSendOperation send(String address, String event, byte[] args) { - ContractEventSendOperation op = CONTRACT_EVENT_SEND_OP_BUILDER.send(address, event, args); - operationList.add(op); - return op; + return send(Bytes.fromBase58(address), event, args); } @Override public ContractEventSendOperation send(Bytes address, String event, byte[] args) { - ContractEventSendOperation op = CONTRACT_EVENT_SEND_OP_BUILDER.send(address, event, args); + int opIndex = operationList.size(); + ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args, opIndex); operationList.add(op); return op; } + @Override + public ContractEventSendOperation send(String address) { + return send(Bytes.fromBase58(address)); + } + + @Override + public ContractEventSendOperation send(Bytes address) { + int opIndex = operationList.size(); + ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, opIndex); + operationList.add(op); + return op; + } } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java new file mode 100644 index 00000000..4cacf19c --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java @@ -0,0 +1,6 @@ +package com.jd.blockchain.transaction; + +public interface ContractEventExecutor { + + T execute(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java index 7acc42ba..641ea6f2 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java @@ -5,6 +5,7 @@ import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.utils.Bytes; public class ContractEventSendOpTemplate implements ContractEventSendOperation { + static { DataContractRegistry.register(ContractEventSendOperation.class); } @@ -14,17 +15,47 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { private String event; //交易操作时间; private long txOpTime; + // 所属操作Index + private int opIndex; public ContractEventSendOpTemplate() { } + public ContractEventSendOpTemplate(Bytes contractAddress) { + this(contractAddress, -1); + } + + public ContractEventSendOpTemplate(Bytes contractAddress, int opIndex) { + this.contractAddress = contractAddress; + this.opIndex = opIndex; + this.txOpTime = System.currentTimeMillis(); + } + public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args) { + this(contractAddress, event, args, -1); + } + + public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args, int opIndex) { this.contractAddress = contractAddress; this.event = event; this.args = args; + this.opIndex = opIndex; this.txOpTime = System.currentTimeMillis(); } + public void setArgs(byte[] args) { + this.args = args; + } + + public void setEvent(String event) { + this.event = event; + } + + public void setEventAndArgs(String event, byte[] args) { + this.event = event; + this.args = args; + } + @Override public Bytes getContractAddress() { return contractAddress; @@ -44,4 +75,13 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { public long getTxOpTime() { return txOpTime; } + + /** + * 获取所属交易中的序号,该值不需要序列化 + * + * @return + */ + public int getOpIndex() { + return opIndex; + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java index 66f1ec22..5bc2e539 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java @@ -23,4 +23,17 @@ public interface ContractEventSendOperationBuilder { @Deprecated ContractEventSendOperation send(Bytes address, String event, byte[] args); + /** + * + * @param address + * @return + */ + ContractEventSendOperation send(String address); + + /** + * + * @param address + * @return + */ + ContractEventSendOperation send(Bytes address); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java index beccc539..faae0029 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java @@ -1,21 +1,21 @@ -package com.jd.blockchain.transaction; - -import com.jd.blockchain.ledger.ContractEventSendOperation; -import com.jd.blockchain.utils.Bytes; - -@Deprecated -class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { - - @Override - public ContractEventSendOperation send(String address, String event, byte[] args) { - ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); - return op; - } - - @Override - public ContractEventSendOperation send(Bytes address, String event, byte[] args) { - ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); - return op; - } - -} +//package com.jd.blockchain.transaction; +// +//import com.jd.blockchain.ledger.ContractEventSendOperation; +//import com.jd.blockchain.utils.Bytes; +// +//@Deprecated +//class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { +// +// @Override +// public ContractEventSendOperation send(String address, String event, byte[] args) { +// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); +// return op; +// } +// +// @Override +// public ContractEventSendOperation send(Bytes address, String event, byte[] args) { +// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); +// return op; +// } +// +//} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java index bcccf78b..617a74c7 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java @@ -4,6 +4,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import com.jd.blockchain.contract.ContractSerializeUtils; +import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.IllegalDataException; @@ -11,41 +12,66 @@ public class ContractInvocationProxy implements InvocationHandler { // private String contractMessage; - private Bytes contractAddress; +// private Bytes contractAddress; private ContractType contractType; - private ContractEventSendOperationBuilder sendOpBuilder; +// private ContractEventSendOperationBuilder sendOpBuilder; + + private ContractEventSendOperation sendOperation; public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, ContractEventSendOperationBuilder sendOpBuilder) { - this.contractAddress = contractAddress; +// this.contractAddress = contractAddress; if(contractType == null){ throw new IllegalDataException("contractType == null, no invoke really."); } this.contractType = contractType; - this.sendOpBuilder = sendOpBuilder; +// this.sendOpBuilder = sendOpBuilder; + // Send一个地址,但不涉及Event + this.sendOperation = sendOpBuilder.send(contractAddress); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + + // 判断是否是常规方法调用 + if (method.getName().equals("hashCode")) { + // 该处需要使用当前代理类的HashCode + return this.hashCode(); + } + if (method.getName().equals("toString")) { + // 该处使用当前代理类的toString + return this.toString(); + } + + if (sendOperation.getEvent() != null) { + throw new IllegalStateException("Contract Object can only execute method one time !!!"); + } + String event = contractType.getEvent(method); if (event == null) { - // 适配 Object 对象的方法; - // toString 方法; - return String.format("[%s]-%s", contractAddress, contractType.toString()); - - // hashCode 方法; + // 该方法不是合约可执行的方法 + throw new IllegalAccessException(String.format("This Method [%s] is not Contract Event Method !!!", + method.getName())); } // 合约方法; byte[] argBytes = serializeArgs(args); - sendOpBuilder.send(contractAddress, event, argBytes); - - // TODO: 暂时未考虑有返回值的情况; + if (sendOperation instanceof ContractEventSendOpTemplate) { + ((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes); + } + // 代理操作,返回值类型无法创建 return null; } private byte[] serializeArgs(Object[] args) { return ContractSerializeUtils.serializeArray(args); } + + public int opIndex() { + if (sendOperation instanceof ContractEventSendOpTemplate) { + return ((ContractEventSendOpTemplate) sendOperation).getOpIndex(); + } + return -1; + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java index 66d79b4a..ad4a1cd5 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java @@ -1,17 +1,19 @@ package com.jd.blockchain.transaction; -import java.lang.annotation.Annotation; import java.lang.reflect.Proxy; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.IllegalDataException; public class ContractInvocationProxyBuilder { private Map, ContractType> contractTypes = new ConcurrentHashMap<>(); + private Map contractOperations = new ConcurrentHashMap<>(); + public T create(String address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); } @@ -22,10 +24,31 @@ public class ContractInvocationProxyBuilder { ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, contractEventBuilder); + T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { contractIntf }, proxyHandler); + // 创建关联关系 + contractOperations.put(proxy, proxyHandler.opIndex()); + return proxy; + } + + public EventResult execute(ContractEventExecutor execute) { + Object contractProxy = execute.execute(); + if (contractProxy == null) { + // 该方法执行必须要有返回值 + throw new IllegalStateException( + String.format("ContractEventExecutor [%s] 's return must be not empty !!!", execute.toString())); + } + if (!(contractProxy instanceof Proxy)) { + throw new IllegalDataException( + String.format("ContractEventExecutor [%s] 's return must from TxTemplate.contract()'s result !!!", execute.toString())); + } - return (T) proxy; + Integer opIndex = contractOperations.get(contractProxy); + if (opIndex != null && opIndex > -1) { + return new EventResult<>(opIndex); + } + return null; } private ContractType resolveContractType(Class contractIntf) { @@ -33,21 +56,8 @@ public class ContractInvocationProxyBuilder { if (contractType != null) { return contractType; } - // TODO 检查返回值类型; - ContractType ct = ContractType.resolve(contractIntf); contractTypes.put(contractIntf, ct); return ct; } - - - /** - * is contractType really? identified by @Contract; - * @param contractIntf - * @return - */ - private boolean isContractType(Class contractIntf) { - Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class); - return annotation != null ? true : false; - } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java index 3e8835aa..a2602a4b 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java @@ -91,6 +91,13 @@ public class ContractType { 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())); + } + contractType.events.put(eventName, method); contractType.handleMethods.put(method, eventName); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java index fd001fb6..de6e1c0e 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java @@ -1,5 +1,6 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.utils.Bytes; public interface EventOperator { @@ -30,4 +31,11 @@ public interface EventOperator { */ T contract(Bytes address, Class contractIntf); + /** + * 执行合约异步等待应答结果 + * + * @param execute + * @return + */ + EventResult result(ContractEventExecutor execute); } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java index 34432aeb..f45706f4 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java @@ -1,6 +1,8 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.binaryproto.BinaryProtocol; +import com.jd.blockchain.contract.ContractSerializeUtils; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; @@ -9,15 +11,24 @@ import com.jd.blockchain.crypto.SignatureDigest; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.*; +import java.util.Map; + public class PreparedTx implements PreparedTransaction { private TransactionRequestBuilder txReqBuilder; private TransactionService txProcessor; + private Map eventResults; + public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor) { + this(txReqBuilder, txProcessor, null); + } + + public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, Map eventResults) { this.txReqBuilder = txReqBuilder; this.txProcessor = txProcessor; + this.eventResults = eventResults; } @Override @@ -53,12 +64,15 @@ public class PreparedTx implements PreparedTransaction { TransactionResponse txResponse = txProcessor.process(txReq); // 重新包装操作集合 OperationResult[] operationResults = txResponse.getOperationResults(); - if (operationResults != null && operationResults.length > 0) { - OperationResult[] wrapOpResults = new OperationResult[operationResults.length]; - for (int i = 0; i < operationResults.length; i++) { - wrapOpResults[i] = new OperationResultData(operationResults[i]); + if (operationResults != null && operationResults.length > 0 && + eventResults != null && !eventResults.isEmpty()) { + for (OperationResult operationResult : operationResults) { + int opIndex = operationResult.getIndex(); + EventResult eventResult = eventResults.get(opIndex); + if (eventResult != null) { + eventResult.done(ContractSerializeUtils.resolve(operationResult.getResult())); + } } - return new TxResponseMessage(txResponse, wrapOpResults); } return txResponse; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java index 12fe552f..87cabb3a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java @@ -2,6 +2,7 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.TransactionBuilder; @@ -10,6 +11,9 @@ import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.ledger.TransactionRequestBuilder; import com.jd.blockchain.utils.Bytes; +import java.util.HashMap; +import java.util.Map; + public class TxBuilder implements TransactionBuilder { static { @@ -18,6 +22,8 @@ public class TxBuilder implements TransactionBuilder { private BlockchainOperationFactory opFactory = new BlockchainOperationFactory(); + private Map contractProxyMap = new HashMap<>(); + private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; private HashDigest ledgerHash; @@ -88,6 +94,11 @@ public class TxBuilder implements TransactionBuilder { return opFactory.contract(address, contractIntf); } + @Override + public EventResult result(ContractEventExecutor execute) { + return opFactory.result(execute); + } + @Override public T contract(String address, Class contractIntf) { return opFactory.contract(address, contractIntf); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java index 984ecf07..908ee7fc 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java @@ -1,20 +1,27 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionRequestBuilder; import com.jd.blockchain.ledger.TransactionTemplate; import com.jd.blockchain.utils.Bytes; +import java.util.HashMap; +import java.util.Map; + public class TxTemplate implements TransactionTemplate { private TxBuilder txBuilder; private TransactionService txService; + private Map eventResults; + public TxTemplate(HashDigest ledgerHash, TransactionService txService) { this.txBuilder = new TxBuilder(ledgerHash); this.txService = txService; + this.eventResults = new HashMap<>(); } @Override @@ -25,7 +32,7 @@ public class TxTemplate implements TransactionTemplate { @Override public PreparedTransaction prepare() { TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); - return new PreparedTx(txReqBuilder, txService); + return new PreparedTx(txReqBuilder, txService, eventResults); } @Override @@ -62,7 +69,16 @@ public class TxTemplate implements TransactionTemplate { public T contract(Bytes address, Class contractIntf) { return txBuilder.contract(address, contractIntf); } - + + @Override + public EventResult result(ContractEventExecutor execute) { + EventResult eventResult = txBuilder.result(execute); + if (eventResult != null) { + eventResults.put(eventResult.opIndex(), eventResult); + } + return eventResult; + } + @Override public T contract(String address, Class contractIntf) { return txBuilder.contract(address, contractIntf); diff --git a/source/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 9e4d16b3..87d886ea 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java @@ -24,8 +24,10 @@ import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicLong; +import com.jd.blockchain.contract.EventResult; import com.jd.blockchain.contract.ReadContract; import com.jd.blockchain.ledger.*; +import com.jd.blockchain.transaction.ContractEventExecutor; import org.apache.commons.io.FileUtils; import org.springframework.core.io.ClassPathResource; @@ -568,13 +570,25 @@ public class IntegrationBase { TransactionTemplate txContract = blockchainService.newTransaction(ledgerHash); ReadContract readContract1 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); - readContract1.read(newDataAccount.getAddress().toBase58(), key1); + + EventResult read1 = txContract.result((ContractEventExecutor) () -> { + readContract1.read(newDataAccount.getAddress().toBase58(), key1); + return readContract1; + }); ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); - readContract2.read(newDataAccount.getAddress().toBase58(), key2); + + EventResult read2 = txContract.result((ContractEventExecutor) () -> { + readContract2.read(newDataAccount.getAddress().toBase58(), key2); + return readContract2; + }); ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); - readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2); + + EventResult read3 = txContract.result((ContractEventExecutor) () -> { + readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2); + return readContract3; + }); // 签名; PreparedTransaction contractPtx = txContract.prepare(); @@ -585,10 +599,16 @@ public class IntegrationBase { OperationResult[] operationResults = readTxResp.getOperationResults(); + // 通过EventResult获取结果 + System.out.printf("readContract1.result = %s \r\n", read1.get()); + System.out.printf("readContract2.result = %s \r\n", read2.get()); + System.out.printf("readContract3.result = %s \r\n", read3.get()); + + // 打印结果 - for (OperationResult or : operationResults) { - System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), or.getResultData()); - } +// for (OperationResult or : operationResults) { +// System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), or.getResult()); +// } // // // 验证结果 // assertNotNull(contractReturn); diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java index 52cc81d3..c01d4a26 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java @@ -2,6 +2,7 @@ package com.jd.blockchain.mocker.proxy; import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.OperationResult; @@ -77,7 +78,7 @@ public class ContractProxy implements InvocationHandler { OperationResult opResult = operationResults[0]; // 处理返回值 - return new OperationResultData(opResult).getResultData(); + return ContractSerializeUtils.resolve(opResult.getResult()); } private boolean isExecuteContractMethod(Method method) {