From 91ea158efca743e0d631bfcdc95a62b1827dc9c5 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 8 May 2019 19:37:34 +0800 Subject: [PATCH] Completed the basic processing of invoking contract with it's interface; --- .../contract/jvm/JavaContractCode.java | 78 +++++++++++-------- .../jd/blockchain/ledger/LedgerTestUtils.java | 32 ++++---- .../blockchain/ledger/TransactionSetTest.java | 9 +-- .../BlockchainOperationFactory.java | 1 - .../transaction/ContractInvocationProxy.java | 43 ++++++++-- .../ContractInvocationProxyBuilder.java | 41 +++++++++- .../blockchain/transaction/ContractType.java | 25 +++--- .../blockchain/transaction/EventOperator.java | 19 ++++- .../jd/blockchain/transaction/TxBuilder.java | 11 ++- .../jd/blockchain/transaction/TxTemplate.java | 8 +- .../peer/LedgerBindingConfigAware.java | 2 - .../sdk/samples/SDKDemo_Contract.java | 9 ++- 12 files changed, 186 insertions(+), 92 deletions(-) diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java index 90f68d5a..0d219a65 100644 --- a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java @@ -13,12 +13,14 @@ import com.jd.blockchain.contract.ContractEvent; import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.engine.ContractCode; import com.jd.blockchain.runtime.Module; +import com.jd.blockchain.transaction.ContractType; import com.jd.blockchain.utils.BaseConstant; import com.jd.blockchain.utils.Bytes; /** * contract code based jvm - * @author zhaogw + * + * @author zhaogw */ public class JavaContractCode implements ContractCode { private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); @@ -26,7 +28,9 @@ public class JavaContractCode implements ContractCode { private Bytes address; private long version; private ContractEventContext contractEventContext; - + + private ContractType contractType; + public JavaContractCode(Bytes address, long version, Module codeModule) { this.address = address; this.version = version; @@ -37,7 +41,7 @@ public class JavaContractCode implements ContractCode { public Bytes getAddress() { return address; } - + @Override public long getVersion() { return version; @@ -46,35 +50,45 @@ public class JavaContractCode implements ContractCode { @Override public void processEvent(ContractEventContext eventContext) { this.contractEventContext = eventContext; - codeModule.execute(new ContractThread()); + codeModule.execute(new ContractExecution()); } - class ContractThread implements Runnable{ - public void run(){ + private Object[] resolveArgs(byte[] args) { + // TODO Auto-generated method stub + return null; + } + + class ContractExecution implements Runnable { + public void run() { LOGGER.info("ContractThread execute()."); try { - //执行预处理; + // 执行预处理; long startTime = System.currentTimeMillis(); String contractClassName = codeModule.getMainClass(); Class myClass = codeModule.loadClass(contractClassName); - Object contractMainClassObj = myClass.newInstance();//合约主类生成的类实例; + Object contractMainClassObj = myClass.newInstance();// 合约主类生成的类实例; - Method beforeMth_ = myClass.getMethod("beforeEvent",codeModule.loadClass(ContractEventContext.class.getName())); - ReflectionUtils.invokeMethod(beforeMth_,contractMainClassObj,contractEventContext); - LOGGER.info("beforeEvent,耗时:"+(System.currentTimeMillis()-startTime)); + Method beforeMth_ = myClass.getMethod("beforeEvent", + codeModule.loadClass(ContractEventContext.class.getName())); + ReflectionUtils.invokeMethod(beforeMth_, contractMainClassObj, contractEventContext); + LOGGER.info("beforeEvent,耗时:" + (System.currentTimeMillis() - startTime)); - Method eventMethod = this.getMethodByAnno(contractMainClassObj,contractEventContext.getEvent()); + Method eventMethod = this.getMethodByAnno(contractMainClassObj, contractEventContext.getEvent()); startTime = System.currentTimeMillis(); - ReflectionUtils.invokeMethod(eventMethod,contractMainClassObj,contractEventContext); + // 反序列化参数; + Method handleMethod = contractType.getHandleMethod(contractEventContext.getEvent()); + Object[] args = resolveArgs(contractEventContext.getArgs()); + + ReflectionUtils.invokeMethod(handleMethod, contractMainClassObj, args); - LOGGER.info("合约执行,耗时:"+(System.currentTimeMillis()-startTime)); + LOGGER.info("合约执行,耗时:" + (System.currentTimeMillis() - startTime)); Method mth2 = myClass.getMethod("postEvent"); startTime = System.currentTimeMillis(); - ReflectionUtils.invokeMethod(mth2,contractMainClassObj); - LOGGER.info("postEvent,耗时:"+(System.currentTimeMillis()-startTime)); + ReflectionUtils.invokeMethod(mth2, contractMainClassObj); + LOGGER.info("postEvent,耗时:" + (System.currentTimeMillis() - startTime)); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Exception e) { @@ -82,39 +96,41 @@ public class JavaContractCode implements ContractCode { } } - //得到当前类中相关方法和注解对应关系; - Method getMethodByAnno(Object classObj, String eventName){ + // 得到当前类中相关方法和注解对应关系; + Method getMethodByAnno(Object classObj, String eventName) { Class c = classObj.getClass(); - Class contractEventClass = null; + Class contractEventClass = null; try { - contractEventClass = (Class )c.getClassLoader().loadClass(ContractEvent.class.getName()); + contractEventClass = (Class) c.getClassLoader().loadClass(ContractEvent.class.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } Method[] classMethods = c.getMethods(); Map methodAnnoMap = new HashMap(); - Map annoMethodMap = new HashMap(); - for(int i = 0;i annoMethodMap = new HashMap(); + for (int i = 0; i < classMethods.length; i++) { Annotation[] a = classMethods[i].getDeclaredAnnotations(); methodAnnoMap.put(classMethods[i], a); - //如果当前方法中包含@ContractEvent注解,则将其放入Map; - for(Annotation annotation_ : a){ - //如果是合同事件类型,则放入map; - if(classMethods[i].isAnnotationPresent(contractEventClass)){ + // 如果当前方法中包含@ContractEvent注解,则将其放入Map; + for (Annotation annotation_ : a) { + // 如果是合同事件类型,则放入map; + if (classMethods[i].isAnnotationPresent(contractEventClass)) { Object obj = classMethods[i].getAnnotation(contractEventClass); String annoAllName = obj.toString(); - //format:@com.jd.blockchain.contract.model.ContractEvent(name=transfer-asset) - String eventName_ = obj.toString().substring(BaseConstant.CONTRACT_EVENT_PREFIX.length(),annoAllName.length()-1); - annoMethodMap.put(eventName_,classMethods[i]); + // format:@com.jd.blockchain.contract.model.ContractEvent(name=transfer-asset) + String eventName_ = obj.toString().substring(BaseConstant.CONTRACT_EVENT_PREFIX.length(), + annoAllName.length() - 1); + annoMethodMap.put(eventName_, classMethods[i]); break; } } } - if(annoMethodMap.containsKey(eventName)){ + if (annoMethodMap.containsKey(eventName)) { return annoMethodMap.get(eventName); - }else { + } else { return null; } } } + } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java index d6f6ae43..33dafeec 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java @@ -43,22 +43,22 @@ public class LedgerTestUtils { return txHandle.txRequest; } - public static TransactionRequest createContractEventTxRequest(HashDigest ledgerHash, - SignatureFunction signatureFunction, String contractAddress, String event, byte[] args) { - TxHandle txHandle = new TxHandle(); - - TxTemplate txTemp = new TxTemplate(ledgerHash, txHandle); - - txTemp.contractEvents().send(contractAddress, event, args); - - AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); - PubKey pubKey = cryptoKeyPair.getPubKey(); - txTemp.users().register(new BlockchainIdentityData(pubKey)); - PreparedTransaction ptx = txTemp.prepare(); - ptx.sign(cryptoKeyPair); - ptx.commit(); - return txHandle.txRequest; - } +// public static TransactionRequest createContractEventTxRequest(HashDigest ledgerHash, +// SignatureFunction signatureFunction, String contractAddress, String event, byte[] args) { +// TxHandle txHandle = new TxHandle(); +// +// TxTemplate txTemp = new TxTemplate(ledgerHash, txHandle); +// +// txTemp.contractEvents().send(contractAddress, event, args); +// +// AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); +// PubKey pubKey = cryptoKeyPair.getPubKey(); +// txTemp.users().register(new BlockchainIdentityData(pubKey)); +// PreparedTransaction ptx = txTemp.prepare(); +// ptx.sign(cryptoKeyPair); +// ptx.commit(); +// return txHandle.txRequest; +// } public static TransactionStagedSnapshot generateRandomSnapshot() { TransactionStagedSnapshot txDataSnapshot = new TransactionStagedSnapshot(); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java index 60b48975..41a9d3b5 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java @@ -6,14 +6,12 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import java.security.KeyFactory; import java.util.Random; -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.crypto.HashDigest; - import org.junit.Test; +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.ContractCodeDeployOperation; @@ -25,7 +23,6 @@ import com.jd.blockchain.ledger.DataAccountRegisterOperation; import com.jd.blockchain.ledger.DigitalSignature; import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.Operation; -import com.jd.blockchain.ledger.TransactionBuilder; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionRequestBuilder; import com.jd.blockchain.ledger.TransactionState; @@ -62,7 +59,7 @@ public class TransactionSetTest { // Build transaction request; HashDigest ledgerHash = LedgerTestUtils.generateRandomHash(); - TransactionBuilder txBuilder = new TxBuilder(ledgerHash); + TxBuilder txBuilder = new TxBuilder(ledgerHash); BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); UserRegisterOperation userRegOp = txBuilder.users().register(userKey.getIdentity()); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java index bd1bfd5b..907608ae 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java @@ -74,7 +74,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe return contractCodeDeployOpBuilder; } - @Override public ContractEventSendOperationBuilder contractEvents() { return contractEventSendOpBuilder; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java index c9b97e4d..47b73020 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java @@ -3,19 +3,46 @@ package com.jd.blockchain.transaction; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -public class ContractInvocationProxy implements InvocationHandler { - - - private String contractMessage; - +import com.jd.blockchain.utils.Bytes; + +public class ContractInvocationProxy implements InvocationHandler { + + // private String contractMessage; + + private Bytes contractAddress; + + private ContractType contractType; private ContractEventSendOperationBuilder sendOpBuilder; - - + + public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, + ContractEventSendOperationBuilder sendOpBuilder) { + this.contractAddress = contractAddress; + this.contractType = contractType; + this.sendOpBuilder = sendOpBuilder; + } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // TODO Auto-generated method stub + + String event = contractType.getEvent(method); + if (event == null) { + // 适配 Object 对象的方法; + // toString 方法; + return String.format("[%s]-%s", contractAddress, contractType.toString()); + + // hashCode 方法; + } + // 合约方法; + byte[] argBytes = serializeArgs(args); + sendOpBuilder.send(contractAddress, event, argBytes); + + // TODO: 暂时未考虑有返回值的情况; + return null; + } + + private byte[] serializeArgs(Object[] args) { + // TODO 根据方法参数的定义序列化参数; return null; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java index 2bc6c9ea..df47c6b3 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java @@ -1,6 +1,45 @@ package com.jd.blockchain.transaction; -class ContractInvocationProxyBuilder { +import java.lang.reflect.Proxy; +import java.util.Map; +import com.jd.blockchain.utils.Bytes; + +public class ContractInvocationProxyBuilder { + + private Map, ContractType> contractTypes; + + public T create(String address, Class contractIntf, BlockchainOperationFactory opFactory) { + return create(Bytes.fromBase58(address), contractIntf, opFactory); + } + + @SuppressWarnings("unchecked") + public T create(Bytes address, Class contractIntf, BlockchainOperationFactory opFactory) { + ContractType contractType = resolveContractType(contractIntf); + + ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, + opFactory.contractEvents()); + T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), + new Class[] { contractIntf }, proxyHandler); + + return (T) proxy; + } + + private ContractType resolveContractType(Class contractIntf) { + ContractType contractType = contractTypes.get(contractIntf); + if (contractType != null) { + return contractType; + } + + // 判断是否是标注了合约的接口类型; + + // 解析合约事件处理方法,检查是否有重名; + + // TODO 检查是否不支持的参数类型; + + // TODO 检查返回值类型; + + return null; + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java index 27d75e25..c57db077 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java @@ -4,12 +4,12 @@ import java.lang.reflect.Method; import java.util.Set; import java.util.SortedMap; -class ContractType { - +public class ContractType { + private String name; - + private SortedMap events; - + private SortedMap handleMethods; /** @@ -17,7 +17,7 @@ class ContractType { * * @return */ - Set getEvents() { + public Set getEvents() { return events.keySet(); } @@ -29,7 +29,7 @@ class ContractType { * @param method * @return */ - String getEvent(Method method) { + public String getEvent(Method method) { return handleMethods.get(method); } @@ -41,16 +41,15 @@ class ContractType { * @param event * @return */ - Method getHandleMethod(String event) { + public Method getHandleMethod(String event) { return events.get(event); } - + private ContractType() { } - - -// public static ContractType resolve(Class contractIntf) { -// -// } + + // public static ContractType resolve(Class contractIntf) { + // + // } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java index 687c204d..fd001fb6 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java @@ -1,14 +1,25 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.utils.Bytes; + public interface EventOperator { + // /** + // * 合约事件; + // * + // * @return + // */ + // @Deprecated + // ContractEventSendOperationBuilder contractEvents(); + /** - * 部署合约; + * 创建调用合约的代理实例; * + * @param address + * @param contractIntf * @return */ - @Deprecated - ContractEventSendOperationBuilder contractEvents(); + T contract(String address, Class contractIntf); /** * 创建调用合约的代理实例; @@ -17,6 +28,6 @@ public interface EventOperator { * @param contractIntf * @return */ - T contract(String address, Class contractIntf); + T contract(Bytes address, Class contractIntf); } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java index 1f315482..9e9afe13 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java @@ -21,6 +21,8 @@ public class TxBuilder implements TransactionBuilder { private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; private HashDigest ledgerHash; + + private ContractInvocationProxyBuilder contractInvoProxyBuilder; public TxBuilder(HashDigest ledgerHash) { this.ledgerHash = ledgerHash; @@ -79,15 +81,18 @@ public class TxBuilder implements TransactionBuilder { return opFactory.contracts(); } - @Override public ContractEventSendOperationBuilder contractEvents() { return opFactory.contractEvents(); } + @Override + public T contract(Bytes address, Class contractIntf) { + return contractInvoProxyBuilder.create(address, contractIntf, opFactory); + } + @Override public T contract(String address, Class contractIntf) { - // TODO Auto-generated method stub - throw new IllegalStateException("Not implemented."); + return contractInvoProxyBuilder.create(address, contractIntf, opFactory); } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java index f19906db..d329b015 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java @@ -53,10 +53,10 @@ public class TxTemplate implements TransactionTemplate { return txBuilder.contracts(); } - @Override - public ContractEventSendOperationBuilder contractEvents() { - return txBuilder.contractEvents(); - } +// @Override +// public ContractEventSendOperationBuilder contractEvents() { +// return txBuilder.contractEvents(); +// } @Override public T contract(String address, Class contractIntf) { diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/LedgerBindingConfigAware.java b/source/peer/src/main/java/com/jd/blockchain/peer/LedgerBindingConfigAware.java index c0bb263b..e8b244c6 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/LedgerBindingConfigAware.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/LedgerBindingConfigAware.java @@ -4,8 +4,6 @@ import com.jd.blockchain.consensus.service.NodeServer; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.tools.initializer.LedgerBindingConfig; -import java.util.List; - public interface LedgerBindingConfigAware { void setConfig(LedgerBindingConfig config); diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java index f88e1cf9..6811fd2f 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java @@ -68,9 +68,12 @@ public class SDKDemo_Contract { Remark remark = new Remark(); String remarkJSON = JSONSerializeUtils.serializeToJSON(remark); -// AssetContract assetContract = txTemp.contract("", AssetContract.class); -// txTemp.contractInvocation(assetContract.issue(amount, assetHolderAddress)) - + AssetContract assetContract = txTemp.contract(profitDistributionContract, AssetContract.class); + assetContract.issue(1000, receiptorAccount1); + assetContract.transfer(receiptorAccount1, receiptorAccount2, 600); + +// assetContract. + // -------------------------------------- // TX 准备就绪;