| @@ -9,5 +9,7 @@ public interface ReadContract { | |||||
| @ContractEvent(name = "version-key") | @ContractEvent(name = "version-key") | ||||
| Long readVersion(String address, String key); | Long readVersion(String address, String key); | ||||
| int test(); | |||||
| } | } | ||||
| @@ -42,4 +42,9 @@ public class ReadContractImpl implements EventProcessingAwire, ReadContract { | |||||
| } | } | ||||
| return -1L; | return -1L; | ||||
| } | } | ||||
| @Override | |||||
| public int test() { | |||||
| return 0; | |||||
| } | |||||
| } | } | ||||
| @@ -1,7 +1,6 @@ | |||||
| package com.jd.blockchain.contract; | 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.contract.param.*; | ||||
| import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
| @@ -19,9 +18,18 @@ public class ContractSerializeUtils { | |||||
| static { | static { | ||||
| MAP.put(byte[].class, WRAP_BYTES.class); | MAP.put(byte[].class, WRAP_BYTES.class); | ||||
| MAP.put(Short.class, WRAP_SHORT.class); | MAP.put(Short.class, WRAP_SHORT.class); | ||||
| MAP.put(short.class, WRAP_SHORT.class); | |||||
| MAP.put(Integer.class, WRAP_INT.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(long.class, WRAP_LONG.class); | |||||
| MAP.put(String.class, WRAP_STRING.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) { | 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) | @DataField(order = 5, primitiveType = PrimitiveType.INT64) | ||||
| long getTxOpTime(); | long getTxOpTime(); | ||||
| } | } | ||||
| @@ -13,6 +13,4 @@ public interface OperationResult { | |||||
| @DataField(order=2, primitiveType = PrimitiveType.BYTES) | @DataField(order=2, primitiveType = PrimitiveType.BYTES) | ||||
| byte[] getResult(); | byte[] getResult(); | ||||
| <T> T getResultData(); | |||||
| } | } | ||||
| @@ -1,6 +1,5 @@ | |||||
| package com.jd.blockchain.ledger; | package com.jd.blockchain.ledger; | ||||
| import com.jd.blockchain.contract.ContractSerializeUtils; | |||||
| public class OperationResultData implements OperationResult { | public class OperationResultData implements OperationResult { | ||||
| @@ -11,10 +10,6 @@ public class OperationResultData implements OperationResult { | |||||
| public OperationResultData() { | public OperationResultData() { | ||||
| } | } | ||||
| public OperationResultData(OperationResult operationResult) { | |||||
| this(operationResult.getIndex(), operationResult.getResult()); | |||||
| } | |||||
| public OperationResultData(int index, byte[] result) { | public OperationResultData(int index, byte[] result) { | ||||
| this.index = index; | this.index = index; | ||||
| this.result = result; | this.result = result; | ||||
| @@ -30,11 +25,6 @@ public class OperationResultData implements OperationResult { | |||||
| return result; | return result; | ||||
| } | } | ||||
| @Override | |||||
| public <T> T getResultData() { | |||||
| return (T) ContractSerializeUtils.resolve(result); | |||||
| } | |||||
| public void setIndex(int index) { | public void setIndex(int index) { | ||||
| this.index = index; | this.index = index; | ||||
| } | } | ||||
| @@ -4,6 +4,7 @@ import java.util.ArrayList; | |||||
| import java.util.Collection; | import java.util.Collection; | ||||
| import java.util.List; | import java.util.List; | ||||
| import com.jd.blockchain.contract.EventResult; | |||||
| import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
| import com.jd.blockchain.ledger.ContractCodeDeployOperation; | import com.jd.blockchain.ledger.ContractCodeDeployOperation; | ||||
| import com.jd.blockchain.ledger.ContractEventSendOperation; | 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 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(); | private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter(); | ||||
| @@ -89,6 +90,11 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||||
| return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); | return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); | ||||
| } | } | ||||
| @Override | |||||
| public <T> EventResult<T> result(ContractEventExecutor execute) { | |||||
| return contractInvoProxyBuilder.execute(execute); | |||||
| } | |||||
| public Collection<Operation> getOperations() { | public Collection<Operation> getOperations() { | ||||
| // TODO: 合并操作列表中可能的重复操作; | // TODO: 合并操作列表中可能的重复操作; | ||||
| return operationList; | return operationList; | ||||
| @@ -130,7 +136,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||||
| operationList.add(op); | operationList.add(op); | ||||
| return op; | return op; | ||||
| } | } | ||||
| } | } | ||||
| private class DataAccountKVSetOperationBuilderFilter implements DataAccountKVSetOperationBuilder { | private class DataAccountKVSetOperationBuilderFilter implements DataAccountKVSetOperationBuilder { | ||||
| @@ -235,25 +240,35 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe | |||||
| operationList.add(op); | operationList.add(op); | ||||
| return op; | return op; | ||||
| } | } | ||||
| } | } | ||||
| private class ContractEventSendOperationBuilderFilter implements ContractEventSendOperationBuilder { | private class ContractEventSendOperationBuilderFilter implements ContractEventSendOperationBuilder { | ||||
| @Override | @Override | ||||
| public ContractEventSendOperation send(String address, String event, byte[] args) { | 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 | @Override | ||||
| public ContractEventSendOperation send(Bytes address, String event, byte[] args) { | 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); | operationList.add(op); | ||||
| return 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; | import com.jd.blockchain.utils.Bytes; | ||||
| public class ContractEventSendOpTemplate implements ContractEventSendOperation { | public class ContractEventSendOpTemplate implements ContractEventSendOperation { | ||||
| static { | static { | ||||
| DataContractRegistry.register(ContractEventSendOperation.class); | DataContractRegistry.register(ContractEventSendOperation.class); | ||||
| } | } | ||||
| @@ -14,17 +15,47 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { | |||||
| private String event; | private String event; | ||||
| //交易操作时间; | //交易操作时间; | ||||
| private long txOpTime; | private long txOpTime; | ||||
| // 所属操作Index | |||||
| private int opIndex; | |||||
| public ContractEventSendOpTemplate() { | 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) { | 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.contractAddress = contractAddress; | ||||
| this.event = event; | this.event = event; | ||||
| this.args = args; | this.args = args; | ||||
| this.opIndex = opIndex; | |||||
| this.txOpTime = System.currentTimeMillis(); | 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 | @Override | ||||
| public Bytes getContractAddress() { | public Bytes getContractAddress() { | ||||
| return contractAddress; | return contractAddress; | ||||
| @@ -44,4 +75,13 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { | |||||
| public long getTxOpTime() { | public long getTxOpTime() { | ||||
| return txOpTime; | return txOpTime; | ||||
| } | } | ||||
| /** | |||||
| * 获取所属交易中的序号,该值不需要序列化 | |||||
| * | |||||
| * @return | |||||
| */ | |||||
| public int getOpIndex() { | |||||
| return opIndex; | |||||
| } | |||||
| } | } | ||||
| @@ -23,4 +23,17 @@ public interface ContractEventSendOperationBuilder { | |||||
| @Deprecated | @Deprecated | ||||
| ContractEventSendOperation send(Bytes address, String event, byte[] args); | 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 java.lang.reflect.Method; | ||||
| import com.jd.blockchain.contract.ContractSerializeUtils; | import com.jd.blockchain.contract.ContractSerializeUtils; | ||||
| import com.jd.blockchain.ledger.ContractEventSendOperation; | |||||
| import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
| import com.jd.blockchain.utils.IllegalDataException; | import com.jd.blockchain.utils.IllegalDataException; | ||||
| @@ -11,41 +12,66 @@ public class ContractInvocationProxy implements InvocationHandler { | |||||
| // private String contractMessage; | // private String contractMessage; | ||||
| private Bytes contractAddress; | |||||
| // private Bytes contractAddress; | |||||
| private ContractType contractType; | private ContractType contractType; | ||||
| private ContractEventSendOperationBuilder sendOpBuilder; | |||||
| // private ContractEventSendOperationBuilder sendOpBuilder; | |||||
| private ContractEventSendOperation sendOperation; | |||||
| public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, | public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, | ||||
| ContractEventSendOperationBuilder sendOpBuilder) { | ContractEventSendOperationBuilder sendOpBuilder) { | ||||
| this.contractAddress = contractAddress; | |||||
| // this.contractAddress = contractAddress; | |||||
| if(contractType == null){ | if(contractType == null){ | ||||
| throw new IllegalDataException("contractType == null, no invoke really."); | throw new IllegalDataException("contractType == null, no invoke really."); | ||||
| } | } | ||||
| this.contractType = contractType; | this.contractType = contractType; | ||||
| this.sendOpBuilder = sendOpBuilder; | |||||
| // this.sendOpBuilder = sendOpBuilder; | |||||
| // Send一个地址,但不涉及Event | |||||
| this.sendOperation = sendOpBuilder.send(contractAddress); | |||||
| } | } | ||||
| @Override | @Override | ||||
| public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | 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); | String event = contractType.getEvent(method); | ||||
| if (event == null) { | 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); | byte[] argBytes = serializeArgs(args); | ||||
| sendOpBuilder.send(contractAddress, event, argBytes); | |||||
| // TODO: 暂时未考虑有返回值的情况; | |||||
| if (sendOperation instanceof ContractEventSendOpTemplate) { | |||||
| ((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes); | |||||
| } | |||||
| // 代理操作,返回值类型无法创建 | |||||
| return null; | return null; | ||||
| } | } | ||||
| private byte[] serializeArgs(Object[] args) { | private byte[] serializeArgs(Object[] args) { | ||||
| return ContractSerializeUtils.serializeArray(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; | package com.jd.blockchain.transaction; | ||||
| import java.lang.annotation.Annotation; | |||||
| import java.lang.reflect.Proxy; | import java.lang.reflect.Proxy; | ||||
| import java.util.Map; | import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | 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.Bytes; | ||||
| import com.jd.blockchain.utils.IllegalDataException; | |||||
| public class ContractInvocationProxyBuilder { | public class ContractInvocationProxyBuilder { | ||||
| private Map<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>(); | 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) { | public <T> T create(String address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { | ||||
| return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); | return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); | ||||
| } | } | ||||
| @@ -22,10 +24,31 @@ public class ContractInvocationProxyBuilder { | |||||
| ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, | ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, | ||||
| contractEventBuilder); | contractEventBuilder); | ||||
| T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), | T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), | ||||
| new Class<?>[] { contractIntf }, proxyHandler); | 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) { | private ContractType resolveContractType(Class<?> contractIntf) { | ||||
| @@ -33,21 +56,8 @@ public class ContractInvocationProxyBuilder { | |||||
| if (contractType != null) { | if (contractType != null) { | ||||
| return contractType; | return contractType; | ||||
| } | } | ||||
| // TODO 检查返回值类型; | |||||
| ContractType ct = ContractType.resolve(contractIntf); | ContractType ct = ContractType.resolve(contractIntf); | ||||
| contractTypes.put(contractIntf, ct); | contractTypes.put(contractIntf, ct); | ||||
| return 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())); | 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.events.put(eventName, method); | ||||
| contractType.handleMethods.put(method, eventName); | contractType.handleMethods.put(method, eventName); | ||||
| } | } | ||||
| @@ -1,5 +1,6 @@ | |||||
| package com.jd.blockchain.transaction; | package com.jd.blockchain.transaction; | ||||
| import com.jd.blockchain.contract.EventResult; | |||||
| import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
| public interface EventOperator { | public interface EventOperator { | ||||
| @@ -30,4 +31,11 @@ public interface EventOperator { | |||||
| */ | */ | ||||
| <T> T contract(Bytes address, Class<T> contractIntf); | <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; | package com.jd.blockchain.transaction; | ||||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | 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.AsymmetricKeypair; | ||||
| import com.jd.blockchain.crypto.Crypto; | import com.jd.blockchain.crypto.Crypto; | ||||
| import com.jd.blockchain.crypto.HashDigest; | 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.crypto.SignatureFunction; | ||||
| import com.jd.blockchain.ledger.*; | import com.jd.blockchain.ledger.*; | ||||
| import java.util.Map; | |||||
| public class PreparedTx implements PreparedTransaction { | public class PreparedTx implements PreparedTransaction { | ||||
| private TransactionRequestBuilder txReqBuilder; | private TransactionRequestBuilder txReqBuilder; | ||||
| private TransactionService txProcessor; | private TransactionService txProcessor; | ||||
| private Map<Integer, EventResult> eventResults; | |||||
| public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor) { | public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor) { | ||||
| this(txReqBuilder, txProcessor, null); | |||||
| } | |||||
| public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, Map<Integer, EventResult> eventResults) { | |||||
| this.txReqBuilder = txReqBuilder; | this.txReqBuilder = txReqBuilder; | ||||
| this.txProcessor = txProcessor; | this.txProcessor = txProcessor; | ||||
| this.eventResults = eventResults; | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -53,12 +64,15 @@ public class PreparedTx implements PreparedTransaction { | |||||
| TransactionResponse txResponse = txProcessor.process(txReq); | TransactionResponse txResponse = txProcessor.process(txReq); | ||||
| // 重新包装操作集合 | // 重新包装操作集合 | ||||
| OperationResult[] operationResults = txResponse.getOperationResults(); | 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; | return txResponse; | ||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package com.jd.blockchain.transaction; | |||||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | import com.jd.blockchain.binaryproto.BinaryProtocol; | ||||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | import com.jd.blockchain.binaryproto.DataContractRegistry; | ||||
| import com.jd.blockchain.contract.EventResult; | |||||
| import com.jd.blockchain.crypto.Crypto; | import com.jd.blockchain.crypto.Crypto; | ||||
| import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
| import com.jd.blockchain.ledger.TransactionBuilder; | 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.ledger.TransactionRequestBuilder; | ||||
| import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| public class TxBuilder implements TransactionBuilder { | public class TxBuilder implements TransactionBuilder { | ||||
| static { | static { | ||||
| @@ -18,6 +22,8 @@ public class TxBuilder implements TransactionBuilder { | |||||
| private BlockchainOperationFactory opFactory = new BlockchainOperationFactory(); | private BlockchainOperationFactory opFactory = new BlockchainOperationFactory(); | ||||
| private Map<Object, Integer> contractProxyMap = new HashMap<>(); | |||||
| private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; | private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; | ||||
| private HashDigest ledgerHash; | private HashDigest ledgerHash; | ||||
| @@ -88,6 +94,11 @@ public class TxBuilder implements TransactionBuilder { | |||||
| return opFactory.contract(address, contractIntf); | return opFactory.contract(address, contractIntf); | ||||
| } | } | ||||
| @Override | |||||
| public <T> EventResult<T> result(ContractEventExecutor execute) { | |||||
| return opFactory.result(execute); | |||||
| } | |||||
| @Override | @Override | ||||
| public <T> T contract(String address, Class<T> contractIntf) { | public <T> T contract(String address, Class<T> contractIntf) { | ||||
| return opFactory.contract(address, contractIntf); | return opFactory.contract(address, contractIntf); | ||||
| @@ -1,20 +1,27 @@ | |||||
| package com.jd.blockchain.transaction; | package com.jd.blockchain.transaction; | ||||
| import com.jd.blockchain.contract.EventResult; | |||||
| import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
| import com.jd.blockchain.ledger.PreparedTransaction; | import com.jd.blockchain.ledger.PreparedTransaction; | ||||
| import com.jd.blockchain.ledger.TransactionRequestBuilder; | import com.jd.blockchain.ledger.TransactionRequestBuilder; | ||||
| import com.jd.blockchain.ledger.TransactionTemplate; | import com.jd.blockchain.ledger.TransactionTemplate; | ||||
| import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| public class TxTemplate implements TransactionTemplate { | public class TxTemplate implements TransactionTemplate { | ||||
| private TxBuilder txBuilder; | private TxBuilder txBuilder; | ||||
| private TransactionService txService; | private TransactionService txService; | ||||
| private Map<Integer, EventResult> eventResults; | |||||
| public TxTemplate(HashDigest ledgerHash, TransactionService txService) { | public TxTemplate(HashDigest ledgerHash, TransactionService txService) { | ||||
| this.txBuilder = new TxBuilder(ledgerHash); | this.txBuilder = new TxBuilder(ledgerHash); | ||||
| this.txService = txService; | this.txService = txService; | ||||
| this.eventResults = new HashMap<>(); | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -25,7 +32,7 @@ public class TxTemplate implements TransactionTemplate { | |||||
| @Override | @Override | ||||
| public PreparedTransaction prepare() { | public PreparedTransaction prepare() { | ||||
| TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | ||||
| return new PreparedTx(txReqBuilder, txService); | |||||
| return new PreparedTx(txReqBuilder, txService, eventResults); | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -62,7 +69,16 @@ public class TxTemplate implements TransactionTemplate { | |||||
| public <T> T contract(Bytes address, Class<T> contractIntf) { | public <T> T contract(Bytes address, Class<T> contractIntf) { | ||||
| return txBuilder.contract(address, 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 | @Override | ||||
| public <T> T contract(String address, Class<T> contractIntf) { | public <T> T contract(String address, Class<T> contractIntf) { | ||||
| return txBuilder.contract(address, contractIntf); | return txBuilder.contract(address, contractIntf); | ||||
| @@ -24,8 +24,10 @@ import java.util.Random; | |||||
| import java.util.concurrent.CountDownLatch; | import java.util.concurrent.CountDownLatch; | ||||
| import java.util.concurrent.atomic.AtomicLong; | import java.util.concurrent.atomic.AtomicLong; | ||||
| import com.jd.blockchain.contract.EventResult; | |||||
| import com.jd.blockchain.contract.ReadContract; | import com.jd.blockchain.contract.ReadContract; | ||||
| import com.jd.blockchain.ledger.*; | import com.jd.blockchain.ledger.*; | ||||
| import com.jd.blockchain.transaction.ContractEventExecutor; | |||||
| import org.apache.commons.io.FileUtils; | import org.apache.commons.io.FileUtils; | ||||
| import org.springframework.core.io.ClassPathResource; | import org.springframework.core.io.ClassPathResource; | ||||
| @@ -568,13 +570,25 @@ public class IntegrationBase { | |||||
| TransactionTemplate txContract = blockchainService.newTransaction(ledgerHash); | TransactionTemplate txContract = blockchainService.newTransaction(ledgerHash); | ||||
| ReadContract readContract1 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | 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); | 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); | 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(); | PreparedTransaction contractPtx = txContract.prepare(); | ||||
| @@ -585,10 +599,16 @@ public class IntegrationBase { | |||||
| OperationResult[] operationResults = readTxResp.getOperationResults(); | 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); | // assertNotNull(contractReturn); | ||||
| @@ -2,6 +2,7 @@ package com.jd.blockchain.mocker.proxy; | |||||
| import com.jd.blockchain.contract.Contract; | import com.jd.blockchain.contract.Contract; | ||||
| import com.jd.blockchain.contract.ContractEvent; | import com.jd.blockchain.contract.ContractEvent; | ||||
| import com.jd.blockchain.contract.ContractSerializeUtils; | |||||
| import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
| import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
| import com.jd.blockchain.ledger.OperationResult; | import com.jd.blockchain.ledger.OperationResult; | ||||
| @@ -77,7 +78,7 @@ public class ContractProxy<T> implements InvocationHandler { | |||||
| OperationResult opResult = operationResults[0]; | OperationResult opResult = operationResults[0]; | ||||
| // 处理返回值 | // 处理返回值 | ||||
| return new OperationResultData(opResult).getResultData(); | |||||
| return ContractSerializeUtils.resolve(opResult.getResult()); | |||||
| } | } | ||||
| private boolean isExecuteContractMethod(Method method) { | private boolean isExecuteContractMethod(Method method) { | ||||