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