| @@ -9,5 +9,7 @@ public interface ReadContract { | |||
| @ContractEvent(name = "version-key") | |||
| Long readVersion(String address, String key); | |||
| int test(); | |||
| } | |||
| @@ -42,4 +42,9 @@ public class ReadContractImpl implements EventProcessingAwire, ReadContract { | |||
| } | |||
| return -1L; | |||
| } | |||
| @Override | |||
| public int test() { | |||
| return 0; | |||
| } | |||
| } | |||
| @@ -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) { | |||
| @@ -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<T> { | |||
| private static final long MAX_SECONDS = 30; | |||
| private CompletableFuture<T> 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()); | |||
| } | |||
| } | |||
| } | |||
| @@ -44,5 +44,4 @@ public interface ContractEventSendOperation extends Operation { | |||
| */ | |||
| @DataField(order = 5, primitiveType = PrimitiveType.INT64) | |||
| long getTxOpTime(); | |||
| } | |||
| @@ -13,6 +13,4 @@ public interface OperationResult { | |||
| @DataField(order=2, primitiveType = PrimitiveType.BYTES) | |||
| byte[] getResult(); | |||
| <T> T getResultData(); | |||
| } | |||
| @@ -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> T getResultData() { | |||
| return (T) ContractSerializeUtils.resolve(result); | |||
| } | |||
| public void setIndex(int index) { | |||
| this.index = index; | |||
| } | |||
| @@ -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 <T> EventResult<T> result(ContractEventExecutor execute) { | |||
| return contractInvoProxyBuilder.execute(execute); | |||
| } | |||
| public Collection<Operation> 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; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| package com.jd.blockchain.transaction; | |||
| public interface ContractEventExecutor<T> { | |||
| T execute(); | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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; | |||
| // } | |||
| // | |||
| //} | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>(); | |||
| private Map<Object, Integer> contractOperations = new ConcurrentHashMap<>(); | |||
| public <T> T create(String address, Class<T> 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 <T> EventResult<T> 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; | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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> T contract(Bytes address, Class<T> contractIntf); | |||
| /** | |||
| * 执行合约异步等待应答结果 | |||
| * | |||
| * @param execute | |||
| * @return | |||
| */ | |||
| <T> EventResult<T> result(ContractEventExecutor execute); | |||
| } | |||
| @@ -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<Integer, EventResult> eventResults; | |||
| public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor) { | |||
| this(txReqBuilder, txProcessor, null); | |||
| } | |||
| public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, Map<Integer, EventResult> 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; | |||
| } | |||
| @@ -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<Object, Integer> 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 <T> EventResult<T> result(ContractEventExecutor execute) { | |||
| return opFactory.result(execute); | |||
| } | |||
| @Override | |||
| public <T> T contract(String address, Class<T> contractIntf) { | |||
| return opFactory.contract(address, contractIntf); | |||
| @@ -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<Integer, EventResult> 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> T contract(Bytes address, Class<T> contractIntf) { | |||
| return txBuilder.contract(address, contractIntf); | |||
| } | |||
| @Override | |||
| public <T> EventResult<T> result(ContractEventExecutor execute) { | |||
| EventResult<T> eventResult = txBuilder.result(execute); | |||
| if (eventResult != null) { | |||
| eventResults.put(eventResult.opIndex(), eventResult); | |||
| } | |||
| return eventResult; | |||
| } | |||
| @Override | |||
| public <T> T contract(String address, Class<T> contractIntf) { | |||
| return txBuilder.contract(address, contractIntf); | |||
| @@ -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<String> read1 = txContract.result((ContractEventExecutor<ReadContract>) () -> { | |||
| readContract1.read(newDataAccount.getAddress().toBase58(), key1); | |||
| return readContract1; | |||
| }); | |||
| ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | |||
| readContract2.read(newDataAccount.getAddress().toBase58(), key2); | |||
| EventResult<String> read2 = txContract.result((ContractEventExecutor<ReadContract>) () -> { | |||
| readContract2.read(newDataAccount.getAddress().toBase58(), key2); | |||
| return readContract2; | |||
| }); | |||
| ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | |||
| readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2); | |||
| EventResult<Long> read3 = txContract.result((ContractEventExecutor<ReadContract>) () -> { | |||
| 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); | |||
| @@ -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<T> implements InvocationHandler { | |||
| OperationResult opResult = operationResults[0]; | |||
| // 处理返回值 | |||
| return new OperationResultData(opResult).getResultData(); | |||
| return ContractSerializeUtils.resolve(opResult.getResult()); | |||
| } | |||
| private boolean isExecuteContractMethod(Method method) { | |||