@@ -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) { | ||||