From 91ea158efca743e0d631bfcdc95a62b1827dc9c5 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 8 May 2019 19:37:34 +0800 Subject: [PATCH 01/17] 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 准备就绪; From c3d011f7f87657432e907c0d249fa517f8934619 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 8 May 2019 19:54:17 +0800 Subject: [PATCH 02/17] Fixed compiling error of ledger-model; --- .../BlockchainOperationFactory.java | 16 +- .../ContractInvocationProxyBuilder.java | 8 +- .../jd/blockchain/transaction/TxBuilder.java | 20 +-- .../jd/blockchain/transaction/TxTemplate.java | 5 + .../jd/blockchain/intgr/IntegrationTest.java | 162 +++++++++--------- 5 files changed, 111 insertions(+), 100 deletions(-) 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 907608ae..c8769428 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 @@ -31,7 +31,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); - private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter(); private UserRegisterOperationBuilder userRegOpBuilder = new UserRegisterOperationBuilderFilter(); @@ -42,6 +41,8 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe private ContractEventSendOperationBuilder contractEventSendOpBuilder = new ContractEventSendOperationBuilderFilter(); + private ContractInvocationProxyBuilder contractInvoProxyBuilder = new ContractInvocationProxyBuilder(); + private List operationList = new ArrayList<>(); @Override @@ -77,11 +78,15 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe public ContractEventSendOperationBuilder contractEvents() { return contractEventSendOpBuilder; } - + @Override public T contract(String address, Class contractIntf) { - // TODO Auto-generated method stub - return null; + return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); + } + + @Override + public T contract(Bytes address, Class contractIntf) { + return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); } public Collection getOperations() { @@ -152,6 +157,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe } return this; } + @Override public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) { innerBuilder.set(key, value, expVersion); @@ -161,6 +167,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe } return this; } + @Override public DataAccountKVSetOperationBuilder set(String key, long value, long expVersion) { innerBuilder.set(key, value, expVersion); @@ -170,6 +177,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe } return this; } + @Override public DataAccountKVSetOperationBuilder set(String key, Bytes value, long expVersion) { innerBuilder.set(key, value, expVersion); 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 df47c6b3..195ed348 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 @@ -9,16 +9,16 @@ public class ContractInvocationProxyBuilder { private Map, ContractType> contractTypes; - public T create(String address, Class contractIntf, BlockchainOperationFactory opFactory) { - return create(Bytes.fromBase58(address), contractIntf, opFactory); + public T create(String address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { + return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); } @SuppressWarnings("unchecked") - public T create(Bytes address, Class contractIntf, BlockchainOperationFactory opFactory) { + public T create(Bytes address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { ContractType contractType = resolveContractType(contractIntf); ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, - opFactory.contractEvents()); + contractEventBuilder); T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { contractIntf }, proxyHandler); 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 9e9afe13..904f3adc 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 @@ -19,10 +19,8 @@ public class TxBuilder implements TransactionBuilder { private BlockchainOperationFactory opFactory = new BlockchainOperationFactory(); private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; - + private HashDigest ledgerHash; - - private ContractInvocationProxyBuilder contractInvoProxyBuilder; public TxBuilder(HashDigest ledgerHash) { this.ledgerHash = ledgerHash; @@ -38,16 +36,16 @@ public class TxBuilder implements TransactionBuilder { TransactionContent txContent = prepareContent(); return new TxRequestBuilder(txContent); } - + @Override public TransactionContent prepareContent() { TxContentBlob txContent = new TxContentBlob(ledgerHash); txContent.addOperations(opFactory.getOperations()); - + byte[] contentBodyBytes = BinaryProtocol.encode(txContent, TransactionContentBody.class); HashDigest contentHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(contentBodyBytes); txContent.setHash(contentHash); - + return txContent; } @@ -55,7 +53,7 @@ public class TxBuilder implements TransactionBuilder { public LedgerInitOperationBuilder ledgers() { return opFactory.ledgers(); } - + @Override public UserRegisterOperationBuilder users() { return opFactory.users(); @@ -65,7 +63,7 @@ public class TxBuilder implements TransactionBuilder { public DataAccountRegisterOperationBuilder dataAccounts() { return opFactory.dataAccounts(); } - + @Override public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { return opFactory.dataAccount(accountAddress); @@ -84,15 +82,15 @@ public class TxBuilder implements TransactionBuilder { public ContractEventSendOperationBuilder contractEvents() { return opFactory.contractEvents(); } - + @Override public T contract(Bytes address, Class contractIntf) { - return contractInvoProxyBuilder.create(address, contractIntf, opFactory); + return opFactory.contract(address, contractIntf); } @Override public T contract(String address, Class contractIntf) { - return contractInvoProxyBuilder.create(address, contractIntf, opFactory); + return opFactory.contract(address, contractIntf); } } 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 d329b015..984ecf07 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 @@ -58,6 +58,11 @@ public class TxTemplate implements TransactionTemplate { // return txBuilder.contractEvents(); // } + @Override + public T contract(Bytes address, Class contractIntf) { + return txBuilder.contract(address, contractIntf); + } + @Override public T contract(String address, Class contractIntf) { return txBuilder.contract(address, contractIntf); diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java index fb64faec..e4b7843c 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java @@ -547,87 +547,87 @@ public class IntegrationTest { } } - private LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash, - BlockchainService blockchainService, IntegratedContext context) { - // valid the basic data in contract; - prepareContractData(adminKey, ledgerHash, blockchainService, context); - - BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); - - // 定义交易; - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - byte[] contractCode = getChainCodeBytes(); - - txTpl.users().register(userKey.getIdentity()); - - txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); - - // 签名; - PreparedTransaction ptx = txTpl.prepare(); - ptx.sign(adminKey); - - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); - - // 验证结果; - txResp.getContentHash(); - - Node node0 = context.getNode(0); - LedgerRepository ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash); - LedgerBlock block = ledgerOfNode0.getBlock(txResp.getBlockHeight()); - byte[] contractCodeInDb = ledgerOfNode0.getContractAccountSet(block).getContract(contractDeployKey.getAddress()) - .getChainCode(); - txContentHash = ptx.getHash(); - - // execute the contract; - testContractExe(adminKey, ledgerHash, userKey, blockchainService, context); - - return block; - } - - private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, - BlockchainService blockchainService, IntegratedContext context) { - LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); - LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); - - // 定义交易; - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - - txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName, - ("888##abc##" + contractDataKey.getAddress() + "##" + previousBlock.getHash().toBase58() + "##" - + userKey.getAddress() + "##" + contractDeployKey.getAddress() + "##" + txContentHash.toBase58() - + "##SOME-VALUE").getBytes()); - - // 签名; - PreparedTransaction ptx = txTpl.prepare(); - ptx.sign(adminKey); - - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); - - // 验证结果; - txResp.getContentHash(); - - LedgerInfo latestLedgerInfo = blockchainService.getLedger(ledgerHash); - - Node node0 = context.getNode(0); - LedgerRepository ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash); - LedgerBlock backgroundLedgerBlock = ledgerOfNode0.retrieveLatestBlock(); - - // 验证合约中的赋值,外部可以获得; - DataAccountSet dataAccountSet = ledgerOfNode0.getDataAccountSet(backgroundLedgerBlock); - AsymmetricKeypair key = Crypto.getSignatureFunction("ED25519").generateKeypair(); - PubKey pubKey = key.getPubKey(); - Bytes dataAddress = AddressEncoding.generateAddress(pubKey); - - // 验证userAccount,从合约内部赋值,然后外部验证;由于目前不允许输入重复的key,所以在内部合约中构建的key,不便于在外展示,屏蔽之; - // UserAccountSet userAccountSet = - // ledgerOfNode0.getUserAccountSet(backgroundLedgerBlock); - // PubKey userPubKey = new PubKey(CryptoAlgorithm.ED25519, - // userPubKeyVal.getBytes()); - // String userAddress = AddressEncoding.generateAddress(userPubKey); - // assertEquals(userAddress, userAccountSet.getUser(userAddress).getAddress()); - } +// private LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash, +// BlockchainService blockchainService, IntegratedContext context) { +// // valid the basic data in contract; +// prepareContractData(adminKey, ledgerHash, blockchainService, context); +// +// BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); +// +// // 定义交易; +// TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); +// byte[] contractCode = getChainCodeBytes(); +// +// txTpl.users().register(userKey.getIdentity()); +// +// txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); +// +// // 签名; +// PreparedTransaction ptx = txTpl.prepare(); +// ptx.sign(adminKey); +// +// // 提交并等待共识返回; +// TransactionResponse txResp = ptx.commit(); +// +// // 验证结果; +// txResp.getContentHash(); +// +// Node node0 = context.getNode(0); +// LedgerRepository ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash); +// LedgerBlock block = ledgerOfNode0.getBlock(txResp.getBlockHeight()); +// byte[] contractCodeInDb = ledgerOfNode0.getContractAccountSet(block).getContract(contractDeployKey.getAddress()) +// .getChainCode(); +// txContentHash = ptx.getHash(); +// +// // execute the contract; +// testContractExe(adminKey, ledgerHash, userKey, blockchainService, context); +// +// return block; +// } + +// private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, +// BlockchainService blockchainService, IntegratedContext context) { +// LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); +// LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); +// +// // 定义交易; +// TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); +// +// txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName, +// ("888##abc##" + contractDataKey.getAddress() + "##" + previousBlock.getHash().toBase58() + "##" +// + userKey.getAddress() + "##" + contractDeployKey.getAddress() + "##" + txContentHash.toBase58() +// + "##SOME-VALUE").getBytes()); +// +// // 签名; +// PreparedTransaction ptx = txTpl.prepare(); +// ptx.sign(adminKey); +// +// // 提交并等待共识返回; +// TransactionResponse txResp = ptx.commit(); +// +// // 验证结果; +// txResp.getContentHash(); +// +// LedgerInfo latestLedgerInfo = blockchainService.getLedger(ledgerHash); +// +// Node node0 = context.getNode(0); +// LedgerRepository ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash); +// LedgerBlock backgroundLedgerBlock = ledgerOfNode0.retrieveLatestBlock(); +// +// // 验证合约中的赋值,外部可以获得; +// DataAccountSet dataAccountSet = ledgerOfNode0.getDataAccountSet(backgroundLedgerBlock); +// AsymmetricKeypair key = Crypto.getSignatureFunction("ED25519").generateKeypair(); +// PubKey pubKey = key.getPubKey(); +// Bytes dataAddress = AddressEncoding.generateAddress(pubKey); +// +// // 验证userAccount,从合约内部赋值,然后外部验证;由于目前不允许输入重复的key,所以在内部合约中构建的key,不便于在外展示,屏蔽之; +// // UserAccountSet userAccountSet = +// // ledgerOfNode0.getUserAccountSet(backgroundLedgerBlock); +// // PubKey userPubKey = new PubKey(CryptoAlgorithm.ED25519, +// // userPubKeyVal.getBytes()); +// // String userAddress = AddressEncoding.generateAddress(userPubKey); +// // assertEquals(userAddress, userAccountSet.getUser(userAddress).getAddress()); +// } private void prepareContractData(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainService blockchainService, IntegratedContext context) { From 19012ae8c4369360627a0acf42e7be22fede418b Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Mon, 13 May 2019 10:15:15 +0800 Subject: [PATCH 03/17] intf-contract dev first edition. --- .../contract/jvm/JavaContractCode.java | 70 +++++++++--------- .../transaction/ContractInvocationProxy.java | 8 +- .../ContractInvocationProxyBuilder.java | 53 ++++++++++++- .../blockchain/transaction/ContractType.java | 46 ++++++++++-- .../sdk/samples/SDKDemo_Contract.java | 10 +-- .../jd/blockchain/intgr/IntegrationBase.java | 10 +-- .../jd/blockchain/intgr/IntegrationTest2.java | 6 +- .../intgr/IntegrationTestAll4Redis.java | 6 +- .../intgr/contract/AssetContract.java | 39 ++++++++++ .../src/test/resources/contract.jar | Bin 0 -> 5602 bytes 10 files changed, 188 insertions(+), 60 deletions(-) create mode 100644 source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract.java create mode 100644 source/test/test-integration/src/test/resources/contract.jar 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 0d219a65..b51184de 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 @@ -74,7 +74,7 @@ public class JavaContractCode implements ContractCode { 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(); // 反序列化参数; @@ -97,40 +97,40 @@ public class JavaContractCode implements ContractCode { } // 得到当前类中相关方法和注解对应关系; - Method getMethodByAnno(Object classObj, String eventName) { - Class c = classObj.getClass(); - Class contractEventClass = null; - try { - 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 < 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)) { - 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]); - break; - } - } - } - if (annoMethodMap.containsKey(eventName)) { - return annoMethodMap.get(eventName); - } else { - return null; - } - } +// Method getMethodByAnno(Object classObj, String eventName) { +// Class c = classObj.getClass(); +// Class contractEventClass = null; +// try { +// 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 < 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)) { +// 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]); +// break; +// } +// } +// } +// if (annoMethodMap.containsKey(eventName)) { +// return annoMethodMap.get(eventName); +// } else { +// return null; +// } +// } } } 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 47b73020..843643bc 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 @@ -4,6 +4,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; public class ContractInvocationProxy implements InvocationHandler { @@ -25,6 +26,10 @@ public class ContractInvocationProxy implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if(contractType == null){ + return "contractType == null, no invoke really."; + } + String event = contractType.getEvent(method); if (event == null) { // 适配 Object 对象的方法; @@ -43,7 +48,6 @@ public class ContractInvocationProxy implements InvocationHandler { private byte[] serializeArgs(Object[] args) { // TODO 根据方法参数的定义序列化参数; - return null; + return BinarySerializeUtils.serialize(args); } - } 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 195ed348..3dd073d7 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,9 +1,16 @@ package com.jd.blockchain.transaction; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.HashMap; import java.util.Map; +import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.utils.BaseConstant; import com.jd.blockchain.utils.Bytes; +import org.apache.http.annotation.Contract; public class ContractInvocationProxyBuilder { @@ -32,14 +39,58 @@ public class ContractInvocationProxyBuilder { } // 判断是否是标注了合约的接口类型; + if (!isContractType(contractIntf)){ + return null; + } // 解析合约事件处理方法,检查是否有重名; + if(!isUniqueEvent(contractIntf)){ + return null; + } // TODO 检查是否不支持的参数类型; // TODO 检查返回值类型; - return null; + return ContractType.resolve(contractIntf); + } + + + private boolean isUniqueEvent(Class contractIntf) { + boolean isUnique = true; + Method[] classMethods = contractIntf.getMethods(); + Map methodAnnoMap = new HashMap(); + Map annoMethodMap = new HashMap(); + for (int i = 0; i < classMethods.length; i++) { + Annotation[] a = classMethods[i].getDeclaredAnnotations(); + methodAnnoMap.put(classMethods[i], a); + // if current method contains @ContractEvent,then put it in this map; + for (Annotation annotation_ : a) { + if (classMethods[i].isAnnotationPresent(ContractEvent.class)) { + Object obj = classMethods[i].getAnnotation(ContractEvent.class); + 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); + //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! + if(annoMethodMap.containsKey(eventName_)){ + isUnique = false; + } + annoMethodMap.put(eventName_, classMethods[i]); + } + } + } + + return isUnique; } + /** + * 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; + } } 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 c57db077..dddcb789 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 @@ -1,8 +1,12 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.utils.BaseConstant; + +import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.Set; -import java.util.SortedMap; +import java.util.*; public class ContractType { @@ -48,8 +52,40 @@ public class ContractType { private ContractType() { } - // public static ContractType resolve(Class contractIntf) { - // - // } + public static ContractType resolve(Class contractIntf) { + ContractType contractType = new ContractType(); + //contractIntf contains @Contract and @ContractEvent; + Method[] classMethods = contractIntf.getMethods(); + Map methodAnnoMap = new HashMap(); + for (int i = 0; i < classMethods.length; i++) { + Annotation[] a = classMethods[i].getDeclaredAnnotations(); + methodAnnoMap.put(classMethods[i], a); + // if current method contains @ContractEvent,then put it in this map; + for (Annotation annotation_ : a) { + if (classMethods[i].isAnnotationPresent(ContractEvent.class)) { + Object obj = classMethods[i].getAnnotation(ContractEvent.class); + 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); + //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! + if(contractType.events.containsKey(eventName_)){ + throw new ContractException("too many same eventNames exists in the contract, check it."); + } + contractType.events.put(eventName_, classMethods[i]); + contractType.handleMethods.put(classMethods[i],eventName_); + } + } + } + return contractType; + } + @Override + public String toString() { + return "ContractType{" + + "name='" + name + '\'' + + ", events=" + events + + ", handleMethods=" + handleMethods + + '}'; + } } 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 6811fd2f..3cff2d52 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 @@ -30,14 +30,14 @@ public class SDKDemo_Contract { */ public static void demoContract() { // 账本地址; - String ledgerAddress = "ffkjhkeqwiuhivnsh3298josijdocaijsda=="; + String ledgerAddress = "6GgNS3YgtxvZDBMvHEoqDiNZvWdiJ3MMpvRS9kL4DYwr4"; // 节点地址列表; - NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), - new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), - new NetworkAddress("192.168.10.13", 8080) }; +// NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), +// new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), +// new NetworkAddress("192.168.10.13", 8080) }; // 创建服务代理; - final String GATEWAY_IP = "127.0.0.1"; + final String GATEWAY_IP = "192.168.151.39"; final int GATEWAY_PORT = 80; final boolean SECURE = false; GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java index e7f7345f..9bf8a31c 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java @@ -28,6 +28,7 @@ import com.jd.blockchain.utils.net.NetworkAddress; import org.apache.commons.io.FileUtils; import org.junit.Assert; import org.springframework.core.io.ClassPathResource; +import test.com.jd.blockchain.intgr.contract.AssetContract; import java.io.File; import java.io.FileInputStream; @@ -470,21 +471,20 @@ public class IntegrationBase { txContentHash = ptx.getHash(); // execute the contract; - testContractExe(adminKey, ledgerHash, userKey, blockchainService, ledgerRepository); + testContractExe(adminKey, ledgerHash, userKey, blockchainService, ledgerRepository, AssetContract.class); return block; } - private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, - BlockchainService blockchainService,LedgerRepository ledgerRepository) { + private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, + BlockchainService blockchainService,LedgerRepository ledgerRepository,Class contractIntf) { LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); // 定义交易; TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName, - ("888##123##" + contractDataKey.getAddress()).getBytes()); + txTpl.contract(contractDeployKey.getAddress(),AssetContract.class).issue(10,"abc"); // 签名; PreparedTransaction ptx = txTpl.prepare(); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java index 4e8d317b..ec968e54 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java @@ -41,6 +41,7 @@ import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback; import com.jd.blockchain.utils.net.NetworkAddress; import test.com.jd.blockchain.intgr.IntegratedContext.Node; +import test.com.jd.blockchain.intgr.contract.AssetContract; import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest; import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest.NodeWebContext; @@ -50,7 +51,7 @@ import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsT public class IntegrationTest2 { // 合约测试使用的初始化数据; BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - private String contractZipName = "AssetContract3.contract"; + private String contractZipName = "contract.jar"; private String eventName = "issue-asset"; @Test @@ -315,8 +316,7 @@ public class IntegrationTest2 { // 定义交易; TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName, - ("888##999##abc").getBytes()); + txTpl.contract(contractDeployKey.getAddress(), AssetContract.class).issue(10,"abc"); // 签名; PreparedTransaction ptx = txTpl.prepare(); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java index bcd2ca80..1339b960 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java @@ -48,6 +48,7 @@ import com.jd.blockchain.utils.codec.HexUtils; import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback; import com.jd.blockchain.utils.net.NetworkAddress; +import test.com.jd.blockchain.intgr.contract.AssetContract; import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest; public class IntegrationTestAll4Redis { @@ -450,10 +451,7 @@ public class IntegrationTestAll4Redis { // 定义交易; TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName, - ("888##abc##" + contractDataKey.getAddress() + "##" + previousBlock.getHash().toBase58() + "##" - + userKey.getAddress() + "##" + contractDeployKey.getAddress() + "##" + txContentHash.toBase58() - + "##" + pubKeyVal).getBytes()); + txTpl.contract(contractDeployKey.getAddress(), AssetContract.class).issue(10,"abc"); // 签名; PreparedTransaction ptx = txTpl.prepare(); diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract.java new file mode 100644 index 00000000..68d223fb --- /dev/null +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract.java @@ -0,0 +1,39 @@ +package test.com.jd.blockchain.intgr.contract; + +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; + +/** + * 示例:一个“资产管理”智能合约; + * + * @author huanghaiquan + * + */ +@Contract +public interface AssetContract { + + /** + * 发行资产; + * + * @param amount + * 新发行的资产数量; + * @param assetHolderAddress + * 新发行的资产的持有账户; + */ + @ContractEvent(name = "issue-asset") + void issue(long amount, String assetHolderAddress); + + /** + * 转移资产 + * + * @param fromAddress + * 转出账户; + * @param toAddress + * 转入账户; + * @param amount + * 转移的资产数额; + */ + @ContractEvent(name = "transfer-asset") + void transfer(String fromAddress, String toAddress, long amount); + +} \ No newline at end of file diff --git a/source/test/test-integration/src/test/resources/contract.jar b/source/test/test-integration/src/test/resources/contract.jar new file mode 100644 index 0000000000000000000000000000000000000000..8cdfebfb565f56ed425cf48ad3c280955ab8d660 GIT binary patch literal 5602 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 ZY-y;V-OgwL0M_l#@AkzsZW$K<@P7fKsw@Bi literal 0 HcmV?d00001 From 535c6c2273971624a90537d835f830f38aa49c0c Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Tue, 14 May 2019 13:58:44 +0800 Subject: [PATCH 04/17] test then optimize the contract based interface; --- .../contract/jvm/JavaContractCode.java | 28 ++++++++----------- .../ContractInvocationProxyBuilder.java | 17 +++++------ .../blockchain/transaction/ContractType.java | 4 +-- .../sdk/samples/SDKDemo_Contract.java | 18 +++++++----- .../com/jd/blockchain/utils/BaseConstant.java | 2 +- 5 files changed, 34 insertions(+), 35 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 b51184de..29a66e6f 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 @@ -1,21 +1,16 @@ package com.jd.blockchain.contract.jvm; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.ReflectionUtils; - -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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.SerializationUtils; + +import java.lang.reflect.Method; /** * contract code based jvm @@ -29,7 +24,7 @@ public class JavaContractCode implements ContractCode { private long version; private ContractEventContext contractEventContext; - private ContractType contractType; + private ContractType contractType ; public JavaContractCode(Bytes address, long version, Module codeModule) { this.address = address; @@ -53,9 +48,8 @@ public class JavaContractCode implements ContractCode { codeModule.execute(new ContractExecution()); } - private Object[] resolveArgs(byte[] args) { - // TODO Auto-generated method stub - return null; + private Object resolveArgs(byte[] args) { + return SerializationUtils.deserialize(args); } class ContractExecution implements Runnable { @@ -78,8 +72,8 @@ public class JavaContractCode implements ContractCode { startTime = System.currentTimeMillis(); // 反序列化参数; - Method handleMethod = contractType.getHandleMethod(contractEventContext.getEvent()); - Object[] args = resolveArgs(contractEventContext.getArgs()); + Method handleMethod = ContractType.resolve(myClass).getHandleMethod(contractEventContext.getEvent()); + Object args = resolveArgs(contractEventContext.getArgs()); ReflectionUtils.invokeMethod(handleMethod, contractMainClassObj, args); 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 3dd073d7..90032a9f 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,20 +1,19 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.utils.BaseConstant; +import com.jd.blockchain.utils.Bytes; + import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; -import com.jd.blockchain.contract.ContractEvent; -import com.jd.blockchain.contract.ContractException; -import com.jd.blockchain.utils.BaseConstant; -import com.jd.blockchain.utils.Bytes; -import org.apache.http.annotation.Contract; - public class ContractInvocationProxyBuilder { - private Map, ContractType> contractTypes; + private Map, ContractType> contractTypes = new HashMap, ContractType>(); public T create(String address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); @@ -52,7 +51,9 @@ public class ContractInvocationProxyBuilder { // TODO 检查返回值类型; - return ContractType.resolve(contractIntf); + ContractType contractType1 = ContractType.resolve(contractIntf); + contractTypes.put(contractIntf,contractType1); + return contractType1; } 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 dddcb789..afaab56e 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 @@ -12,9 +12,9 @@ public class ContractType { private String name; - private SortedMap events; + private SortedMap events = Collections.synchronizedSortedMap(new TreeMap<>()); - private SortedMap handleMethods; + private Map handleMethods = new HashMap<>();; /** * 返回声明的所有事件; 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 3cff2d52..3059aaac 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 @@ -25,20 +25,24 @@ public class SDKDemo_Contract { public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); + public static void main(String[] args) { + demoContract(); + } + /** * 演示合约执行的过程; */ public static void demoContract() { // 账本地址; - String ledgerAddress = "6GgNS3YgtxvZDBMvHEoqDiNZvWdiJ3MMpvRS9kL4DYwr4"; + String ledgerAddress = "j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7"; // 节点地址列表; // NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080), // new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080), // new NetworkAddress("192.168.10.13", 8080) }; // 创建服务代理; - final String GATEWAY_IP = "192.168.151.39"; - final int GATEWAY_PORT = 80; + final String GATEWAY_IP = "localhost"; + final int GATEWAY_PORT = 11000; final boolean SECURE = false; GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE, CLIENT_CERT); @@ -52,13 +56,13 @@ public class SDKDemo_Contract { // 一个贸易账户,贸易结算后的利润将通过一个合约账户来执行利润分配; // 合约账户被设置为通用的账户,不具备对贸易结算账户的直接权限; // 只有当前交易发起人具备对贸易账户的直接权限,当交易发起人对交易进行签名之后,权限被间接传递给合约账户; - String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf=="; + String commerceAccount = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1"; // 处理利润分成的通用业务逻辑的合约账户; - String profitDistributionContract = "AAdfe4346fHhefe34fwf343kaeER4678RT=="; + String profitDistributionContract = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1"; // 收益人账户; - String receiptorAccount1 = "MMMEy902jkjjJJDkshreGeasdfassdfajjf=="; - String receiptorAccount2 = "Kjfe8832hfa9jjjJJDkshrFjksjdlkfj93F=="; + String receiptorAccount1 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1"; + String receiptorAccount2 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1"; // 资产编码; String assetKey = "RMB-ASSET"; // 此次待分配利润; diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java index 303f82ee..6e3aeb8c 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java @@ -22,7 +22,7 @@ public class BaseConstant { public static final String SYS_CONTRACT_PROPS_NAME = "sys-contract.properties"; public static final String CONTRACT_MAIN_CLASS_KEY = "contract"; - public static final String CONTRACT_EVENT_PREFIX="@com.jd.blockchain.contract.model.ContractEvent(name="; + public static final String CONTRACT_EVENT_PREFIX="@com.jd.blockchain.contract.ContractEvent(name="; // 编译时引用包黑名单 public static final String PACKAGE_BLACKLIST = "BLACKLIST"; From a67ab58873849cf8af8c53b347d06fc1975b2208 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Tue, 14 May 2019 19:04:14 +0800 Subject: [PATCH 05/17] the first contract test based interface is OK. --- .../com/jd/blockchain/contract/jvm/JavaContractCode.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 29a66e6f..cb37af72 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 @@ -10,7 +10,9 @@ import org.slf4j.LoggerFactory; import org.springframework.util.ReflectionUtils; import org.springframework.util.SerializationUtils; +import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.lang.reflect.Type; /** * contract code based jvm @@ -75,7 +77,11 @@ public class JavaContractCode implements ContractCode { Method handleMethod = ContractType.resolve(myClass).getHandleMethod(contractEventContext.getEvent()); Object args = resolveArgs(contractEventContext.getArgs()); - ReflectionUtils.invokeMethod(handleMethod, contractMainClassObj, args); + Object[] params = null; + if(args.getClass().isArray()){ + params = (Object[])args; + } + ReflectionUtils.invokeMethod(handleMethod, contractMainClassObj, params); LOGGER.info("合约执行,耗时:" + (System.currentTimeMillis() - startTime)); From 642946eece19bdfb9fa60bc707dad253e73ef8aa Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 17 May 2019 09:15:06 +0800 Subject: [PATCH 06/17] add ContractSerialUtils.java; --- .../contract/jvm/JavaContractCode.java | 10 ++-- .../transaction/ContractInvocationProxy.java | 12 ++--- .../binary/ContractSerializeUtils.java | 51 +++++++++++++++++++ 3 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 source/utils/utils-serialize/src/main/java/com/jd/blockchain/utils/serialize/binary/ContractSerializeUtils.java 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 cb37af72..98eccc18 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 @@ -5,14 +5,12 @@ import com.jd.blockchain.contract.engine.ContractCode; import com.jd.blockchain.runtime.Module; import com.jd.blockchain.transaction.ContractType; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.serialize.binary.ContractSerializeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ReflectionUtils; -import org.springframework.util.SerializationUtils; -import java.lang.reflect.Array; import java.lang.reflect.Method; -import java.lang.reflect.Type; /** * contract code based jvm @@ -50,8 +48,8 @@ public class JavaContractCode implements ContractCode { codeModule.execute(new ContractExecution()); } - private Object resolveArgs(byte[] args) { - return SerializationUtils.deserialize(args); + private Object resolveArgs(byte[] args, Method method) { + return ContractSerializeUtils.deserializeMethodParam(args,method); } class ContractExecution implements Runnable { @@ -75,7 +73,7 @@ public class JavaContractCode implements ContractCode { // 反序列化参数; Method handleMethod = ContractType.resolve(myClass).getHandleMethod(contractEventContext.getEvent()); - Object args = resolveArgs(contractEventContext.getArgs()); + Object args = resolveArgs(contractEventContext.getArgs(), handleMethod); Object[] params = null; if(args.getClass().isArray()){ 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 843643bc..26857631 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 @@ -1,11 +1,11 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.serialize.binary.ContractSerializeUtils; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; - public class ContractInvocationProxy implements InvocationHandler { // private String contractMessage; @@ -39,15 +39,15 @@ public class ContractInvocationProxy implements InvocationHandler { // hashCode 方法; } // 合约方法; - byte[] argBytes = serializeArgs(args); + byte[] argBytes = serializeArgs(args,method); sendOpBuilder.send(contractAddress, event, argBytes); // TODO: 暂时未考虑有返回值的情况; return null; } - private byte[] serializeArgs(Object[] args) { + private byte[] serializeArgs(Object[] args, Method method) throws Exception { // TODO 根据方法参数的定义序列化参数; - return BinarySerializeUtils.serialize(args); + return ContractSerializeUtils.serializeMethodParam(args,method); } } diff --git a/source/utils/utils-serialize/src/main/java/com/jd/blockchain/utils/serialize/binary/ContractSerializeUtils.java b/source/utils/utils-serialize/src/main/java/com/jd/blockchain/utils/serialize/binary/ContractSerializeUtils.java new file mode 100644 index 00000000..d239c883 --- /dev/null +++ b/source/utils/utils-serialize/src/main/java/com/jd/blockchain/utils/serialize/binary/ContractSerializeUtils.java @@ -0,0 +1,51 @@ +package com.jd.blockchain.utils.serialize.binary; + +import com.jd.blockchain.utils.ArrayUtils; +import com.jd.blockchain.utils.io.BytesUtils; +import org.springframework.util.SerializationUtils; + +import java.lang.reflect.Method; +import java.math.BigDecimal; + +/** + * @author zhaogw + * date 2019/5/16 18:05 + */ +public class ContractSerializeUtils { + public static final Class[] confirmedType = {Integer.class, Long.class, Double.class, + int.class,long.class,double.class,String.class, BigDecimal.class}; + + /** + * valid then parse the Object by Method params; + * @param object + * @param method + * @return + */ + public static byte[] serializeMethodParam(Object object,Method method) { + if (object == null) { + return BytesUtils.EMPTY_BYTES; + } + + Class[] classType = method.getParameterTypes(); + for(Class curClass : classType){ + if(!ArrayUtils.asList(confirmedType).contains(curClass)){ + throw new IllegalArgumentException("not support this type="+curClass.toString()); + } + } + return SerializationUtils.serialize(object); + } + + public static Object deserializeMethodParam(byte[] bytes,Method method) { + if (bytes == null) { + return null; + } + + Class[] classType = method.getParameterTypes(); + for(Class curClass : classType){ + if(!ArrayUtils.asList(confirmedType).contains(curClass)){ + throw new IllegalArgumentException("not support this type="+curClass.toString()); + } + } + return SerializationUtils.deserialize(bytes); + } +} From f781f6c3d187b020bf58085c8caf524c490a4785 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Tue, 21 May 2019 14:59:41 +0800 Subject: [PATCH 07/17] parse the params'bytes[] --- .../blockchain/binaryproto/DataContract.java | 2 +- .../contract/jvm/JavaContractCode.java | 2 +- .../contract/ContractSerializeUtils.java | 202 ++++++++++++ .../blockchain/ledger/CONTRACT_BIG_INT.java | 20 ++ .../jd/blockchain/ledger/CONTRACT_BINARY.java | 18 ++ .../jd/blockchain/ledger/CONTRACT_INT16.java | 18 ++ .../jd/blockchain/ledger/CONTRACT_INT32.java | 18 ++ .../jd/blockchain/ledger/CONTRACT_INT64.java | 18 ++ .../jd/blockchain/ledger/CONTRACT_INT8.java | 18 ++ .../jd/blockchain/ledger/CONTRACT_TEXT.java | 18 ++ .../contract/ContractConfigure.java | 93 ++++++ .../contract/samples/AssetContract2.java | 27 ++ .../contract/samples/AssetContractImpl2.java | 68 ++++ .../sdk/test/SDK_Contract_Test.java | 301 ++++++++++++++++++ .../sdk/test/SDK_GateWay_KeyPair_Para.java | 16 +- .../src/test/resources/contract.jar | Bin 0 -> 5372 bytes .../test/resources/sys-contract.properties | 13 + .../binary/ContractSerializeUtils.java | 51 --- 18 files changed, 842 insertions(+), 61 deletions(-) create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java create mode 100644 source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java create mode 100644 source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java create mode 100644 source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java create mode 100644 source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java create mode 100644 source/sdk/sdk-samples/src/test/resources/contract.jar create mode 100644 source/sdk/sdk-samples/src/test/resources/sys-contract.properties delete mode 100644 source/utils/utils-serialize/src/main/java/com/jd/blockchain/utils/serialize/binary/ContractSerializeUtils.java diff --git a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataContract.java b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataContract.java index dee872e3..6c0fc8e2 100644 --- a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataContract.java +++ b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataContract.java @@ -27,7 +27,7 @@ import java.lang.annotation.Target; * @author huanghaiquan * */ -@Target({ ElementType.TYPE }) +@Target({ ElementType.TYPE, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) public @interface DataContract { 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 98eccc18..e1697b8b 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 @@ -5,7 +5,7 @@ import com.jd.blockchain.contract.engine.ContractCode; import com.jd.blockchain.runtime.Module; import com.jd.blockchain.transaction.ContractType; import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.serialize.binary.ContractSerializeUtils; +import com.jd.blockchain.contract.ContractSerializeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ReflectionUtils; diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java new file mode 100644 index 00000000..440c06d1 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -0,0 +1,202 @@ +package com.jd.blockchain.contract; + +import com.jd.blockchain.binaryproto.BinaryProtocol; +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.consts.DataCodes; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.utils.ArrayUtils; +import com.jd.blockchain.utils.io.ByteArray; +import com.jd.blockchain.utils.io.BytesUtils; +import org.springframework.util.SerializationUtils; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author zhaogw + * date 2019/5/16 18:05 + */ +public class ContractSerializeUtils { + public static Map> dataContractMap = new HashMap<>(); + public static final Class[] confirmedType = {CONTRACT_INT8.class,CONTRACT_INT16.class,CONTRACT_INT32.class,CONTRACT_INT64.class, + CONTRACT_TEXT.class,CONTRACT_BINARY.class,CONTRACT_BIG_INT.class}; + + /** + * valid then parse the Object by Method params; + * @param object + * @param method + * @return + */ + public static byte[] serializeMethodParam(Object object,Method method) { + if (object == null) { + return null; + } + + Object[] objArr = null; + if(object.getClass().isArray()){ + objArr = (Object[]) object; + } + + Class[] classTypes = method.getParameterTypes(); + Annotation [][] annotations = method.getParameterAnnotations(); + byte[][] result = new byte[classTypes.length][]; + //将method中形参转换为实体对象,每个形参都必须为@DataContract类型;每个形参使用系统的BinaryProtocol来进行序列化,如果有5个参数,则使用5次序列化; + int sum = 0; + for(int i=0;i classType = classTypes[i]; + DataContract dataContract = classType.getDeclaredAnnotation(DataContract.class); + if(dataContract == null){ + boolean canPass = false; + //check by annotation; + Annotation[] annotationArr = annotations[i]; + for(Annotation annotation : annotationArr){ + if(annotation.annotationType().equals(DataContract.class)){ + dataContract = (DataContract) annotation; + objArr[i] = regenObj(dataContract,objArr[i]); + canPass = true; + } + } + if(!canPass){ + throw new IllegalArgumentException("must set annotation in each param of contract."); + } + } + //get data interface; + result[i] = BinaryProtocol.encode(objArr[i],getDataIntf().get(dataContract.code())); + sum += result[i].length; + } + /** + * //return is byte[], but now is byte[][], so we should reduct dimension, use the header info to the first byte(length=classTypes.length); + format:result[][]={{1,2,3},{4,5},{6,7}}; newResult[]=classTypes.length/first length/second length/3 length/result[0]/result[1]/result[2]; + rtnBytes[0]: 4 bytes(classTypes.length, <255); + rtnBytes[1]: 4 bytes(each param's length, ) + rtnBytes[2]: 4 bytes(each param's length, ) + rtnBytes[3]: 4 bytes(each param's length, ) + rtnBytes[4...]: result[0][] bytes(each param's length) + rtnBytes[5...]: result[1][] bytes(each param's length) + rtnBytes[6...]: result[2][] bytes(each param's length) + */ + + int bodyFirstPosition = 4 + 4*(classTypes.length); + ByteBuffer byteBuffer = ByteBuffer.allocate(bodyFirstPosition + sum); + byteBuffer.putInt(classTypes.length); + for(int j=0; j[] classTypes = method.getParameterTypes(); + Object result[] = new Object[classTypes.length]; + + ByteBuffer byteBuffer = ByteBuffer.allocate(params.length); + int paramNums = byteBuffer.getInt(0); + + if(paramNums != classTypes.length){ + throw new IllegalArgumentException("deserializeMethodparm. params'length in byte[] != method's param length"); + } + for(int i=0; i classType = classTypes[i]; + int curParamLength = byteBuffer.get(i+1); + DataContract dataContract = classType.getDeclaredAnnotation(DataContract.class); + if(dataContract == null){ + throw new IllegalArgumentException("must set annotation in each param of contract."); + } + result [i] = BinaryProtocol.decodeAs( + byteBuffer.get(params,(i + 1 + classTypes.length)*4,curParamLength).array(), + getDataIntf().get(dataContract.code())); + } + + return result; + } + + + public static Map > getDataIntf(){ + dataContractMap.put(DataCodes.CONTRACT_INT8, CONTRACT_INT8.class); + dataContractMap.put(DataCodes.CONTRACT_INT16, CONTRACT_INT16.class); + dataContractMap.put(DataCodes.CONTRACT_INT32, CONTRACT_INT32.class); + dataContractMap.put(DataCodes.CONTRACT_INT64, CONTRACT_INT64.class); + dataContractMap.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class); + dataContractMap.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class); + dataContractMap.put(DataCodes.CONTRACT_BIG_INT, CONTRACT_BIG_INT.class); + dataContractMap.put(DataCodes.TX_CONTENT_BODY, TransactionContentBody.class); + return dataContractMap; + } + + private static Object regenObj(DataContract dataContract, Object object){ + if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT8.class)){ + return new CONTRACT_INT8() { + @Override + public int getValue() { + return Integer.parseInt(object.toString()); + } + }; + }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT16.class)){ + return new CONTRACT_INT16() { + @Override + public int getValue() { + return Integer.parseInt(object.toString()); + } + }; + }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT32.class)){ + return new CONTRACT_INT32() { + @Override + public int getValue() { + return Integer.parseInt(object.toString()); + } + }; + }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT64.class)){ + return new CONTRACT_INT64() { + @Override + public long getValue() { + return Long.parseLong(object.toString()); + } + }; + }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_TEXT.class)){ + return new CONTRACT_TEXT() { + @Override + public String getValue() { + return object.toString(); + } + }; + }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BINARY.class)){ + return new CONTRACT_BINARY() { + @Override + public Byte getValue() { + return (Byte) object; + } + }; + }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BIG_INT.class)){ + return new CONTRACT_BIG_INT() { + @Override + public BigDecimal getValue() { + return new BigDecimal(object.toString()); + } + }; + } + return null; + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java new file mode 100644 index 00000000..e53f017f --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java @@ -0,0 +1,20 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +import java.math.BigDecimal; + +/** + * contract args for BIG_INT; + * @author zhaogw + * date 2019-05-17 15:32 + */ +@DataContract(code = DataCodes.CONTRACT_BINARY) +public interface CONTRACT_BIG_INT { + + @DataField(order=2, primitiveType= PrimitiveType.BIG_INT) + BigDecimal getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java new file mode 100644 index 00000000..b4193d85 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java @@ -0,0 +1,18 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +/** + * contract args for Binary; + * @author zhaogw + * date 2019-05-17 15:32 + */ +@DataContract(code = DataCodes.CONTRACT_BINARY) +public interface CONTRACT_BINARY { + + @DataField(order=2, primitiveType= PrimitiveType.BYTES) + Byte getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java new file mode 100644 index 00000000..cb27e0c6 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java @@ -0,0 +1,18 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +/** + * contract args for int16; + * @author zhaogw + * date 2019-05-17 15:32 + */ +@DataContract(code = DataCodes.CONTRACT_INT16) +public interface CONTRACT_INT16 { + + @DataField(order=2, primitiveType= PrimitiveType.INT16) + int getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java new file mode 100644 index 00000000..02fdb07e --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java @@ -0,0 +1,18 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +/** + * contract args for int32; + * @author zhaogw + * date 2019-05-17 15:32 + */ +@DataContract(code = DataCodes.CONTRACT_INT32) +public interface CONTRACT_INT32 { + + @DataField(order=2, primitiveType= PrimitiveType.INT32) + int getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java new file mode 100644 index 00000000..ad092edd --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java @@ -0,0 +1,18 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +/** + * contract args for int64; + * @author zhaogw + * date 2019-05-17 15:32 + */ +@DataContract(code = DataCodes.CONTRACT_INT64) +public interface CONTRACT_INT64 { + + @DataField(order=2, primitiveType= PrimitiveType.INT64) + long getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java new file mode 100644 index 00000000..754e23ed --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java @@ -0,0 +1,18 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +/** + * contract args for int8; + * @author zhaogw + * date 2019-05-17 15:32 + */ +@DataContract(code = DataCodes.CONTRACT_INT8) +public interface CONTRACT_INT8 { + + @DataField(order=2, primitiveType= PrimitiveType.INT8) + int getValue(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java new file mode 100644 index 00000000..8f5e4a4c --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java @@ -0,0 +1,18 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +/** + * contract args for String; + * @author zhaogw + * date 2019-05-17 15:32 + */ +@DataContract(code = DataCodes.CONTRACT_TEXT) +public interface CONTRACT_TEXT { + + @DataField(order=2, primitiveType= PrimitiveType.TEXT) + String getValue(); +} diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java new file mode 100644 index 00000000..61dbb10c --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java @@ -0,0 +1,93 @@ +package com.jd.blockchain.contract; + +import com.jd.blockchain.utils.BaseConstant; +import com.jd.blockchain.utils.ConsoleUtils; +import com.jd.blockchain.utils.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + +import java.io.*; +import java.util.*; + +import static com.jd.blockchain.utils.BaseConstant.SYS_CONTRACT_CONF; +import static com.jd.blockchain.utils.BaseConstant.SYS_CONTRACT_PROPS_NAME; + +/** + * + * @author zhaogw + * date 2019/3/15 18:22 + */ +public enum ContractConfigure { + instance(); + private static final Logger LOGGER = LoggerFactory.getLogger(ContractConfigure.class); + static Properties pp; + + ContractConfigure(){ + init(); + } + + private void init(){ + String contractConfPath = System.getProperty(SYS_CONTRACT_CONF); + System.out.println("contractConfPath="+contractConfPath); + try { + if (contractConfPath == null) { + ConsoleUtils.info("Load build-in default contractConf in ContractConfigure ..."); + ClassPathResource contractConfigResource = new ClassPathResource(SYS_CONTRACT_PROPS_NAME); + InputStream in = contractConfigResource.getInputStream(); + pp = FileUtils.readProperties(in, BaseConstant.CHARSET_UTF_8); + } else { + ConsoleUtils.info("Load configuration in ContractConfigure,contractConfPath="+contractConfPath); + File file = new File(contractConfPath); + pp = FileUtils.readProperties(file, BaseConstant.CHARSET_UTF_8); + } + } catch (Exception e) { + LOGGER.info(SYS_CONTRACT_PROPS_NAME+"文件异常!"+e.getMessage()); + } + } + + public String values(String key) { + if(pp == null){ + init(); + } + return pp.getProperty(key); + } + + public String allValues() { + if(pp == null){ + init(); + } + Set allKeys = pp.stringPropertyNames(); + List propList = new ArrayList(); + for(String _key : allKeys){ + String value = pp.getProperty(_key); + propList.add(_key+": "+value); + LOGGER.info("key={}, value={}",_key,value); + } + return propList.toString(); + } + + //写入资源文件信息 + public static void writeProperties(String fileAllName, String comments, Map map){ + Properties properties=new Properties(); + try { + File file = new File(fileAllName); + if (!file.getParentFile().exists()) { + boolean result = file.getParentFile().mkdirs(); + if (!result) { + System.out.println("文件创建失败."); + } + } + OutputStream outputStream=new FileOutputStream(file); + for(Map.Entry entry : map.entrySet()){ + properties.setProperty(entry.getKey(), entry.getValue()); + } + properties.store(outputStream, comments); + outputStream.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java new file mode 100644 index 00000000..24fcc598 --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java @@ -0,0 +1,27 @@ +package com.jd.blockchain.contract.samples; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.consts.DataCodes; +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.ledger.CONTRACT_TEXT; +import com.jd.blockchain.ledger.TransactionContentBody; + +/** + * 示例:一个“资产管理”智能合约; + * + * @author zhaogw + */ +@Contract +public interface AssetContract2 { + + /** + * 发行资产; + * 新发行的资产数量; + * @param assetHolderAddress + * 新发行的资产的持有账户; + */ + @ContractEvent(name = "issue-asset") + void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, + @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress); +} \ No newline at end of file diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java new file mode 100644 index 00000000..a6c2b157 --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java @@ -0,0 +1,68 @@ +package com.jd.blockchain.contract.samples; + +import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.contract.EventProcessingAwire; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.KVDataObject; +import com.jd.blockchain.ledger.TransactionContentBody; +import com.jd.blockchain.utils.io.BytesUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * 示例:一个“资产管理”智能合约的实现; + * + * 注: 1、实现 EventProcessingAwire 接口以便合约实例在运行时可以从上下文获得合约生命周期事件的通知; 2、实现 + * AssetContract 接口定义的合约方法; + * + * @author huanghaiquan + * + */ +public class AssetContractImpl2 implements EventProcessingAwire, AssetContract2 { + // 合约事件上下文; + private ContractEventContext eventContext; + + @Override + public void issue(TransactionContentBody transactionContentBody, String assetHolderAddress) { + System.out.println(transactionContentBody.toString()); + } + + /* + * (non-Javadoc) + * + * @see + * com.jd.blockchain.contract.model.EventProcessingAwire#beforeEvent(com.jd. + * blockchain.contract.model.ContractEventContext) + */ + @Override + public void beforeEvent(ContractEventContext eventContext) { + this.eventContext = eventContext; + } + + /* + * (non-Javadoc) + * + * @see com.jd.blockchain.contract.model.EventProcessingAwire#postEvent(com.jd. + * blockchain.contract.model.ContractEventContext, + * com.jd.blockchain.contract.model.ContractError) + */ + @Override + public void postEvent(ContractEventContext eventContext, ContractException error) { + this.eventContext = null; + } + + @Override + public void postEvent(ContractException error) { + + } + + @Override + public void postEvent() { + + } +} diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java new file mode 100644 index 00000000..d74ea6bd --- /dev/null +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -0,0 +1,301 @@ +package test.com.jd.blockchain.sdk.test; + +import com.jd.blockchain.contract.samples.AssetContract; +import com.jd.blockchain.contract.samples.AssetContract2; +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.BlockchainServiceFactory; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.sdk.samples.SDKDemo_Contract; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.codec.Base58Utils; +import com.jd.blockchain.utils.io.ByteArray; +import com.jd.blockchain.utils.net.NetworkAddress; +import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +import static org.junit.Assert.assertTrue; + +/** + * 演示合约执行的过程; + * + * @author zhaogw + * 2019-05-21 11:03 + */ +public class SDK_Contract_Test { + public static Logger log = LoggerFactory.getLogger(SDKDemo_Contract.class); + + public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519"); + // 账本地址; + public static String ledgerAddress; + private PrivKey privKey; + private PubKey pubKey; + BlockchainService bcsrv; + AsymmetricKeypair signKeyPair; + HashDigest ledgerHash; + + @Before + public void init(){ + ledgerAddress = "j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7"; + ledgerHash = getLedgerHash(); + pubKey = SDK_GateWay_KeyPair_Para.pubKey0; + privKey = SDK_GateWay_KeyPair_Para.privkey0; + // 使用私钥进行签名; + signKeyPair = new BlockchainKeypair(pubKey, privKey); + + // 创建服务代理; + final String GATEWAY_IP = "localhost"; + final int GATEWAY_PORT = 11000; + NetworkAddress addr = new NetworkAddress(GATEWAY_IP,GATEWAY_PORT); + GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(addr); + bcsrv = serviceFactory.getBlockchainService(); + } + + /** + * 演示合约执行的过程; + */ + @Test + public void demoContract1() { + // 发起交易; + TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); + String contractAddress = "LdeNfBcbQWqVge1sVyLq3EHBJhMMjwQY3uJJE"; + AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); + TransactionContentBody transactionContentBody = new TransactionContentBody() { + @Override + public HashDigest getLedgerHash() { + return new HashDigest(ClassicAlgorithm.SHA256, "zhaogw".getBytes()); + } + + @Override + public Operation[] getOperations() { + return new Operation[0]; + } + }; + assetContract.issue(transactionContentBody,contractAddress); + + // TX 准备就绪; + PreparedTransaction prepTx = txTemp.prepare(); + prepTx.sign(signKeyPair); + // 提交交易; + prepTx.commit(); + } + + @Test + public void registerData(){ + // 在本地定义 TX 模板 + TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); + BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); + txTemp.dataAccounts().register(dataAccount.getIdentity()); + + String key1 = "jd_key1"; + String val1 = "www.jd1.com"; + String key2 = "jd_key2"; + String val2 = "www.jd2.com"; + // 定义交易,传输最简单的数字、字符串、提取合约中的地址; + txTemp.dataAccount(dataAccount.getAddress()).set(key1, val1, -1); + txTemp.dataAccount(dataAccount.getAddress()).set(key2, val2, -1); + + // TX 准备就绪; + PreparedTransaction prepTx = txTemp.prepare(); + prepTx.sign(signKeyPair); + // 提交交易; + TransactionResponse transactionResponse = prepTx.commit(); + + assertTrue(transactionResponse.isSuccess()); + + //repeat; + String[] keys = {key1,key2}; + String[] values = {"www.jd1.com.v1","www.jd2.com.v1"}; + this.setDataInDataAddress(dataAccount.getAddress(),keys,values,0); + String[] values2 = {"www.jd1.com.v2","www.jd2.com.v2"}; + this.setDataInDataAddress(dataAccount.getAddress(),keys,values2,1); + } + + private void setDataInDataAddress(Bytes dataAddress, String[] keys, String[] values, long version){ + // 在本地定义 TX 模板 + TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); + BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); + + for(int i=0; i + * + * 注:私钥由调用方在本地保管和使用; + * + * @return + */ + private static AsymmetricKeypair getSponsorKey() { + SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519"); + return signatureFunction.generateKeypair(); + } + + /** + * 商品信息; + * + * @author huanghaiquan + * + */ + public static class Remark { + + private String code; + + private String name; + + private String venderAddress; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVenderAddress() { + return venderAddress; + } + + public void setVenderAddress(String venderAddress) { + this.venderAddress = venderAddress; + } + + } + +} diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java index 916a3460..450e5ff4 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java @@ -10,16 +10,16 @@ import com.jd.blockchain.tools.keygen.KeyGenCommand; public class SDK_GateWay_KeyPair_Para { public static final String PASSWORD = "abc"; - public static final String[] PUB_KEYS = { "endPsK36imXrY66pru6ttZ8dZ3TynWekmdqoM1K7ZRRoRBBiYVzM", - "endPsK36jQE1uYpdVRSnwQXVYhgAMWTaMJiAqii7URiULoBDLUUN", - "endPsK36fc7FSecKAJCJdFhTejbPHMLaGcihJVQCv95czCq4tW5n", - "endPsK36m1grx8mkTMgh8XQHiiaNzajdC5hkuqP6pAuLmMbYkzd4" }; + public static final String[] PUB_KEYS = { "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", + "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", + "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", + "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk" }; public static final String[] PRIV_KEYS = { - "177gjsuHdbf3PU68Sm1ZU2aMcyB7sLWj94xwBUoUKvTgHq7qGUfg6ynDB62hocYYXSRXD4X", - "177gjwQwTdXthkutDKVgKwiq6wWfLWYuxhji1U2N1C5MzqLRWCLZXo3i2g4vpfcEAQUPG8H", - "177gjvLHUjxvAWsqVcGgV8eHgVNBvJZYDfpP9FLjTouR1gEJNiamYu1qjTNDh18XWyLg8or", - "177gk2VtYeGbK5TS2xWhbSZA4BsT9Xj5Fb8hqCzxzgbojVVcqaDSFFrFPsLbZBx7rszyCNy" }; + "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", + "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", + "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", + "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns" }; public static PrivKey privkey0 = KeyGenCommand.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD); public static PrivKey privkey1 = KeyGenCommand.decodePrivKeyWithRawPassword(PRIV_KEYS[1], PASSWORD); diff --git a/source/sdk/sdk-samples/src/test/resources/contract.jar b/source/sdk/sdk-samples/src/test/resources/contract.jar new file mode 100644 index 0000000000000000000000000000000000000000..c96e32148a9e10caa00ba044c759389e29140337 GIT binary patch literal 5372 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 Ob^Z8VC-(5q3;92z6GNE* literal 0 HcmV?d00001 diff --git a/source/sdk/sdk-samples/src/test/resources/sys-contract.properties b/source/sdk/sdk-samples/src/test/resources/sys-contract.properties new file mode 100644 index 00000000..a1457b06 --- /dev/null +++ b/source/sdk/sdk-samples/src/test/resources/sys-contract.properties @@ -0,0 +1,13 @@ +#ledger info; +ownerPubPath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.pub +ownerPrvPath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.priv +ownerPassword=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.pwd +ledgerHash=j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7 +host=localhost +port=11000 +#execute contract; +event = issue-asset +chainCodePath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\contract-compile\\target\\contract.jar +contractArgs=1000##fromAddr##LdeNvLeq6MB6y8CoyawYxgCCYCJkrp5xoVGUw +#contractArgs=fromAddr##toAddr##30##LdeNvLeq6MB6y8CoyawYxgCCYCJkrp5xoVGUw + diff --git a/source/utils/utils-serialize/src/main/java/com/jd/blockchain/utils/serialize/binary/ContractSerializeUtils.java b/source/utils/utils-serialize/src/main/java/com/jd/blockchain/utils/serialize/binary/ContractSerializeUtils.java deleted file mode 100644 index d239c883..00000000 --- a/source/utils/utils-serialize/src/main/java/com/jd/blockchain/utils/serialize/binary/ContractSerializeUtils.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.jd.blockchain.utils.serialize.binary; - -import com.jd.blockchain.utils.ArrayUtils; -import com.jd.blockchain.utils.io.BytesUtils; -import org.springframework.util.SerializationUtils; - -import java.lang.reflect.Method; -import java.math.BigDecimal; - -/** - * @author zhaogw - * date 2019/5/16 18:05 - */ -public class ContractSerializeUtils { - public static final Class[] confirmedType = {Integer.class, Long.class, Double.class, - int.class,long.class,double.class,String.class, BigDecimal.class}; - - /** - * valid then parse the Object by Method params; - * @param object - * @param method - * @return - */ - public static byte[] serializeMethodParam(Object object,Method method) { - if (object == null) { - return BytesUtils.EMPTY_BYTES; - } - - Class[] classType = method.getParameterTypes(); - for(Class curClass : classType){ - if(!ArrayUtils.asList(confirmedType).contains(curClass)){ - throw new IllegalArgumentException("not support this type="+curClass.toString()); - } - } - return SerializationUtils.serialize(object); - } - - public static Object deserializeMethodParam(byte[] bytes,Method method) { - if (bytes == null) { - return null; - } - - Class[] classType = method.getParameterTypes(); - for(Class curClass : classType){ - if(!ArrayUtils.asList(confirmedType).contains(curClass)){ - throw new IllegalArgumentException("not support this type="+curClass.toString()); - } - } - return SerializationUtils.deserialize(bytes); - } -} From 5851902fc4cc4f5b2746cc775fae41d1ee7d5bb1 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Wed, 22 May 2019 11:24:38 +0800 Subject: [PATCH 08/17] test pass for contract param serialize and deserialize --- .../com/jd/blockchain/consts/DataCodes.java | 8 +++ .../contract/ContractSerializeUtils.java | 62 ++++++++++++++---- .../blockchain/ledger/CONTRACT_BIG_INT.java | 2 +- .../jd/blockchain/ledger/CONTRACT_BINARY.java | 3 +- .../jd/blockchain/ledger/CONTRACT_INT16.java | 2 +- .../jd/blockchain/ledger/CONTRACT_INT8.java | 2 +- .../transaction/ContractInvocationProxy.java | 5 +- .../sdk/client/GatewayServiceFactory.java | 8 +++ .../sdk/test/SDK_Contract_Test.java | 4 +- .../src/test/resources/contract.jar | Bin 5372 -> 6765 bytes .../jd/blockchain/intgr/IntegrationTest.java | 37 +++-------- .../jd/blockchain/intgr/IntegrationTest2.java | 41 +++++------- .../intgr/IntegrationTestAll4Redis.java | 43 ++++-------- 13 files changed, 113 insertions(+), 104 deletions(-) diff --git a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java index 6b47a505..9d069903 100644 --- a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java +++ b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java @@ -79,7 +79,15 @@ public interface DataCodes { public static final int DATA = 0x900; + //contract related; public static final int CONTRACT = 0xA00; + public static final int CONTRACT_INT8 = 0xA01; + public static final int CONTRACT_INT16 = 0xA02; + public static final int CONTRACT_INT32 = 0xA03; + public static final int CONTRACT_INT64 = 0xA04; + public static final int CONTRACT_TEXT = 0xA05; + public static final int CONTRACT_BINARY = 0xA06; + public static final int CONTRACT_BIG_INT = 0xA07; public static final int HASH = 0xB00; diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index 440c06d1..c68c84bc 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -6,8 +6,10 @@ import com.jd.blockchain.binaryproto.DataField; import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.ledger.*; import com.jd.blockchain.utils.ArrayUtils; +import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.io.ByteArray; import com.jd.blockchain.utils.io.BytesUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.util.SerializationUtils; import java.lang.annotation.Annotation; @@ -92,7 +94,7 @@ public class ContractSerializeUtils { byteBuffer.putInt(curResult.length); } for(int k=0; k classType = classTypes[i]; - int curParamLength = byteBuffer.get(i+1); + int curParamLength = byteBuffer.getInt((i+1)*4); DataContract dataContract = classType.getDeclaredAnnotation(DataContract.class); if(dataContract == null){ - throw new IllegalArgumentException("must set annotation in each param of contract."); + boolean canPass = false; + //check by annotation; + Annotation[] annotationArr = annotations[i]; + for(Annotation annotation : annotationArr){ + if(annotation.annotationType().equals(DataContract.class)){ + dataContract = (DataContract) annotation; + canPass = true; + } + } + if(!canPass){ + throw new IllegalArgumentException("must set annotation in each param of contract."); + } } - result [i] = BinaryProtocol.decodeAs( - byteBuffer.get(params,(i + 1 + classTypes.length)*4,curParamLength).array(), + ByteBuffer byteBuffer1 = ByteBuffer.allocate(curParamLength); + byteBuffer1.put(params,offsetPosition,curParamLength); + offsetPosition += curParamLength; + //if dataContract=primitive type(byte/short/int/long/String),only use its getValues(); + Object object = BinaryProtocol.decodeAs(byteBuffer1.array(), getDataIntf().get(dataContract.code())); + if(isPrimitiveType(dataContract.code())){ + Class classObj = getDataIntf().get(dataContract.code()); + try { + result[i] = ReflectionUtils.invokeMethod(classObj.getMethod("getValue"),object); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("no getValue(). detail="+e.getMessage()); + } + }else { + result[i] = object; + } + byteBuffer1.clear(); } return result; @@ -146,19 +177,28 @@ public class ContractSerializeUtils { return dataContractMap; } + public static boolean isPrimitiveType(int dataContractCode){ + return (dataContractCode == DataCodes.CONTRACT_INT8 || + dataContractCode == DataCodes.CONTRACT_INT16 || + dataContractCode == DataCodes.CONTRACT_INT32 || + dataContractCode == DataCodes.CONTRACT_INT64 || + dataContractCode == DataCodes.CONTRACT_TEXT + ); + } + private static Object regenObj(DataContract dataContract, Object object){ if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT8.class)){ return new CONTRACT_INT8() { @Override - public int getValue() { - return Integer.parseInt(object.toString()); + public Byte getValue() { + return Byte.parseByte(object.toString()); } }; }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT16.class)){ return new CONTRACT_INT16() { @Override - public int getValue() { - return Integer.parseInt(object.toString()); + public short getValue() { + return Short.parseShort(object.toString()); } }; }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT32.class)){ @@ -185,8 +225,8 @@ public class ContractSerializeUtils { }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BINARY.class)){ return new CONTRACT_BINARY() { @Override - public Byte getValue() { - return (Byte) object; + public Bytes getValue() { + return (Bytes) object; } }; }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BIG_INT.class)){ diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java index e53f017f..fad0e208 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java @@ -12,7 +12,7 @@ import java.math.BigDecimal; * @author zhaogw * date 2019-05-17 15:32 */ -@DataContract(code = DataCodes.CONTRACT_BINARY) +@DataContract(code = DataCodes.CONTRACT_BIG_INT) public interface CONTRACT_BIG_INT { @DataField(order=2, primitiveType= PrimitiveType.BIG_INT) diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java index b4193d85..7661b852 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java @@ -4,6 +4,7 @@ import com.jd.blockchain.binaryproto.DataContract; import com.jd.blockchain.binaryproto.DataField; import com.jd.blockchain.binaryproto.PrimitiveType; import com.jd.blockchain.consts.DataCodes; +import com.jd.blockchain.utils.Bytes; /** * contract args for Binary; @@ -14,5 +15,5 @@ import com.jd.blockchain.consts.DataCodes; public interface CONTRACT_BINARY { @DataField(order=2, primitiveType= PrimitiveType.BYTES) - Byte getValue(); + Bytes getValue(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java index cb27e0c6..b6666cc0 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java @@ -14,5 +14,5 @@ import com.jd.blockchain.consts.DataCodes; public interface CONTRACT_INT16 { @DataField(order=2, primitiveType= PrimitiveType.INT16) - int getValue(); + short getValue(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java index 754e23ed..f77d3de2 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java @@ -14,5 +14,5 @@ import com.jd.blockchain.consts.DataCodes; public interface CONTRACT_INT8 { @DataField(order=2, primitiveType= PrimitiveType.INT8) - int getValue(); + Byte getValue(); } 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 26857631..542e31f5 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 @@ -1,8 +1,7 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.serialize.binary.ContractSerializeUtils; - import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -46,7 +45,7 @@ public class ContractInvocationProxy implements InvocationHandler { return null; } - private byte[] serializeArgs(Object[] args, Method method) throws Exception { + private byte[] serializeArgs(Object[] args, Method method) { // TODO 根据方法参数的定义序列化参数; return ContractSerializeUtils.serializeMethodParam(args,method); } diff --git a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java index 5396a430..f3e3b42c 100644 --- a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java +++ b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java @@ -56,6 +56,14 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl DataContractRegistry.register(ClientIdentifications.class); DataContractRegistry.register(ClientIdentification.class); + DataContractRegistry.register(CONTRACT_INT8.class); + DataContractRegistry.register(CONTRACT_INT16.class); + DataContractRegistry.register(CONTRACT_INT32.class); + DataContractRegistry.register(CONTRACT_INT64.class); + DataContractRegistry.register(CONTRACT_TEXT.class); + DataContractRegistry.register(CONTRACT_BINARY.class); +// DataContractRegistry.register(CONTRACT_BIG_INT.class); + ByteArrayObjectUtil.init(); } diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index d74ea6bd..168065d7 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -46,7 +46,7 @@ public class SDK_Contract_Test { @Before public void init(){ - ledgerAddress = "j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7"; + ledgerAddress = "j5qHcS8jG6XwpE5wXv9HYMeGTb5Fs2gQao3TPQ3irqFpQL"; ledgerHash = getLedgerHash(); pubKey = SDK_GateWay_KeyPair_Para.pubKey0; privKey = SDK_GateWay_KeyPair_Para.privkey0; @@ -68,7 +68,7 @@ public class SDK_Contract_Test { public void demoContract1() { // 发起交易; TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - String contractAddress = "LdeNfBcbQWqVge1sVyLq3EHBJhMMjwQY3uJJE"; + String contractAddress = "LdeNm31KhQ4e76bVjCyhPc7QoTejU6Pig9mHW"; AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); TransactionContentBody transactionContentBody = new TransactionContentBody() { @Override diff --git a/source/sdk/sdk-samples/src/test/resources/contract.jar b/source/sdk/sdk-samples/src/test/resources/contract.jar index c96e32148a9e10caa00ba044c759389e29140337..8fb967493d7e30e2fe84a0d75ccf3130e7894aa8 100644 GIT binary patch delta 1621 zcmZXUdpHwn9LG0XL*}xJWtL+yvI@hfIE-A15mJgF2_-9YORjTwT&lBHk(v-i3?=Dt ztwo2q9hYuWi7;x+C6{tJn>x=qo%4JD_&)FZyzlRQ-|zE$Kg)PNQQCnF0&fI}iW6VO zkj63d@!4Q}(xKkvqe++(aLgM`9V25wnb3!o-Q_zz|X&_JY>Y#<2;7kx~>loq53 z1OOmn0Dv}txrW$A*VQ^sJr*2%{`W2$kdEB5Mrt+t%!(7=tS%LM#1S;azT>JXv7y;! z>NT~f_)P)MFRy&`iMSxI>9rR=X$wTX-PX6^y=_AS$pko%@7Qc6p91yauN>3~>5A;R zu%t2UcV?tE3ehic^D!S;EI~YzLO;+~@{ia3(CItt9Dwts$B%KK;iO%sli8!O9~OO1 z#s5+gH*eT+=#2u#qI&|ZWkA5;4dG*~qhrUcVo~PQrYuN_CZrDjuH-STrfhY`X88>x zF9?|!La_m-V{0d*ZOT%P>fmOpIBR7`GR>2ckZPTSRAOY9WgUGeF=H#2(5xQSe&3H-UdYnYKYaVgETJ? zpVIfVGW8d7hpv|Nd>i5ilW4|YodWG^{n>-=6ze#ZC9Z5#Jy))4^ej5!g|{VPE_2y5 z>SP~x4_^>;#Ti2G8Gi0w7Nr-UInRqGdDD!hQBNIsPBR^@^)>rSB}q^WxFYAg20M+L z<1l$)$ZVf}1GIF&w2^UTc+YsOa!@swo?skC*-m=3UE!^&p{`LsvlIN_@EKx2%PGqu zuflu_1x1h+OfMt)6u7@U)txlg%J7og*CCCS|5$4xEjA%}?));ZvZ38ICb>18M{#q! zq;AJ2>cNOUq``?tWd&C!DP>Fe>nbz6*kM!Z4UciKukX$_{%u! zo=YA>*F7eSCqX?vghKr0blN?}FA<> zEFH6(hT=MNTQ*p!F718ajBEa=Q(xZOUdZUqYFPt+voeFOuyLNTF}dE?V=)Q^j6P3^ zK+1B?{o=Lm1*LoAh$j0#gJl@EVUH|_vy#vOw;y`i5;I^@Z&Mt(>5lZARP>qN;H^#W z1Gkd86*?w+XFZwNPL8Ca`gBEA`k}i9)Yj!WS={PNg5{91i?nJ-sh+g;r_?~tG~MhY z7`C0-><%&ioC;L`d@#Dr;^H(|Cq4Ugo)%@Z+x)pgI|U=qaa2D3^IXwwegxPekDvAG zway6Dc~$vGLLh+e5g|$K6bA_r%M6DTe`YMR2ClzOtr@uXy5bPJ>*|6qUZ>bKgw?tZ zAzWbpgBa5mxf}H(Uk+rT7!o9+`TCtq6C_5=4J@J@GYN^piq8HVP!aaOS3z7URJ2j? mUvd3!yBuM=5n16bC8ocW49bDL0U|mqB^-tz06=MzX!aL6TFh(! delta 376 zcmaEB@<)?5z?+$civa|lhOL{(tHS#vY@OdZ>BfNRK%spT?PTls@--`nv^|{LQvHBU z!K^Uj&XtwEK31i?1;b{$@& zWBK|3>&+^KRV{sst)xr81S<32vTMF%_=Lr3^(>C!-?6g`Kg}up#(;1)Tj08hf908h z)MR-^B{1#6sLKrW$K(=5GZ4LbEu%dnn32ii%K>J5;x}h!2Ksoij<^Y`mnY|nn}Q8l zDy|QvuZtUjX&wn%u%SK@ZeV( Date: Thu, 23 May 2019 11:31:49 +0800 Subject: [PATCH 09/17] test pass for contract param serialize and deserialize. then clean; --- .../contract/ContractSerializeUtils.java | 115 ++++++------------ .../sdk/test/SDK_Contract_Test.java | 2 +- 2 files changed, 35 insertions(+), 82 deletions(-) diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index c68c84bc..898f8edf 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -2,24 +2,17 @@ package com.jd.blockchain.contract; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.ledger.*; -import com.jd.blockchain.utils.ArrayUtils; import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.io.ByteArray; -import com.jd.blockchain.utils.io.BytesUtils; import org.springframework.util.ReflectionUtils; -import org.springframework.util.SerializationUtils; import java.lang.annotation.Annotation; -import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.nio.ByteBuffer; -import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -27,9 +20,9 @@ import java.util.Map; * date 2019/5/16 18:05 */ public class ContractSerializeUtils { - public static Map> dataContractMap = new HashMap<>(); - public static final Class[] confirmedType = {CONTRACT_INT8.class,CONTRACT_INT16.class,CONTRACT_INT32.class,CONTRACT_INT64.class, - CONTRACT_TEXT.class,CONTRACT_BINARY.class,CONTRACT_BIG_INT.class}; + public static Map> DATA_CONTRACT_MAP = new HashMap<>(); + public static final Integer[] PRIMITIVE_TYPES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32, + DataCodes.CONTRACT_INT64, DataCodes.CONTRACT_BIG_INT,DataCodes.CONTRACT_TEXT, DataCodes.CONTRACT_BINARY }; /** * valid then parse the Object by Method params; @@ -38,6 +31,7 @@ public class ContractSerializeUtils { * @return */ public static byte[] serializeMethodParam(Object object,Method method) { + if (object == null) { return null; } @@ -60,7 +54,7 @@ public class ContractSerializeUtils { //check by annotation; Annotation[] annotationArr = annotations[i]; for(Annotation annotation : annotationArr){ - if(annotation.annotationType().equals(DataContract.class)){ + if(annotation instanceof DataContract){ dataContract = (DataContract) annotation; objArr[i] = regenObj(dataContract,objArr[i]); canPass = true; @@ -75,18 +69,17 @@ public class ContractSerializeUtils { sum += result[i].length; } /** - * //return is byte[], but now is byte[][], so we should reduct dimension, use the header info to the first byte(length=classTypes.length); - format:result[][]={{1,2,3},{4,5},{6,7}}; newResult[]=classTypes.length/first length/second length/3 length/result[0]/result[1]/result[2]; - rtnBytes[0]: 4 bytes(classTypes.length, <255); - rtnBytes[1]: 4 bytes(each param's length, ) - rtnBytes[2]: 4 bytes(each param's length, ) - rtnBytes[3]: 4 bytes(each param's length, ) - rtnBytes[4...]: result[0][] bytes(each param's length) - rtnBytes[5...]: result[1][] bytes(each param's length) - rtnBytes[6...]: result[2][] bytes(each param's length) + return is byte[], but now is byte[][], so we should reduct dimension by adding the header info to the rtnBytes[]; + rtnBytes[]=classTypes.length/first length/second length/third length/result[0]/result[1]/result[2]; + rtnBytes[0]: 4 bytes(classTypes.length); + rtnBytes[1]: 4 bytes(1 param's length); + rtnBytes[2]: 4 bytes(2 param's length); + rtnBytes[3]: 4 bytes(3 param's length); + rtnBytes[...]: result[0][] bytes(1 param's length); + rtnBytes[...]: result[1][] bytes(2 param's length); + rtnBytes[...]: result[2][] bytes(3 param's length); */ - - int bodyFirstPosition = 4 + 4*(classTypes.length); + int bodyFirstPosition = 4 + 4 * (classTypes.length); ByteBuffer byteBuffer = ByteBuffer.allocate(bodyFirstPosition + sum); byteBuffer.putInt(classTypes.length); for(int j=0; j Map > getDataIntf(){ - dataContractMap.put(DataCodes.CONTRACT_INT8, CONTRACT_INT8.class); - dataContractMap.put(DataCodes.CONTRACT_INT16, CONTRACT_INT16.class); - dataContractMap.put(DataCodes.CONTRACT_INT32, CONTRACT_INT32.class); - dataContractMap.put(DataCodes.CONTRACT_INT64, CONTRACT_INT64.class); - dataContractMap.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class); - dataContractMap.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class); - dataContractMap.put(DataCodes.CONTRACT_BIG_INT, CONTRACT_BIG_INT.class); - dataContractMap.put(DataCodes.TX_CONTENT_BODY, TransactionContentBody.class); - return dataContractMap; + DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT8, CONTRACT_INT8.class); + DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT16, CONTRACT_INT16.class); + DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT32, CONTRACT_INT32.class); + DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT64, CONTRACT_INT64.class); + DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class); + DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class); + DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIG_INT, CONTRACT_BIG_INT.class); + DATA_CONTRACT_MAP.put(DataCodes.TX_CONTENT_BODY, TransactionContentBody.class); + return DATA_CONTRACT_MAP; } public static boolean isPrimitiveType(int dataContractCode){ - return (dataContractCode == DataCodes.CONTRACT_INT8 || - dataContractCode == DataCodes.CONTRACT_INT16 || - dataContractCode == DataCodes.CONTRACT_INT32 || - dataContractCode == DataCodes.CONTRACT_INT64 || - dataContractCode == DataCodes.CONTRACT_TEXT - ); + return Arrays.asList(PRIMITIVE_TYPES).contains(dataContractCode); } private static Object regenObj(DataContract dataContract, Object object){ if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT8.class)){ - return new CONTRACT_INT8() { - @Override - public Byte getValue() { - return Byte.parseByte(object.toString()); - } - }; + return (CONTRACT_INT8) () -> Byte.parseByte(object.toString()); }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT16.class)){ - return new CONTRACT_INT16() { - @Override - public short getValue() { - return Short.parseShort(object.toString()); - } - }; + return (CONTRACT_INT16) () -> Short.parseShort(object.toString()); }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT32.class)){ - return new CONTRACT_INT32() { - @Override - public int getValue() { - return Integer.parseInt(object.toString()); - } - }; + return (CONTRACT_INT32) () -> Integer.parseInt(object.toString()); }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT64.class)){ - return new CONTRACT_INT64() { - @Override - public long getValue() { - return Long.parseLong(object.toString()); - } - }; + return (CONTRACT_INT64) () -> Long.parseLong(object.toString()); }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_TEXT.class)){ - return new CONTRACT_TEXT() { - @Override - public String getValue() { - return object.toString(); - } - }; + return (CONTRACT_TEXT) () -> object.toString(); }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BINARY.class)){ - return new CONTRACT_BINARY() { - @Override - public Bytes getValue() { - return (Bytes) object; - } - }; + return (CONTRACT_BINARY) () -> (Bytes) object; }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BIG_INT.class)){ - return new CONTRACT_BIG_INT() { - @Override - public BigDecimal getValue() { - return new BigDecimal(object.toString()); - } - }; + return (CONTRACT_BIG_INT) () -> new BigDecimal(object.toString()); } return null; } diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index 168065d7..797e93ae 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -68,7 +68,7 @@ public class SDK_Contract_Test { public void demoContract1() { // 发起交易; TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - String contractAddress = "LdeNm31KhQ4e76bVjCyhPc7QoTejU6Pig9mHW"; + String contractAddress = "LdeP3W9d3xy9bLktWqEhkFWv2Zru7YmQyuu6M"; AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); TransactionContentBody transactionContentBody = new TransactionContentBody() { @Override From 5eb467b8d57f6894bb601a908ba5ec1d245637e8 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Thu, 23 May 2019 17:47:17 +0800 Subject: [PATCH 10/17] test pass for contract param serialize and deserialize. then clean; --- .../contract/ContractSerializeUtils.java | 16 ++++++- .../blockchain/transaction/ContractType.java | 46 ++++++++----------- .../contract/samples/AssetContract2.java | 19 +++++++- .../contract/samples/AssetContractImpl2.java | 17 +++++++ .../sdk/test/SDK_Contract_Test.java | 6 ++- 5 files changed, 73 insertions(+), 31 deletions(-) diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index 898f8edf..a0670648 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -49,6 +49,7 @@ public class ContractSerializeUtils { for(int i=0;i classType = classTypes[i]; DataContract dataContract = classType.getDeclaredAnnotation(DataContract.class); + //if the param's class Type don't contain @DataContract, then check parameterAnnotations of this method. if(dataContract == null){ boolean canPass = false; //check by annotation; @@ -60,15 +61,21 @@ public class ContractSerializeUtils { canPass = true; } } + //if parameterAnnotations don't contain @DataContract, we will say goodbye. if(!canPass){ - throw new IllegalArgumentException("must set annotation in each param of contract."); + throw new IllegalArgumentException("must set @DataContract for each param of contract."); } } + if(!getDataIntf().containsKey(dataContract.code())){ + throw new IllegalArgumentException(String.format( + "for now, this @dataContract(code=%s) is forbidden in the param list.",dataContract.code())); + } //get data interface; result[i] = BinaryProtocol.encode(objArr[i],getDataIntf().get(dataContract.code())); sum += result[i].length; } /** + * return byte[] format: return is byte[], but now is byte[][], so we should reduct dimension by adding the header info to the rtnBytes[]; rtnBytes[]=classTypes.length/first length/second length/third length/result[0]/result[1]/result[2]; rtnBytes[0]: 4 bytes(classTypes.length); @@ -138,6 +145,11 @@ public class ContractSerializeUtils { ByteBuffer byteBuffer1 = ByteBuffer.allocate(curParamLength); byteBuffer1.put(params,offsetPosition,curParamLength); offsetPosition += curParamLength; + + if(!getDataIntf().containsKey(dataContract.code())){ + throw new IllegalArgumentException(String.format( + "for now, this @dataContract(code=%s) is forbidden in the param list.",dataContract.code())); + } //if dataContract=primitive type(byte/short/int/long/String),only use its getValues(); Object object = BinaryProtocol.decodeAs(byteBuffer1.array(), getDataIntf().get(dataContract.code())); @@ -166,7 +178,7 @@ public class ContractSerializeUtils { DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class); DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class); DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIG_INT, CONTRACT_BIG_INT.class); - DATA_CONTRACT_MAP.put(DataCodes.TX_CONTENT_BODY, TransactionContentBody.class); +// DATA_CONTRACT_MAP.put(DataCodes.TX_CONTENT_BODY, TransactionContentBody.class); return DATA_CONTRACT_MAP; } 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 afaab56e..1bb3e7c8 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,7 +4,6 @@ import com.jd.blockchain.contract.ContractEvent; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.utils.BaseConstant; -import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.*; @@ -52,33 +51,28 @@ public class ContractType { private ContractType() { } - public static ContractType resolve(Class contractIntf) { + public static ContractType resolve(Class contractIntf){ ContractType contractType = new ContractType(); //contractIntf contains @Contract and @ContractEvent; - Method[] classMethods = contractIntf.getMethods(); - Map methodAnnoMap = new HashMap(); - for (int i = 0; i < classMethods.length; i++) { - Annotation[] a = classMethods[i].getDeclaredAnnotations(); - methodAnnoMap.put(classMethods[i], a); - // if current method contains @ContractEvent,then put it in this map; - for (Annotation annotation_ : a) { - if (classMethods[i].isAnnotationPresent(ContractEvent.class)) { - Object obj = classMethods[i].getAnnotation(ContractEvent.class); - 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); - //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! - if(contractType.events.containsKey(eventName_)){ - throw new ContractException("too many same eventNames exists in the contract, check it."); - } - contractType.events.put(eventName_, classMethods[i]); - contractType.handleMethods.put(classMethods[i],eventName_); - } - } - } - return contractType; - } + Method[] classMethods = contractIntf.getDeclaredMethods(); + for (Method method : classMethods) { + // if current method contains @ContractEvent,then put it in this map; + if (method.isAnnotationPresent(ContractEvent.class)) { + Object obj = method.getAnnotation(ContractEvent.class); + 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); + //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! + if(contractType.events.containsKey(eventName_)){ + throw new ContractException("too many same eventNames exists in the contract, check it."); + } + contractType.events.put(eventName_, method); + contractType.handleMethods.put(method,eventName_); + } + } + return contractType; + } @Override public String toString() { diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java index 24fcc598..2a8ff282 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java @@ -6,6 +6,7 @@ import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEvent; import com.jd.blockchain.ledger.CONTRACT_TEXT; import com.jd.blockchain.ledger.TransactionContentBody; +import com.jd.blockchain.utils.Bytes; /** * 示例:一个“资产管理”智能合约; @@ -21,7 +22,23 @@ public interface AssetContract2 { * @param assetHolderAddress * 新发行的资产的持有账户; */ - @ContractEvent(name = "issue-asset") + @ContractEvent(name = "issue-asset-0") void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress); + + /** + * issue asset; + * @param transactionContentBody + * @param assetHolderAddress + * @param cashNumber + */ + @ContractEvent(name = "issue-asset") + public void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, + @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, + @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); + + @ContractEvent(name = "issue-asset-2") + void issue(@DataContract(code = DataCodes.CONTRACT_BINARY) Bytes bytes, + @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, + @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); } \ No newline at end of file diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java index a6c2b157..66b422fe 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java @@ -1,5 +1,8 @@ package com.jd.blockchain.contract.samples; +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.consts.DataCodes; +import com.jd.blockchain.contract.ContractEvent; import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.contract.EventProcessingAwire; @@ -8,6 +11,7 @@ import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.KVDataEntry; import com.jd.blockchain.ledger.KVDataObject; import com.jd.blockchain.ledger.TransactionContentBody; +import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.io.BytesUtils; import java.util.HashMap; @@ -32,6 +36,19 @@ public class AssetContractImpl2 implements EventProcessingAwire, AssetContract2 System.out.println(transactionContentBody.toString()); } + @Override + @ContractEvent(name = "issue-asset") + public void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, + @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, + @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber) { + System.out.println(transactionContentBody.toString()+",address="+assetHolderAddress+",cashNumber="+cashNumber); + } + + @Override + public void issue(Bytes bytes, String assetHolderAddress, long cashNumber) { + + } + /* * (non-Javadoc) * diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index 797e93ae..e9f3f373 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -68,7 +68,7 @@ public class SDK_Contract_Test { public void demoContract1() { // 发起交易; TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - String contractAddress = "LdeP3W9d3xy9bLktWqEhkFWv2Zru7YmQyuu6M"; + String contractAddress = "LdeNvwqrHKCDtEVv5m3nQSpJ66ahds2E7FtnV"; AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); TransactionContentBody transactionContentBody = new TransactionContentBody() { @Override @@ -81,7 +81,9 @@ public class SDK_Contract_Test { return new Operation[0]; } }; - assetContract.issue(transactionContentBody,contractAddress); +// assetContract.issue(transactionContentBody,contractAddress); +// assetContract.issue(transactionContentBody,contractAddress,888888); + assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,999999); // TX 准备就绪; PreparedTransaction prepTx = txTemp.prepare(); From 48c3ac91873dc7eead0f4c7f099fe64be72fd32b Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Thu, 23 May 2019 17:48:20 +0800 Subject: [PATCH 11/17] update the contract.jar; --- .../src/test/resources/contract.jar | Bin 6765 -> 7407 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/source/sdk/sdk-samples/src/test/resources/contract.jar b/source/sdk/sdk-samples/src/test/resources/contract.jar index 8fb967493d7e30e2fe84a0d75ccf3130e7894aa8..437022505ab92b5c2ef6100ee8d5cb79131287dd 100644 GIT binary patch delta 1997 zcmY+Fc{J4PAIE3LHvCK&^J9h?l$kbkH%Wf$rPb0Ob_(yJGE;8mRC%0~{=4~H3h=pys zwdqC=5M^f1=X+WaI`8?HHkD5Rs7mERFbhBO#JTO#cJZk{zH6kBk|NF^d&Ow@)0cl^ z$v|2)aq(=a!=Ym*4&pNCRDEFQOCY3QEc{YgXr=5`(y4@xW|ArbN+22 ziPUR#I?+qZ=^xS64E;!JVJ9kX_(utyf!8I(o+*cl`oB`u2aNL%5C+hy z)(WEzl8awzpc-ZFyzy>%l3^$sA_NdHb_RdlQxiFOmYhTzk`JDoR^o@hJ0UhXX95pb z9(%uhoN?I0O@OrW$DKx3DaX%(Z=^1tuxG26>6tn-CpxNim_mnL1pU;&w^u-S0zAAR zVWx4cB}f$H7dZjwF1jjjerxC+qpL*U8D#+w=&L9Qr2UH#!9U3F7bjALqpSnshtXpq z)NZ6tpoD$7GCS_IcO|vZUf31XA7h<(Ab{0=SQM)rEG1Rjux0X{|C)~fVz1b{TdTB5 zPbkY%X8!0-+Q!6K{Zcp(-u->MM;-vz-N<9kwYuofuGGXu!6mwIL8m^2<5bt&B$lwj zfLJ^hJ0?9XL{Oa?=b!l4(nk;g9Q-?*0AcuF`*RmYfcGW{&k6t66td<){? zz|H1&@~p_Yfwmrh&da(Mb;l;`f&cG@ zPg_2y46YhDG3IL);f-wjwm~g*_EoF;z!JK3IJJLyPR8by>LPJ=Xwce0xvZtsHb`}x zoQrstVwgWNr8)0+Bg#SGgHx5u^c!l4XYi;Ln4;aK5!9oL=5RBq=N}{xW$D0tF(mbf z=Xx#-a$CkHemb}@u`|mH_=M&KY3~&Hq-EpFW9X0f({DHAI~zK5Qi<>B3&l^@(&LG5GMoYK(lr=Ct@$Lj`-K6k6-0(W2H_M7|qc zS!Tb!ZIXnHB(FN9ob%tjwE3%S`_G5zc!^pQy+GFM|}fDmd!_iel0aoi#72mer1-tG`#OYk~uN6bc4+4q}n+Z zAq?(7ACg{9-UOW4S7X0ptl~vS^wRPc+s_&wOBO#ptP;M;Sa72mrSB_q%68Y`#dW}< z(?{K77@zPArp@NY0DHWZqQYSoCZA^iX;yg%UG*8l>$QLC;rZUuG7ec(N>hzWCh4eYReN1aCU+Fl!GZpk3JC!C=E)f>+;5U?=RRgXS~n;NpSkNv*#G&=m6%Lurxsz53dNFl)0&Q@2AbvcwbAJPNb`*9*10h}vue%GFNYTa zUkmT;H`t!YDh%Yd1ak``dLMk#E-*tV@l)g!Y<`=3y@e1G=)}WrgL8RUG&?_~=DA|E zXY-Vj8eSLe8(KUR;+Bwuy8oy{qNhX@1stq`JrMc1pW97Sg)`>^5+fatZ_pKcLVJua zd_A7KW)!OYRMU8Wbn6UI034mh71A@6#NyvmYAVpO*J5sRC3BzzOFCRj=A9g|O_!*P zGs`ipzZf{PGaFL>BHsH2{E=i4h~Z@coC-W#nfT`rE@gP7ffP#~EAu_qe6-7IlU!9K zxl%!fl9DT~KpcjWaW?uvlCE+KYVx66o=Ie0mtaDrAo7dC!ppEx{{hymlVifwGQQO# z{%3sGFaEOHf1GwzOkZd(9#y4vcH@%eAw9d-6Ok5sH67`+@84<3`i?xaH?l#=LUQ?8 zU~$ZDbh6S>QVP4ue|h#^8vk<5$`!@sT Bm>mEB delta 1335 zcmaEF`PPItz?+$civa`aqmH8OJgIO0h8UKdufEjx zQ{!=F-qYPR!nZ!eq&h$Sv0C^Tx8xR6+3Y5xhv(8hhvloJH9bGXQ)zEepWC+fS;NC0 zsaZ{Os~f*roejM$A?46`G1XQ@w64||9#e!)wGe+;^7hOI-Jxdl+<-f)_I#$u*%!b-RO7c!I$ZO9BMMIoN{{mp=fFtoA;&1S7X=J80YJL zdr@njQegd2>~O$~;7@0x_U`gn!)ebW&9Y%$ug2Q0Q}Y7e^*wU*Fx|(q=8nVuiBlgt zy=;&#+J36O*|t1d+x~{O#9d`8BkNm}&#`O?&ojwCk>$D~Y3U*t2`OehLF1m;Bl5$LG;OPJ6@(&oE5!)UTofXCaSLOWcQ2cn7~PDzHd#81x-@zAH3SJ zZppNF(d&L{&Q|>NqT#Va&YZZHEP>OGrmt)fJ+wijRAFxQiTWG!SDg;nu5c>6{l%&W zCxlBkr+d#3@bWxrP`)+jRr|Xuu?pV#r`tXq*_B^a_oc}B{LFJF6q>X7!i*}~o=fgI z;LYC36Zf!`E%S@vnYfpe40z^zzkU2uXeDeG5n&AG?YwlGKURo$H)jg*2{X<@t^meQqj z4ISrOu^WC-Vs%sg>3;vH%F!o=d)Hq+vvlIc87Ka;{C0EX`MXvnp`mU;%IpSdi6s-S zBybc)|CzUG<^PM{WjDSQKH`6&m~Y}T!5yxTXS7P@FWZ*jW6~qYeYZXERCi$gyiUoy z%f;$PV(%<&y(n?^-Q~{-lNHV#;*?VRxM6E|=qj_ElYhSOtNgoe;QB~Dl2`fc8e?A1 z*PVq4T}HDaq}TeYe%4{ip0`2l*0*BG(=PoVSq!^pnmJi)k>;B( zE0(>jVsTmccE*jHhEH?C{>ejg2pa<=i3g z Date: Fri, 24 May 2019 18:51:00 +0800 Subject: [PATCH 12/17] The judgment of annotations to contract parameters is removed. Now you don't have to fill in parameter annotations in the interface. The primitive data types are automatically mapped in the background. --- .../contract/jvm/JavaContractCode.java | 10 ++- .../contract/ContractSerializeUtils.java | 70 +++++++++++---- .../contract/samples/AssetContract2.java | 17 +++- .../contract/samples/AssetContractImpl2.java | 85 ------------------- .../sdk/test/SDK_Contract_Test.java | 7 +- 5 files changed, 78 insertions(+), 111 deletions(-) delete mode 100644 source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java 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 e1697b8b..854e23b7 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 @@ -1,11 +1,12 @@ package com.jd.blockchain.contract.jvm; import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.contract.engine.ContractCode; import com.jd.blockchain.runtime.Module; import com.jd.blockchain.transaction.ContractType; import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.contract.ContractSerializeUtils; +import com.jd.blockchain.utils.IllegalDataException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ReflectionUtils; @@ -73,6 +74,9 @@ public class JavaContractCode implements ContractCode { // 反序列化参数; Method handleMethod = ContractType.resolve(myClass).getHandleMethod(contractEventContext.getEvent()); + if (handleMethod == null){ + throw new IllegalDataException("don't get this method by it's @ContractEvent."); + } Object args = resolveArgs(contractEventContext.getArgs(), handleMethod); Object[] params = null; @@ -88,9 +92,9 @@ public class JavaContractCode implements ContractCode { ReflectionUtils.invokeMethod(mth2, contractMainClassObj); LOGGER.info("postEvent,耗时:" + (System.currentTimeMillis() - startTime)); } catch (NoSuchMethodException e) { - e.printStackTrace(); + throw new IllegalArgumentException(e.getMessage()); } catch (Exception e) { - e.printStackTrace(); + throw new IllegalDataException(e.getMessage()); } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index a0670648..0e650415 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -21,9 +21,10 @@ import java.util.Map; */ public class ContractSerializeUtils { public static Map> DATA_CONTRACT_MAP = new HashMap<>(); - public static final Integer[] PRIMITIVE_TYPES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32, + public static final Integer[] PRIMITIVE_DATA_CODES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32, DataCodes.CONTRACT_INT64, DataCodes.CONTRACT_BIG_INT,DataCodes.CONTRACT_TEXT, DataCodes.CONTRACT_BINARY }; + /** * valid then parse the Object by Method params; * @param object @@ -31,7 +32,6 @@ public class ContractSerializeUtils { * @return */ public static byte[] serializeMethodParam(Object object,Method method) { - if (object == null) { return null; } @@ -53,15 +53,21 @@ public class ContractSerializeUtils { if(dataContract == null){ boolean canPass = false; //check by annotation; - Annotation[] annotationArr = annotations[i]; - for(Annotation annotation : annotationArr){ - if(annotation instanceof DataContract){ - dataContract = (DataContract) annotation; - objArr[i] = regenObj(dataContract,objArr[i]); - canPass = true; - } +// Annotation[] annotationArr = annotations[i]; +// for(Annotation annotation : annotationArr){ +// if(annotation instanceof DataContract){ +// dataContract = (DataContract) annotation; +// objArr[i] = regenObj(dataContract,objArr[i]); +// canPass = true; +// } +// } + //if parameterAnnotations don't contain @DataContract, is it primitive type? + Class contractType = getContractTypeByPrimitiveType(classType); + dataContract = contractType.getDeclaredAnnotation(DataContract.class); + if(dataContract != null){ + objArr[i] = regenObj(dataContract,objArr[i]); + canPass = true; } - //if parameterAnnotations don't contain @DataContract, we will say goodbye. if(!canPass){ throw new IllegalArgumentException("must set @DataContract for each param of contract."); } @@ -131,12 +137,18 @@ public class ContractSerializeUtils { if(dataContract == null){ boolean canPass = false; //check by annotation; - Annotation[] annotationArr = annotations[i]; - for(Annotation annotation : annotationArr){ - if(annotation.annotationType().equals(DataContract.class)){ - dataContract = (DataContract) annotation; - canPass = true; - } +// Annotation[] annotationArr = annotations[i]; +// for(Annotation annotation : annotationArr){ +// if(annotation.annotationType().equals(DataContract.class)){ +// dataContract = (DataContract) annotation; +// canPass = true; +// } +// } + //if parameterAnnotations don't contain @DataContract, is it primitive type? + Class contractType = getContractTypeByPrimitiveType(classType); + dataContract = contractType.getDeclaredAnnotation(DataContract.class); + if(dataContract != null){ + canPass = true; } if(!canPass){ throw new IllegalArgumentException("must set annotation in each param of contract."); @@ -183,7 +195,7 @@ public class ContractSerializeUtils { } public static boolean isPrimitiveType(int dataContractCode){ - return Arrays.asList(PRIMITIVE_TYPES).contains(dataContractCode); + return Arrays.asList(PRIMITIVE_DATA_CODES).contains(dataContractCode); } private static Object regenObj(DataContract dataContract, Object object){ @@ -204,4 +216,28 @@ public class ContractSerializeUtils { } return null; } + + /** + * get contractType(contain @DataContract) by primitive class type; + * some class type can be supported default (byte/char/int/long/String/Bytes, and so on). + * in other words, need not contain the @DataContract in its class for contract param's serialization or deserialization. + * @param classType + * @return + */ + private static Class getContractTypeByPrimitiveType(Class classType) { + if(classType.equals(byte.class) || classType.equals(Byte.class)){ + return CONTRACT_INT8.class; + }else if(classType.equals(char.class) || classType.equals(Character.class)){ + return CONTRACT_INT16.class; + }else if(classType.equals(int.class) || classType.equals(Integer.class)){ + return CONTRACT_INT32.class; + }else if(classType.equals(long.class) || classType.equals(Long.class)){ + return CONTRACT_INT64.class; + }else if(classType.equals(String.class)){ + return CONTRACT_TEXT.class; + }else if(classType.equals(Bytes.class)){ + return CONTRACT_BINARY.class; + } + return null; + } } diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java index 2a8ff282..8bb2256e 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java @@ -4,7 +4,6 @@ import com.jd.blockchain.binaryproto.DataContract; import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEvent; -import com.jd.blockchain.ledger.CONTRACT_TEXT; import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.utils.Bytes; @@ -37,8 +36,18 @@ public interface AssetContract2 { @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); + /** + * Bytes can bring the byte[]; + * @param bytes + * @param assetHolderAddress + * @param cashNumber + */ @ContractEvent(name = "issue-asset-2") - void issue(@DataContract(code = DataCodes.CONTRACT_BINARY) Bytes bytes, - @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, - @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); + void issue(Bytes bytes,String assetHolderAddress, long cashNumber); + + @ContractEvent(name = "issue-asset-3") + void issue(Byte bytes, String assetHolderAddress, long cashNumber); + + @ContractEvent(name = "issue-asset-4") + void issue1(byte[] bytes, String assetHolderAddress, long cashNumber); } \ No newline at end of file diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java deleted file mode 100644 index 66b422fe..00000000 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl2.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.jd.blockchain.contract.samples; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.consts.DataCodes; -import com.jd.blockchain.contract.ContractEvent; -import com.jd.blockchain.contract.ContractEventContext; -import com.jd.blockchain.contract.ContractException; -import com.jd.blockchain.contract.EventProcessingAwire; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; -import com.jd.blockchain.ledger.TransactionContentBody; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.io.BytesUtils; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * 示例:一个“资产管理”智能合约的实现; - * - * 注: 1、实现 EventProcessingAwire 接口以便合约实例在运行时可以从上下文获得合约生命周期事件的通知; 2、实现 - * AssetContract 接口定义的合约方法; - * - * @author huanghaiquan - * - */ -public class AssetContractImpl2 implements EventProcessingAwire, AssetContract2 { - // 合约事件上下文; - private ContractEventContext eventContext; - - @Override - public void issue(TransactionContentBody transactionContentBody, String assetHolderAddress) { - System.out.println(transactionContentBody.toString()); - } - - @Override - @ContractEvent(name = "issue-asset") - public void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, - @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, - @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber) { - System.out.println(transactionContentBody.toString()+",address="+assetHolderAddress+",cashNumber="+cashNumber); - } - - @Override - public void issue(Bytes bytes, String assetHolderAddress, long cashNumber) { - - } - - /* - * (non-Javadoc) - * - * @see - * com.jd.blockchain.contract.model.EventProcessingAwire#beforeEvent(com.jd. - * blockchain.contract.model.ContractEventContext) - */ - @Override - public void beforeEvent(ContractEventContext eventContext) { - this.eventContext = eventContext; - } - - /* - * (non-Javadoc) - * - * @see com.jd.blockchain.contract.model.EventProcessingAwire#postEvent(com.jd. - * blockchain.contract.model.ContractEventContext, - * com.jd.blockchain.contract.model.ContractError) - */ - @Override - public void postEvent(ContractEventContext eventContext, ContractException error) { - this.eventContext = null; - } - - @Override - public void postEvent(ContractException error) { - - } - - @Override - public void postEvent() { - - } -} diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index e9f3f373..cc160bf3 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -68,7 +68,7 @@ public class SDK_Contract_Test { public void demoContract1() { // 发起交易; TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - String contractAddress = "LdeNvwqrHKCDtEVv5m3nQSpJ66ahds2E7FtnV"; + String contractAddress = "LdeNmSdtUqVfURfcVxmJda252HC4FYHYfGTQv"; AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); TransactionContentBody transactionContentBody = new TransactionContentBody() { @Override @@ -83,7 +83,10 @@ public class SDK_Contract_Test { }; // assetContract.issue(transactionContentBody,contractAddress); // assetContract.issue(transactionContentBody,contractAddress,888888); - assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,999999); +// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); +// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); + Byte byteObj = Byte.parseByte("127"); + assetContract.issue(byteObj,contractAddress,321123); // TX 准备就绪; PreparedTransaction prepTx = txTemp.prepare(); From 7a073f64f150a1f4c712de50ea2a8393ff82f3d0 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Mon, 27 May 2019 15:05:55 +0800 Subject: [PATCH 13/17] According to Haiquan's suggestion to modify the codes for improving the performance. must admit: these proposals are very valuable. --- .../contract/ContractSerializeUtils.java | 1 - .../transaction/ContractInvocationProxy.java | 10 +++--- .../ContractInvocationProxyBuilder.java | 35 ++++++++++--------- .../blockchain/transaction/ContractType.java | 16 ++++----- .../sdk/test/SDK_Contract_Test.java | 2 +- .../com/jd/blockchain/utils/BaseConstant.java | 2 +- 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index 0e650415..474a1838 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -42,7 +42,6 @@ public class ContractSerializeUtils { } Class[] classTypes = method.getParameterTypes(); - Annotation [][] annotations = method.getParameterAnnotations(); byte[][] result = new byte[classTypes.length][]; //将method中形参转换为实体对象,每个形参都必须为@DataContract类型;每个形参使用系统的BinaryProtocol来进行序列化,如果有5个参数,则使用5次序列化; int sum = 0; 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 542e31f5..a5a3fd09 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 @@ -2,6 +2,8 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.IllegalDataException; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -18,17 +20,15 @@ public class ContractInvocationProxy implements InvocationHandler { public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, ContractEventSendOperationBuilder sendOpBuilder) { this.contractAddress = contractAddress; + if(contractType == null){ + throw new IllegalDataException("contractType == null, no invoke really."); + } this.contractType = contractType; this.sendOpBuilder = sendOpBuilder; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - - if(contractType == null){ - return "contractType == null, no invoke really."; - } - String event = contractType.getEvent(method); if (event == null) { // 适配 Object 对象的方法; 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 90032a9f..4bf825b7 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 @@ -4,16 +4,18 @@ import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEvent; import com.jd.blockchain.utils.BaseConstant; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.IllegalDataException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class ContractInvocationProxyBuilder { - private Map, ContractType> contractTypes = new HashMap, ContractType>(); + private Map, ContractType> contractTypes = new ConcurrentHashMap<>(); public T create(String address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); @@ -39,12 +41,12 @@ public class ContractInvocationProxyBuilder { // 判断是否是标注了合约的接口类型; if (!isContractType(contractIntf)){ - return null; + throw new IllegalDataException("is not Contract Type, becaust there is not @Contract."); } // 解析合约事件处理方法,检查是否有重名; if(!isUniqueEvent(contractIntf)){ - return null; + throw new IllegalDataException("there is repeat definition of contractEvent to @ContractEvent."); } // TODO 检查是否不支持的参数类型; @@ -63,22 +65,21 @@ public class ContractInvocationProxyBuilder { Map methodAnnoMap = new HashMap(); Map annoMethodMap = new HashMap(); for (int i = 0; i < classMethods.length; i++) { - Annotation[] a = classMethods[i].getDeclaredAnnotations(); - methodAnnoMap.put(classMethods[i], a); + Annotation[] annotations = classMethods[i].getDeclaredAnnotations(); + methodAnnoMap.put(classMethods[i], annotations); // if current method contains @ContractEvent,then put it in this map; - for (Annotation annotation_ : a) { - if (classMethods[i].isAnnotationPresent(ContractEvent.class)) { - Object obj = classMethods[i].getAnnotation(ContractEvent.class); - 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); - //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! - if(annoMethodMap.containsKey(eventName_)){ - isUnique = false; - } - annoMethodMap.put(eventName_, classMethods[i]); + Method curMethod = classMethods[i]; + ContractEvent contractEvent = curMethod.getAnnotation(ContractEvent.class); + if (contractEvent != null) { + Object obj = classMethods[i].getAnnotation(ContractEvent.class); + String annoAllName = obj.toString(); + // format:@com.jd.blockchain.contract.model.ContractEvent(name=transfer-asset) + String eventName_ = contractEvent.name(); + //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! + if(annoMethodMap.containsKey(eventName_)){ + isUnique = false; } + annoMethodMap.put(eventName_, classMethods[i]); } } 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 1bb3e7c8..97424e48 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 @@ -2,16 +2,17 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.contract.ContractEvent; import com.jd.blockchain.contract.ContractException; -import com.jd.blockchain.utils.BaseConstant; import java.lang.reflect.Method; -import java.util.*; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; public class ContractType { private String name; - private SortedMap events = Collections.synchronizedSortedMap(new TreeMap<>()); + private Map events = new HashMap<>(); private Map handleMethods = new HashMap<>();; @@ -57,12 +58,9 @@ public class ContractType { Method[] classMethods = contractIntf.getDeclaredMethods(); for (Method method : classMethods) { // if current method contains @ContractEvent,then put it in this map; - if (method.isAnnotationPresent(ContractEvent.class)) { - Object obj = method.getAnnotation(ContractEvent.class); - 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); + ContractEvent contractEvent = method.getAnnotation(ContractEvent.class); + if (contractEvent != null) { + String eventName_ = contractEvent.name(); //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! if(contractType.events.containsKey(eventName_)){ throw new ContractException("too many same eventNames exists in the contract, check it."); diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index cc160bf3..b2aa577d 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -68,7 +68,7 @@ public class SDK_Contract_Test { public void demoContract1() { // 发起交易; TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - String contractAddress = "LdeNmSdtUqVfURfcVxmJda252HC4FYHYfGTQv"; + String contractAddress = "LdeNw7PsVrXTrffQMfYLTvqscDyQ8QCUPruTS"; AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); TransactionContentBody transactionContentBody = new TransactionContentBody() { @Override diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java index 6e3aeb8c..4548dbad 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java @@ -22,7 +22,7 @@ public class BaseConstant { public static final String SYS_CONTRACT_PROPS_NAME = "sys-contract.properties"; public static final String CONTRACT_MAIN_CLASS_KEY = "contract"; - public static final String CONTRACT_EVENT_PREFIX="@com.jd.blockchain.contract.ContractEvent(name="; +// public static final String CONTRACT_EVENT_PREFIX="@com.jd.blockchain.contract.ContractEvent(name="; // 编译时引用包黑名单 public static final String PACKAGE_BLACKLIST = "BLACKLIST"; From b8dff42d04373b70e1e4aa6703c8af0d53ba87e8 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Tue, 28 May 2019 17:30:02 +0800 Subject: [PATCH 14/17] reduce the invoke of reflection to improve the performance. --- .../com/jd/blockchain/consts/DataCodes.java | 2 + .../jd/blockchain/binaryproto/DataType.java | 2 +- .../contract/jvm/JavaContractCode.java | 53 ++----- .../contract/ContractSerializeUtils.java | 132 ++++++------------ .../blockchain/ledger/ContractBizContent.java | 30 ++++ .../transaction/ContractInvocationProxy.java | 5 +- .../ContractInvocationProxyBuilder.java | 40 ------ .../blockchain/transaction/ContractType.java | 40 +++++- .../sdk/test/SDK_Contract_Test.java | 2 +- .../jd/blockchain/intgr/IntegrationBase.java | 23 ++- .../intgr/contract/AssetContract2.java | 53 +++++++ .../src/test/resources/contract.jar | Bin 5602 -> 7648 bytes 12 files changed, 188 insertions(+), 194 deletions(-) create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java create mode 100644 source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java diff --git a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java index 9d069903..a7382d0a 100644 --- a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java +++ b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java @@ -88,6 +88,8 @@ public interface DataCodes { public static final int CONTRACT_TEXT = 0xA05; public static final int CONTRACT_BINARY = 0xA06; public static final int CONTRACT_BIG_INT = 0xA07; + //...0xA19 + public static final int CONTRACT_BIZ_CONTENT = 0xA20; public static final int HASH = 0xB00; diff --git a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java index 9df9f7bd..1129518b 100644 --- a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java +++ b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java @@ -7,7 +7,7 @@ public interface DataType { */ public static final byte NIL = (byte) 0x00; - /** + /**LdeNhjPGzHcHL6rLcJ7whHxUbn9Tv7qSKRfEA * 布尔; */ public static final byte BOOLEAN = (byte) 0x01; 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 854e23b7..6bf5e859 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 @@ -1,5 +1,6 @@ package com.jd.blockchain.contract.jvm; +import com.jd.blockchain.binaryproto.DataContract; import com.jd.blockchain.contract.ContractEventContext; import com.jd.blockchain.contract.ContractSerializeUtils; import com.jd.blockchain.contract.engine.ContractCode; @@ -12,6 +13,7 @@ import org.slf4j.LoggerFactory; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; +import java.util.List; /** * contract code based jvm @@ -25,7 +27,7 @@ public class JavaContractCode implements ContractCode { private long version; private ContractEventContext contractEventContext; - private ContractType contractType ; + private ContractType contractType; public JavaContractCode(Bytes address, long version, Module codeModule) { this.address = address; @@ -49,8 +51,11 @@ public class JavaContractCode implements ContractCode { codeModule.execute(new ContractExecution()); } - private Object resolveArgs(byte[] args, Method method) { - return ContractSerializeUtils.deserializeMethodParam(args,method); + private Object resolveArgs(byte[] args, List dataContractList) { + if(args == null || args.length == 0){ + return null; + } + return ContractSerializeUtils.deserializeMethodParam(args,dataContractList); } class ContractExecution implements Runnable { @@ -73,11 +78,13 @@ public class JavaContractCode implements ContractCode { startTime = System.currentTimeMillis(); // 反序列化参数; - Method handleMethod = ContractType.resolve(myClass).getHandleMethod(contractEventContext.getEvent()); + contractType = ContractType.resolve(myClass); + Method handleMethod = contractType.getHandleMethod(contractEventContext.getEvent()); if (handleMethod == null){ throw new IllegalDataException("don't get this method by it's @ContractEvent."); } - Object args = resolveArgs(contractEventContext.getArgs(), handleMethod); + Object args = resolveArgs(contractEventContext.getArgs(), + contractType.getDataContractMap().get(handleMethod)); Object[] params = null; if(args.getClass().isArray()){ @@ -97,42 +104,6 @@ public class JavaContractCode implements ContractCode { throw new IllegalDataException(e.getMessage()); } } - - // 得到当前类中相关方法和注解对应关系; -// Method getMethodByAnno(Object classObj, String eventName) { -// Class c = classObj.getClass(); -// Class contractEventClass = null; -// try { -// 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 < 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)) { -// 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]); -// break; -// } -// } -// } -// if (annoMethodMap.containsKey(eventName)) { -// return annoMethodMap.get(eventName); -// } else { -// return null; -// } -// } } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index 474a1838..9d5d3d77 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -6,13 +6,11 @@ import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.ledger.*; import com.jd.blockchain.utils.Bytes; import org.springframework.util.ReflectionUtils; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -24,57 +22,20 @@ public class ContractSerializeUtils { public static final Integer[] PRIMITIVE_DATA_CODES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32, DataCodes.CONTRACT_INT64, DataCodes.CONTRACT_BIG_INT,DataCodes.CONTRACT_TEXT, DataCodes.CONTRACT_BINARY }; - /** - * valid then parse the Object by Method params; - * @param object - * @param method + * serialize the Object[] by List list; + * @param objArr + * @param dataContractList * @return */ - public static byte[] serializeMethodParam(Object object,Method method) { - if (object == null) { - return null; - } - - Object[] objArr = null; - if(object.getClass().isArray()){ - objArr = (Object[]) object; - } - - Class[] classTypes = method.getParameterTypes(); - byte[][] result = new byte[classTypes.length][]; + public static byte[] serializeMethodParam(Object[] objArr,List dataContractList) { + byte[][] result = new byte[objArr.length][]; //将method中形参转换为实体对象,每个形参都必须为@DataContract类型;每个形参使用系统的BinaryProtocol来进行序列化,如果有5个参数,则使用5次序列化; int sum = 0; - for(int i=0;i classType = classTypes[i]; - DataContract dataContract = classType.getDeclaredAnnotation(DataContract.class); - //if the param's class Type don't contain @DataContract, then check parameterAnnotations of this method. - if(dataContract == null){ - boolean canPass = false; - //check by annotation; -// Annotation[] annotationArr = annotations[i]; -// for(Annotation annotation : annotationArr){ -// if(annotation instanceof DataContract){ -// dataContract = (DataContract) annotation; -// objArr[i] = regenObj(dataContract,objArr[i]); -// canPass = true; -// } -// } - //if parameterAnnotations don't contain @DataContract, is it primitive type? - Class contractType = getContractTypeByPrimitiveType(classType); - dataContract = contractType.getDeclaredAnnotation(DataContract.class); - if(dataContract != null){ - objArr[i] = regenObj(dataContract,objArr[i]); - canPass = true; - } - if(!canPass){ - throw new IllegalArgumentException("must set @DataContract for each param of contract."); - } - } - if(!getDataIntf().containsKey(dataContract.code())){ - throw new IllegalArgumentException(String.format( - "for now, this @dataContract(code=%s) is forbidden in the param list.",dataContract.code())); - } + + for(int i=0;i[] classTypes = method.getParameterTypes(); - Object result[] = new Object[classTypes.length]; - + public static Object[] deserializeMethodParam(byte[] params, List dataContractList) { + Object result[] = new Object[dataContractList.size()]; ByteBuffer byteBuffer = ByteBuffer.allocate(params.length); byteBuffer.put(params); int paramNums = byteBuffer.getInt(0); - if(paramNums != classTypes.length){ + if(paramNums != dataContractList.size()){ throw new IllegalArgumentException("deserialize Method param. params'length in byte[] != method's param length"); } - Annotation [][] annotations = method.getParameterAnnotations(); - int offsetPosition = (1 + classTypes.length)*4; //start position of real data; - for(int i=0; i classType = classTypes[i]; + int offsetPosition = (1 + dataContractList.size())*4; //start position of real data; + for(int i=0; i contractType = getContractTypeByPrimitiveType(classType); - dataContract = contractType.getDeclaredAnnotation(DataContract.class); - if(dataContract != null){ - canPass = true; - } - if(!canPass){ - throw new IllegalArgumentException("must set annotation in each param of contract."); - } - } ByteBuffer byteBuffer1 = ByteBuffer.allocate(curParamLength); byteBuffer1.put(params,offsetPosition,curParamLength); offsetPosition += curParamLength; - - if(!getDataIntf().containsKey(dataContract.code())){ - throw new IllegalArgumentException(String.format( - "for now, this @dataContract(code=%s) is forbidden in the param list.",dataContract.code())); - } //if dataContract=primitive type(byte/short/int/long/String),only use its getValues(); Object object = BinaryProtocol.decodeAs(byteBuffer1.array(), getDataIntf().get(dataContract.code())); @@ -239,4 +167,26 @@ public class ContractSerializeUtils { } return null; } + + public static DataContract parseDataContract(Class classType){ + DataContract dataContract = classType.getDeclaredAnnotation(DataContract.class); + //if the param's class Type don't contain @DataContract, then check parameterAnnotations of this method. + if(dataContract == null){ + boolean canPass = false; + //if parameterAnnotations don't contain @DataContract, is it primitive type? + Class contractType = getContractTypeByPrimitiveType(classType); + dataContract = contractType.getDeclaredAnnotation(DataContract.class); + if(dataContract != null){ + canPass = true; + } + if(!canPass){ + throw new IllegalArgumentException("must set @DataContract for each param of contract."); + } + } + if(!getDataIntf().containsKey(dataContract.code())){ + throw new IllegalArgumentException(String.format( + "for now, this @dataContract(code=%s) is forbidden in the param list.",dataContract.code())); + } + return dataContract; + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java new file mode 100644 index 00000000..e9cabf75 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java @@ -0,0 +1,30 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; +import com.jd.blockchain.crypto.HashDigest; + +/** + * build complex param Object; + */ +@DataContract(code = DataCodes.CONTRACT_BIZ_CONTENT) +public interface ContractBizContent { + + /** + * 执行交易的账本地址; + * 注:除了账本的创世交易之外,任何交易的账本地址都不允许为 null; + * + * @return + */ + @DataField(order = 1, primitiveType = PrimitiveType.BYTES) + HashDigest getLedgerHash(); + + /** + * 操作列表; + * @return + */ + @DataField(order = 2, list = true, refContract = true, genericContract = true) + Operation[] getOperations(); +} 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 a5a3fd09..acabd5b4 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 @@ -47,6 +47,9 @@ public class ContractInvocationProxy implements InvocationHandler { private byte[] serializeArgs(Object[] args, Method method) { // TODO 根据方法参数的定义序列化参数; - return ContractSerializeUtils.serializeMethodParam(args,method); + if(args == null || args.length==0){ + return null; + } + return ContractSerializeUtils.serializeMethodParam(args,contractType.getDataContractMap().get(method)); } } 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 4bf825b7..06c6b386 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 @@ -38,19 +38,6 @@ public class ContractInvocationProxyBuilder { if (contractType != null) { return contractType; } - - // 判断是否是标注了合约的接口类型; - if (!isContractType(contractIntf)){ - throw new IllegalDataException("is not Contract Type, becaust there is not @Contract."); - } - - // 解析合约事件处理方法,检查是否有重名; - if(!isUniqueEvent(contractIntf)){ - throw new IllegalDataException("there is repeat definition of contractEvent to @ContractEvent."); - } - - // TODO 检查是否不支持的参数类型; - // TODO 检查返回值类型; ContractType contractType1 = ContractType.resolve(contractIntf); @@ -59,33 +46,6 @@ public class ContractInvocationProxyBuilder { } - private boolean isUniqueEvent(Class contractIntf) { - boolean isUnique = true; - Method[] classMethods = contractIntf.getMethods(); - Map methodAnnoMap = new HashMap(); - Map annoMethodMap = new HashMap(); - for (int i = 0; i < classMethods.length; i++) { - Annotation[] annotations = classMethods[i].getDeclaredAnnotations(); - methodAnnoMap.put(classMethods[i], annotations); - // if current method contains @ContractEvent,then put it in this map; - Method curMethod = classMethods[i]; - ContractEvent contractEvent = curMethod.getAnnotation(ContractEvent.class); - if (contractEvent != null) { - Object obj = classMethods[i].getAnnotation(ContractEvent.class); - String annoAllName = obj.toString(); - // format:@com.jd.blockchain.contract.model.ContractEvent(name=transfer-asset) - String eventName_ = contractEvent.name(); - //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! - if(annoMethodMap.containsKey(eventName_)){ - isUnique = false; - } - annoMethodMap.put(eventName_, classMethods[i]); - } - } - - return isUnique; - } - /** * is contractType really? identified by @Contract; * @param contractIntf 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 97424e48..8110fc33 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 @@ -1,20 +1,22 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEvent; import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.contract.ContractSerializeUtils; +import com.jd.blockchain.utils.IllegalDataException; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import java.util.*; public class ContractType { private String name; - private Map events = new HashMap<>(); - - private Map handleMethods = new HashMap<>();; + private Map handleMethods = new HashMap<>(); + private Map> dataContractMap = new HashMap<>(); /** * 返回声明的所有事件; @@ -25,6 +27,10 @@ public class ContractType { return events.keySet(); } + public Map> getDataContractMap() { + return dataContractMap; + } + /** * 返回指定方法声明的事件;
* @@ -54,6 +60,15 @@ public class ContractType { public static ContractType resolve(Class contractIntf){ ContractType contractType = new ContractType(); + + Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class); + + //contains: @Contract? + boolean isContractType = annotation != null ? true : false; + if(!isContractType){ + throw new IllegalDataException("is not Contract Type, becaust there is not @Contract."); + } + //contractIntf contains @Contract and @ContractEvent; Method[] classMethods = contractIntf.getDeclaredMethods(); for (Method method : classMethods) { @@ -63,8 +78,19 @@ public class ContractType { String eventName_ = contractEvent.name(); //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! if(contractType.events.containsKey(eventName_)){ - throw new ContractException("too many same eventNames exists in the contract, check it."); + throw new ContractException("there is repeat definition of contractEvent to @ContractEvent."); + } + //check param's type is fit for need. + Class[] paramTypes = method.getParameterTypes(); + List dataContractList = new ArrayList(); + for(Class curParamType : paramTypes){ + DataContract dataContract = ContractSerializeUtils.parseDataContract(curParamType); + dataContractList.add(dataContract); } + if(dataContractList.size()>0){ + contractType.dataContractMap.put(method,dataContractList); + } + contractType.events.put(eventName_, method); contractType.handleMethods.put(method,eventName_); } diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index b2aa577d..000e7879 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -68,7 +68,7 @@ public class SDK_Contract_Test { public void demoContract1() { // 发起交易; TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - String contractAddress = "LdeNw7PsVrXTrffQMfYLTvqscDyQ8QCUPruTS"; + String contractAddress = "LdeNhjPGzHcHL6rLcJ7whHxUbn9Tv7qSKRfEA"; AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); TransactionContentBody transactionContentBody = new TransactionContentBody() { @Override diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java index e3bf4f16..7bbfa791 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java @@ -29,6 +29,7 @@ import org.apache.commons.io.FileUtils; import org.junit.Assert; import org.springframework.core.io.ClassPathResource; import test.com.jd.blockchain.intgr.contract.AssetContract; +import test.com.jd.blockchain.intgr.contract.AssetContract2; import java.io.File; import java.io.FileInputStream; @@ -431,17 +432,13 @@ public class IntegrationBase { } // 合约测试使用的初始化数据; - BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate(); - BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); + static BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate(); + static BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); // 保存资产总数的键; - private static final String KEY_TOTAL = "TOTAL"; // 第二个参数; - private static final String KEY_ABC = "abc"; - private String contractZipName = "Example1.jar"; - HashDigest txContentHash; - String pubKeyVal = "jd.com"+System.currentTimeMillis(); - private String eventName = "issue-asset"; - public LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash, + private static String contractZipName = "contract.jar"; + static HashDigest txContentHash; + public static LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainService blockchainService,LedgerRepository ledgerRepository) { System.out.println("adminKey="+ AddressEncoding.generateAddress(adminKey.getPubKey())); BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate(); @@ -476,7 +473,7 @@ public class IntegrationBase { return block; } - private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, + private static void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, BlockchainService blockchainService,LedgerRepository ledgerRepository,Class contractIntf) { LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); @@ -484,7 +481,9 @@ public class IntegrationBase { // 定义交易; TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); - txTpl.contract(contractDeployKey.getAddress(),AssetContract.class).issue(10,"abc"); + Byte byteObj = Byte.parseByte("127"); + txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj, + contractDeployKey.getAddress().toBase58(),321123); // 签名; PreparedTransaction ptx = txTpl.prepare(); @@ -503,7 +502,7 @@ public class IntegrationBase { * * @return */ - private byte[] getChainCodeBytes() { + private static byte[] getChainCodeBytes() { // 构建合约的字节数组; byte[] contractCode = null; File file = null; diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java new file mode 100644 index 00000000..c554ba46 --- /dev/null +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java @@ -0,0 +1,53 @@ +package test.com.jd.blockchain.intgr.contract; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.consts.DataCodes; +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.ledger.TransactionContentBody; +import com.jd.blockchain.utils.Bytes; + +/** + * 示例:一个“资产管理”智能合约; + * + * @author zhaogw + */ +@Contract +public interface AssetContract2 { + + /** + * 发行资产; + * 新发行的资产数量; + * @param assetHolderAddress + * 新发行的资产的持有账户; + */ + @ContractEvent(name = "issue-asset-0") + void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, + @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress); + + /** + * issue asset; + * @param transactionContentBody + * @param assetHolderAddress + * @param cashNumber + */ + @ContractEvent(name = "issue-asset") + public void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, + @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, + @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); + + /** + * Bytes can bring the byte[]; + * @param bytes + * @param assetHolderAddress + * @param cashNumber + */ + @ContractEvent(name = "issue-asset-2") + void issue(Bytes bytes, String assetHolderAddress, long cashNumber); + + @ContractEvent(name = "issue-asset-3") + void issue(Byte bytes, String assetHolderAddress, long cashNumber); + + @ContractEvent(name = "issue-asset-4") + void issue1(byte[] bytes, String assetHolderAddress, long cashNumber); +} \ No newline at end of file diff --git a/source/test/test-integration/src/test/resources/contract.jar b/source/test/test-integration/src/test/resources/contract.jar index 8cdfebfb565f56ed425cf48ad3c280955ab8d660..a0e2ab0a648d77a0854abbe790d5d0f36ab46cb9 100644 GIT binary patch delta 4619 zcmZ{ocTm$!x5q;Xpb$_X(t8u6N-qJW6FMrrcMzl_{U;bhmq6&!M2eAK#Q@Tq6zS3> z)BsWh6cmtGz4yKEJag~ef4)1r=bYJ{voq)HXXVziJj6hoi1;e#&nQZ1N``PlUZphY zp)ZfH8NZj>k`-BiX39=>dL%9v5xPvmUa@71ZOE12@bQ&wJFuvxWi0sS{Vi|x6t;h$ zb?_a*e+27wd|GA3e-)nnI>AcxSMcV69N%~HRR8N7uQqlooQH`&u%oLBN{ezU2EE#t z$Sx?}w-sD8ZCJos^rj1CQXip$I^r z5+V>t1cbf|6##AvJ9yan`BfMW=vj!-!bWCz6P~4;DQgxyDG*Mrtc7P1D-#lYK&Bnp zgQMx1YgvlU&FLS@lD<5Z7g5vEt?cK7HF+j+su^YWyGpZZ0Q!ze#7?^0c zRr0FUeK6bi4eMasbZSV<2r8hnEA8{ZFin4w>5 zyOG}8QctAZ%!Sy7lh0qcB}$*028~US8zsB-OQ6h4OHocTp;XesQ7kK$(@u;=}tydd#98X?YNmHPiNeig(f>r#kW9GJoQzcFR<0?aDti?1wH6!i7VwCJz&5bn*9he@7TN_X5B+qc*%a-4Zv_wng(3Da`;xD|`^p5^|jNY7ajZ*$wNVH66 zMfbsZDp^ShSr#sa7|#vVUBtXl*5hE@dJ4x&Boh~x{2zz z*}<-aVF`R-Uk|T3m`llN2EdGcLG5iD1z4M}Z+OT%ybFmm-gog2wD0X7Xl-$Q_*Hx^ zd!cudxyt7FejRc*(|F)s#lXYy%Dfk_ii}qA``$Vopn(yrfwxMBkC7F7MBY2`c=c(2 z9rte;@b2yLJi|Rp$w4w%gYkH3n{VxGV>~P|UY(is9$oin@LEgKegF^0^m=x==v?i3 z6Z9j^$$szy5)(glvyHAUj)W6Tq`LTxoo$rREdH(*lQPQ@o+DWECwH@n)>OfkOzl&D zZVkpQk;T52E?GC|A=2tr(QB6nu(z6X*>!%sKKIfA4HeJ*P zYVO|bjmAe)2ju5QwkH?N(e22g`s9NbI-UO1JPvVS-&uUhJk4qqYT`h^+G5sArKLNZ z-D=?l%i`lDYznOIQdP=pgTzHYr?JX$G4F6q2g4U$*px3M0ieHm5rEsK517u=&1@d9 zaU8BQFlCCbCm)qR^u&m~#63Q3MJg=^@VCCi@h;Jt0&muaboH`j(Gog3r@JNbrPcKW zT1QGN>7O&*VHP9rpM8?G_>@bnLG7{IK+^LP30^Qh;DbCqkb3LU8y`*>mw(QsebXRO ztU-Ca)m_QO0+2m?F?M1j=9wbw1eLMV}?zz=I zn9%lPv4Thi7K@f%h>;frN54@%p1RSdX)G7RgI&A+7{FMUEkV9Wc)o$OR*Ru{YXYi% zN>OdC*BX8xR~Q%cgxpK>MduTM%OoEBs9ZgvQ*vd6KQDJIz@{tpbn`JmFL;4o!Jxf7 z+h*q|cWFREf9T>}&ZSkVTU>*feHDTDiGMPqxxZ+(F4Nv@tzBq7IG!viLX?VlZ&7@f z7q6}kD2gije`Sm0HXlvQb?xE(()s9M;S^9Iw`bnRFjcLyRWW`L*bFlH`Y!(!?dPcd z<&pVo(y%F3MU|yBM&{*vN6>@o$A>}(^pr;Ny%j>|Ne(Qfm2I)HF?feOHrLXO6dxk=@nLW41L+7_C zsDbeU&jCHF)?K5zGHK(|6AsKL>xnXpSpgIKhBR|d`x^O~=_o4}bB!|=4=P;eVeul1 zCyN-M#cEgf7@==Rp3fAttd<`LbssMj*(tBls6dQ@a`14a@*$I|3p@gCxAE+(Bm8nA@4;=Vwh%ectD_ z_rL>KoIHeTa{~85$UAxtg+YvwS(9f z+LZ_2kDdH*ndroN7{JQeK$04blV)GI^F*or?(7rAp~5Z8X&bqVUq&WQ@}^F?4V)H& z8A3&LqAKoC%}<6UsX!p{KMjNM|MYq$4^3z^=p#s|r37yY2)v%UI%C@@ z6gT=N26{k}2*1)}6yk#}w-cL9Y-UPbvaqlSZTozNX)AyUxx;p;@JZWS@@O89PU=-z z7;B(2-@d}fBkPUaZ~4IGIa51(MEV#qOI_iq*_8~(Ne5np%MTeo+&kW()nI@@WLb@Y z+InR$!|Amq66M~lSoER*cU8I{QQiJhIJzLZx?iXYiAqDE?b=h5`y`*+J+mG3HbB)N zb~qML)q*&uD^;R5=Te+yR!eZM(#%Meuc=w_LM09Z2^ruD)yy3AN@Ahm>IIY3CNnJm+A{pX*THRk$kAG>+Dv{^QdIEBLmI;I$-8&x_|QAd(8|cc zY^uMT`gt)^mR)7@)YpdZNm>DfhY!}XKW5F=J13S*q&v?mfOcXS0s&n*3XP9$b=Zn~ zs_Kv~|NE4hOxTAbBm`gzNsX^F+$-aJr)QM6{nJ_rLZ-||EJ_@D z^)Sz|ANnvxsVgA`mAS0GDBPFJWQ0~8ShjeMyrGIe_WJXylU@Ga-De!g+~glM5YWy> zpMVslkxt4SbYfg}gMs9t)9_-{cdfU@OigU+;(QX!>@BR#Kf+`@Z5hlOn{Ma~KgyuaFrprQ?nNxGT4l&7tkJ0pT~0Ov24MCto9 zE8zO(_)S{fYhn`&`u42kIhA`|{3Fzyk`TK~-@>D-LIM#JPH!;A4XIo>Kd{YmIzj{* z_N)pT_7w2K)FKiz{h^9hi~r};5oe_R$=PC-6S!$jKQ-hBefsmPLz)7IA;N7)@0F{cYM zJLwDdOy9q~au+EM8F1BWxt~Kp%4yifrLvooEelA?7Q0BiczbvunQ1tD{a1ZR_&3RG zv4@ScMU6cl&HKgTg+)D*${#0~HvUkJ$#%+XbAnubX@hVsbD6BVl?*bHv#u62KO#YJ zKgTpm`6KM~9c#@GPK;ZbG$lBoF2fJmebDkELYUd8z^_+-Sd4T48{oUT@}(*LuN3!2 z`fdSK#rla988yBvYm7bK=``_F)mPk&AKsv$O{4I#tw_EilHIJBK>4%4Lxp9|O+5qR zrFI-EFp(q21#89&sdK#&n+YfVVv;?H1HqWOSBzEh7+T0RHR(hO7``~k@cj>git&a- zyw~gIq@VBP$?AzsM!ng_EkD8#^v0t>q_+W~iUK$A2gXPpuIhNQK=PFDoG9&1mvB5? zx8ZmYs+?-9CDxb(zhA9uGpABNYOLXvH1U~+My6H@Cg8~G=kzNIbOlV!n)O2S-pRh} z`{-fI_4E|gq+w(8FJ^biAwu)`u|dB1t+ARYmNZI9a#FdQ^|_fPcl=7Rv6-&gdOQGJ zkH@m~)Pugy&FfhxS7+mX2{t5;Z1tAS}G;(eUv&CV(wQn?8@V3l4KO zH|6>D&stH(Lm^H2ml)X4Nc@w4pbKau|1yOc8j-(xmG<^uRicIc^#Ewq|7t(2+4cX0 z7|^$&vf}?u7!0%t2x*D_u$KSpL;Huo{MRUoY$N_%t?sb@iT2MT_HUEluqKiU@~5Qz qf5A=i=s$lY0fEpE5QzUjZomCZY0xjB;*{hda**6_3W8$%v->ZRjg(pd delta 2734 zcmZXWc{~%28^=ek851+P7ENe5bEXXuN+QQlB9Y0RIXZ+TMspOFqme6elVginl50p* zge;6{N?)WfXMW}P`u*{J{hmLb_w#x_|9t*@Gm$eY!nRiXcmx4|Cy`i@CVW_!K&-GC zkcqL)`txc{GlJn>f@9^y{>tTI950_h?I}sjeGmS12h>u;Ho8QWRF!c-U z&j0#JYW?S{@B^n5ohq1BHse&@q5PW%YqbgP%qnXEsg!`Aj56hS66X9Mz5&vwjqSA- z{Mg|BO%U~=OtWsscdzQijtW(S?`^!FBIGOL9y~oE6TV`nATn+g`{CFu&xuNsKXG8f)?f)v-Sp-H*j8Da)2 zE%Ema)W~eCxDlwSbEvS<`qY%AoaK<7^|(@0!lUftIwu)C<14HBEA+gf&`p0FQ)g$f zM)ghRd^WLfWbt#ecIdUmetpjTlU*7X+7^V{R=W$!{>eIQgUALmbq3b4{6?@&ga$Fm_NH3yB<13>d3@caW0mAxWOUK0h?d6vy1ExWTYk&1UUpNU60(q2il z`9-?fo+r?U1X~N4Irlcyc&8+mu8E^6nMl*!X8G2nCB%C4-Ds3to5+uQOj;Q;0jC9y zm{N-t-|hi%98_3zt;^}l^>NSzf*FUoyjD{avuI{&TDBXfSJI{J5~P~<9Aps`pn*T} zHW%Y>fGo!-g#&-LE*7$4PxCRh6w5Xro zFQ=jlojt(trj;JHP~7cA>tEFlBTb-O%@I#a=_{r*jZYb+)l8I7pqr(6IxB1)0g|f~X2g9ykA? zym3NzRG>4Y;z{~yEk3tr*VHturqO2ylXil)Q&%{ElO@t=RMen^YFI*<6m@)QIR1#~ zh)vb)$Kmt3s#c8;gR5TDui-aRiMa>0i6bCIaRhiaSId!(n<$4@IfXosv2R%%7eUlTLAMY`+p#)8qM8E4pwd zYds@Tgr%T$*$yjOd$!D7mZG`k50p`H%Wh0bhAzERjjGwG#|4ZP%!pkkK3~0Iuk7)b z*>o_x#cudHuE-!N`3mVnPUp`REFa{kI%~CL!Ku^g73Xk0GCc~(-%srAXaOG{vZx51 zX)A2+Eq;kKj)1>FV&z+s5VGf}bbRtf=yj&x&8UmQ33(cmbq_304Ff{m=G_DBps!x% z9Icrl71UI&t3@k&tiI0GH8|l{ER-1#*12G1-QV7hvr!zzJ$&&Q?But2Z%eNx?b1kh z5y$)@zQm@xFj1xn!4f(8`~J-)FEVwke1=EKYumCbfBC?n4QF=!b!9n7i-dTW>+rJT z2j)uRQ(kTJuwdiy^U}PTHv^gp#OEGTK5iE(hBB+K-A3gQb1y7-j%u<_KNiWk_@1o# ze!>>7hBFyRvWwSkqV^$FPQF4{ecV(CeDLi?OX&Rw&$lyYR=eYoafsTCK}m{_rDJAA z#AHoT`9NPDTbTiah<)5*aq8)k$ccdj_Pt0>%X(cg85e8@Tw`2rm` zb>@!z^r`J9cCq{E)fg6E^lkZcrydreZ|R8X zIOmsIAq@7YC?rrAcdZ)!y}hyw_;H}E;folp;RlxMdgmQTUXruCh&e5*FpgVWfU-f_ zK5v`=buIwoom?#@bRXoGWLLgOkEq94jr@WiO)zcMFL#&mJ0o=4MeNjMHQ{2_&jM@0 z5i+v&YIu%u(Jfi{emfdiv{=P?|3PZ9ZXsFwzS*|+1^w7n?Iz-H^RHc0rKm|lOB}>J zsM6)x9sTf*d75W1U&>(H)UXRj41LUHw3s}SfiT0HPTb2NxqQcaIrx{ITik~;t!X{% ztk+=DA9q%}Bt-!4U027a=Ar9qoMdezdkIC>bv*!Xc7Wr_HiG9_K}MsRQ=;BD*odcL zdCR-xl>SYnk#_HAI^D&T0ue?k{l>Xaw(R0--jR=Qs!FY@3M$X7TDxo`OLk4Z;g0R> zT4ag0b0O{>L?p)A%S4oztXSfdHcOPTJ&2qGwhwV1vTVW%ZNx3>?(%$GKtC&3BUWI` z_C2aJj|~$vJl+%HpK0;VYA~|#j`60iqs3*HhaJb;v!6BpwnG7o2P~t7QU#gZ)=Fo1 zzb##oEH=!@Gx`#7(j9aw6>VskcQPFs=r^<%=buJDV5G$yj2qkhl?XWN~coUpz$ z&C{$Ek3p%jSc}HNAkM8IlVv7EN7PG`zOhrxn^G%UocMK|KIX@hOKGI>Eum=KU=Ejs z0rMZnu?!O9ki9Saw7dh|=e?5%#t(MM9(u`g`~-U}k!la6@aV>4&w?r~-p?PTgOAqj z20y-P-nG}A1*XYbU9rbyQlrKB@yB=8#S;5yWz+ezUR{En&lV+UYhTFp}oltO*FfLlDWNXnrHY4}4vBk*-2 z$HvK;1U5?A0}@qwKhbxD<2#Uhh@_~>yWpe{QN$I7W7$` zFn?hBsV^7yksBi>O)?WGgU5S*hTyqJ7d+Jm?2XRnwL{mY9cDLR|J<@|7%9sg%H91#G}T^!fMXDPLOW-!e#KO6%?=k}?{5JS(HMN1Tk|9$(2= z>`_4WqUitG7BNKDfG7ZykpG)F=Sfa2^8o-vVE_QJXP^IF#W9jXf2<5fq`@S>KmZUB N$qfM5{*g5R;6GFI7a9Nn From 28a6d81f0ced94e3b69ef7fe8cd6d656d6b92740 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Wed, 29 May 2019 19:39:03 +0800 Subject: [PATCH 15/17] IntegrationTest4Contract.java can run OK. --- .../contract/ContractSerializeUtils.java | 11 ++++- .../blockchain/ledger/ContractBizContent.java | 13 ++++-- .../sdk/client/GatewayServiceFactory.java | 2 +- .../contract/samples/AssetContract2.java | 14 +++--- .../sdk/test/SDK_Contract_Test.java | 44 +++++++++++++++--- .../src/test/resources/contract.jar | Bin 7407 -> 7914 bytes .../jd/blockchain/intgr/IntegrationBase.java | 28 +++++++---- .../intgr/contract/AssetContract2.java | 31 +++++------- .../src/test/resources/contract.jar | Bin 7648 -> 7914 bytes 9 files changed, 94 insertions(+), 49 deletions(-) diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index 9d5d3d77..2a09cd1b 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -5,6 +5,7 @@ import com.jd.blockchain.binaryproto.DataContract; import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.ledger.*; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.IllegalDataException; import org.springframework.util.ReflectionUtils; import java.math.BigDecimal; import java.nio.ByteBuffer; @@ -117,7 +118,7 @@ public class ContractSerializeUtils { DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class); DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class); DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIG_INT, CONTRACT_BIG_INT.class); -// DATA_CONTRACT_MAP.put(DataCodes.TX_CONTENT_BODY, TransactionContentBody.class); + DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIZ_CONTENT, ContractBizContent.class); return DATA_CONTRACT_MAP; } @@ -140,8 +141,12 @@ public class ContractSerializeUtils { return (CONTRACT_BINARY) () -> (Bytes) object; }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BIG_INT.class)){ return (CONTRACT_BIG_INT) () -> new BigDecimal(object.toString()); + }else if(getDataIntf().get(dataContract.code()).equals(ContractBizContent.class)){ + ContractBizContent contractBizContent = (ContractBizContent)object; + return contractBizContent; + }else { + throw new IllegalDataException("cann't get new Object by dataContract and object."); } - return null; } /** @@ -164,6 +169,8 @@ public class ContractSerializeUtils { return CONTRACT_TEXT.class; }else if(classType.equals(Bytes.class)){ return CONTRACT_BINARY.class; + }else if(classType.equals(BigDecimal.class)){ + return CONTRACT_BIG_INT.class; } return null; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java index e9cabf75..ab2ff4c3 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java @@ -22,9 +22,16 @@ public interface ContractBizContent { HashDigest getLedgerHash(); /** - * 操作列表; + * 地址; * @return */ - @DataField(order = 2, list = true, refContract = true, genericContract = true) - Operation[] getOperations(); + @DataField(order = 2, primitiveType = PrimitiveType.TEXT) + String getAddr(); + + /** + * 年龄; + * @return + */ + @DataField(order = 3, primitiveType = PrimitiveType.INT32) + int getAge(); } diff --git a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java index f3e3b42c..666677d8 100644 --- a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java +++ b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java @@ -62,7 +62,7 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl DataContractRegistry.register(CONTRACT_INT64.class); DataContractRegistry.register(CONTRACT_TEXT.class); DataContractRegistry.register(CONTRACT_BINARY.class); -// DataContractRegistry.register(CONTRACT_BIG_INT.class); + DataContractRegistry.register(ContractBizContent.class); ByteArrayObjectUtil.init(); } diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java index 8bb2256e..03e6e720 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java @@ -4,9 +4,12 @@ import com.jd.blockchain.binaryproto.DataContract; import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.ledger.ContractBizContent; import com.jd.blockchain.ledger.TransactionContentBody; import com.jd.blockchain.utils.Bytes; +import java.math.BigDecimal; + /** * 示例:一个“资产管理”智能合约; * @@ -22,19 +25,16 @@ public interface AssetContract2 { * 新发行的资产的持有账户; */ @ContractEvent(name = "issue-asset-0") - void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, - @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress); + void issue(ContractBizContent contractBizContent, String assetHolderAddress); /** * issue asset; - * @param transactionContentBody + * @param contractBizContent * @param assetHolderAddress * @param cashNumber */ @ContractEvent(name = "issue-asset") - public void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, - @DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, - @DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); + public void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber); /** * Bytes can bring the byte[]; @@ -49,5 +49,5 @@ public interface AssetContract2 { void issue(Byte bytes, String assetHolderAddress, long cashNumber); @ContractEvent(name = "issue-asset-4") - void issue1(byte[] bytes, String assetHolderAddress, long cashNumber); + void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber); } \ No newline at end of file diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index 000e7879..12954711 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -23,7 +23,9 @@ import org.springframework.core.io.ClassPathResource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.math.BigDecimal; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** @@ -64,21 +66,27 @@ public class SDK_Contract_Test { /** * 演示合约执行的过程; */ - @Test +// @Test public void demoContract1() { + String dataAddress = registerData4Contract(); // 发起交易; TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - String contractAddress = "LdeNhjPGzHcHL6rLcJ7whHxUbn9Tv7qSKRfEA"; + String contractAddress = "LdeNg8JHFCKABJt6AaRNVCZPgY4ofGPd8MgcR"; AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); - TransactionContentBody transactionContentBody = new TransactionContentBody() { + ContractBizContent contractBizContent = new ContractBizContent() { @Override public HashDigest getLedgerHash() { return new HashDigest(ClassicAlgorithm.SHA256, "zhaogw".getBytes()); } @Override - public Operation[] getOperations() { - return new Operation[0]; + public String getAddr() { + return "jinghailu street."; + } + + @Override + public int getAge() { + return 100; } }; // assetContract.issue(transactionContentBody,contractAddress); @@ -86,13 +94,19 @@ public class SDK_Contract_Test { // assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); // assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); Byte byteObj = Byte.parseByte("127"); - assetContract.issue(byteObj,contractAddress,321123); + assetContract.issue(byteObj,dataAddress,321123); + assetContract.issue(contractBizContent,dataAddress); + assetContract.issue(Byte.parseByte("126"),dataAddress,Bytes.fromString("100.234")); // TX 准备就绪; PreparedTransaction prepTx = txTemp.prepare(); prepTx.sign(signKeyPair); // 提交交易; - prepTx.commit(); + TransactionResponse transactionResponse = prepTx.commit(); + + //check; + KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,"total"); + assertEquals("100",dataEntries[0].getValue().toString()); } @Test @@ -126,6 +140,22 @@ public class SDK_Contract_Test { this.setDataInDataAddress(dataAccount.getAddress(),keys,values2,1); } + private String registerData4Contract(){ + // 在本地定义 TX 模板 + TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); + BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); + txTemp.dataAccounts().register(dataAccount.getIdentity()); + txTemp.dataAccount(dataAccount.getAddress()).set("total", 200, -1); + // TX 准备就绪; + PreparedTransaction prepTx = txTemp.prepare(); + prepTx.sign(signKeyPair); + // 提交交易; + TransactionResponse transactionResponse = prepTx.commit(); + assertTrue(transactionResponse.isSuccess()); + + return dataAccount.getAddress().toBase58(); + } + private void setDataInDataAddress(Bytes dataAddress, String[] keys, String[] values, long version){ // 在本地定义 TX 模板 TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); diff --git a/source/sdk/sdk-samples/src/test/resources/contract.jar b/source/sdk/sdk-samples/src/test/resources/contract.jar index 437022505ab92b5c2ef6100ee8d5cb79131287dd..3f21f9b388229093ba00383b91e01b4389f40378 100644 GIT binary patch delta 2492 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 delta 1981 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 delta 2224 zcmY*bc{~#gAD?4{4UZ$om>5m&BdV>lU`=ikm(ORKE4%;Yp?XM0IW-}V5;iZ$0t7wtQX9o&w#pI9wH$;#)eRC})4 z{FC!!{!bF=fGaSr!4SLU=+&$Ak3lM{K13o*CqO$KsWXEAaw=`9#$T&=@dnlhE?1Rk zq&a1^{)9O~QoY*PNuRA5wvJw{7#-LOOTv9*7Pb=mvx6Q(`|rQ*P5^|05HKw{k9yNV z>Q8RCtvuSh*Jp&;b(#+RMh+g`jKWWfFSMOxbhp%V7&pVnE0%oI2fj(V`;OrwV|;cg zzP(yB=aLedm)zjn?o_-fmvl*@58ic7o0wtXHn6O6*B- znDDYZ`}(ys)4a|o+ab+#H$Sn-lvUFT%Fq85o*W;omzB??V8(ceFr?&!06{3m$?}R| zB-~Om_(jr9Vq|v)tDF75HRi=4j8v?mI>#a4|J0s1qP8xK)A|Je5r>th1!8xB0035i zJ_6DwRXF%L2%CvVa|!9FC@U$IPVi2;cc|VUejF$Ii7UyHr^_zlI=vis_H9x#B<;P6 zi_5LH4?oJ<@{y`U$<1uHfGxG_Q|@hIzv`4TrX`EaiTENIKkyw4aJ*j8L*r zhIgHKGCarer^$ppJvi&x=~weNCDdmxN(fyc&Glz^m6}s%#7?842l*^s-ClBa`y;j3 z{MhPV)hY@tokqvCr=|30C*$t9_XnbBHRM&GJx86LH<)bS_G5MU9 zm7vPR_myWgWjmuoVT=M9Rqe&j?wLN{AqI{@nQwZ8fQzrdMw}?^PqSW&>-2=0keboG z3fg`sYj59Tg=@_5wQ}Oe{TVlq9$(Xd;FE3yaXP!s(kP{$z#XSuIvsWgFlZXt=-m*4 zs`EI4Ih71a`mrvK1JKakIlaP4spOB^N`oaFxvypBr|l7NP80|5?l)%6ePx zox~htcuyMwR^ueXti?cPL%wySri#m^DDaCAdwz3Bliwg08xW*z_IXl%ZWO-zgI_a* zF>hOTGE2YcrPcVVN!mDg!g4OKy7EQ)ZVo7m;6?3k{;N)(%t17I{GZ;wiqa zTAVu_WDO;Ki>9`LZjSigGZ$DC=yF*$)K``bya~?q{ zIIG2E-tiY9ft^2ODY+?oHDJK%Qjd}jzul$ODbcY}(K6tn{;274;Q}Qd@5>4sU|y!wou;m zm1_d=z+4%3N<~u&NnLNf>%Nhhs6oLjxW&S$@|_$@6&NtjB;OEeNpQ)TLjpJF8_5D9 zk#SVT-1m7_=DCyVEIjbxEHlRTdb1&`XX=bYE3qa%5#6)lhLAJvCWJ&^^rDj2-+zsY zt%?XEk9j>V!#1SBSi!)nvkbDjXym;r(a5_2Wwqo)^AM7#ksDtNc~c~kDkHz&TN7Qd z?OeXCog?YBgB;I2pJ6U~3)6g=ktL^OIkp@+Q_vCj`lSXsZ^dhRBq)TH1vD^3+&6R3 z#b35(Cxnc%^{jRN^bOkzG1rn6B@FnTx=u%^tCqcu z3H!{u=Q8-5v;@3hjVMX&Ei~E~>`@jdwoL+M)R2Ot7bLp^8Nvwy)jUM3-$`MSbWnhM zMGB94cC%3;|Mz@<6X_{mR0cTU;+J@(u^a;!vUyn*1uHx|8O6QkkUh=|CZptPC#{Tbp!J*UHPpvQDKK*f|CPq4)Uz?BH zK(RhIlX*V4q$xhr$I3>*(ni6xWY?c0-s2l^?-s11b?`fQCb$GnF0mC7`Bs0M_9+cs zRNTN)uOFC5@GN(SFUp=3Tef}$L~M9C%&CR_ke4?;EP$@RC+BqfI2rH0a`=%sthGUG zLLFMLvO8SIU>B{62t#gbQPp|T_X)2G;jW{?-Dh%6Msz43aU>+cM=v3`5=!b%!ic@u zE`_7Cfj%^IieXHXWlWRed0}I;g9SRHE#E>i&-fiO2Hu+n(GB^we`m?EgDxLtFW7jp z!jcT0JHI`D3o7QSvff`q4PkHNJn{wfDo$Ry6clvocgX<&&K;YL|D~ck0^notA&8G21qB`dNQ6Sz W9fg0brRfhu`03+NK`xr)5&mED$q=sq From a472334b7e4372c58d634e542493b75928b2b5ae Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 31 May 2019 11:37:40 +0800 Subject: [PATCH 16/17] IntegrationTest4Contract.java can run OK. for String[]; --- .../jd/blockchain/intgr/IntegrationBase.java | 32 +++++++++++++++++- .../src/test/resources/contract.jar | Bin 7914 -> 8016 bytes 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java index 232d5816..3065da89 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java @@ -110,6 +110,8 @@ public class IntegrationBase { TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); txTpl.dataAccounts().register(dataAccount.getIdentity()); txTpl.dataAccount(dataAccount.getAddress()).set("total", 200, -1); +// txTpl.dataAccount(dataAccount.getAddress()).set("param1", "v", -1); +// txTpl.dataAccount(dataAccount.getAddress()).set("param2", 200, -1); // 签名; PreparedTransaction ptx = txTpl.prepare(); @@ -473,6 +475,7 @@ public class IntegrationBase { // execute the contract; testContractExe(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); + testContractExe1(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); return block; } @@ -490,7 +493,6 @@ public class IntegrationBase { // contractDeployKey.getAddress().toBase58(),321123); txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj, dataKey.getAddress().toBase58(),Bytes.fromString("123321")); -// txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj,dataKey.getAddress().toBase58(),123456); // 签名; PreparedTransaction ptx = txTpl.prepare(); @@ -507,6 +509,34 @@ public class IntegrationBase { assertEquals("100",kvDataEntries[0].getValue().toString()); } + private static void testContractExe1(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey, + BlockchainService blockchainService,LedgerRepository ledgerRepository) { + LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); + LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); + + // 定义交易; + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + + AssetContract2 assetContract = txTpl.contract(contractDeployKey.getAddress(), AssetContract2.class); + ContractBizContent contractBizContent = () -> new String[]{"param1","param2"}; + assetContract.issue(contractBizContent,dataKey.getAddress().toBase58(),123456); + + // 签名; + PreparedTransaction ptx = txTpl.prepare(); + ptx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse txResp = ptx.commit(); + + // 验证结果; + Assert.assertTrue(txResp.isSuccess()); + assertEquals(ptx.getHash(),txResp.getContentHash()); + LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight()); + KVDataEntry[] kvDataEntries = ledgerRepository.getDataAccountSet(block).getDataAccount(dataKey.getAddress()).getDataEntries(1,2); + assertEquals("value1",kvDataEntries[0].getValue().toString()); + assertEquals(888L,kvDataEntries[1].getValue()); + } + /** * 根据合约构建字节数组; * diff --git a/source/test/test-integration/src/test/resources/contract.jar b/source/test/test-integration/src/test/resources/contract.jar index 3f21f9b388229093ba00383b91e01b4389f40378..7c172d0edcb2a34e5aeecddac90a767afd4c204a 100644 GIT binary patch delta 2196 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 Uva+NS&@s{kMD#EZ__u`o16Qdm)&Kwi delta 2123 zcmZ9Oc{~%0AIB%xHl)ls=E#v_uFXTP^`u{JD#sIYWaLP44>k5gZMi1q&e=rnW+G?g zifHDpQQ4Rll_gI^d7eD4-#^dykMHOE`Fvlm@4xTw1nPsi$T>S+J}}@{sgSy}L{xZ{ zN!=6!a~|G*EGe4D@Rw2>cupP!)X#@*{X1az9Ds-aSviizsSdaa0s#6D5?$CB_rPt( zhrxy=@(F;*mD(UqbCrfc#1#mn&A^>;_fbUUipR(mW;&&T6w047pQklq5N#Fv_FF>r z+U(+m$=O>0oQ~#?gdgX3*W-O;81rC#A?yVA!)`(k?HgA0=jL0ZH+~*0?5ae!%S!6tE10-!w~^afR;Q8|Z~LiZSjH!OpKKW97}N*Fc>}#>AJsB% z>!DIJLF1VOE~rbr5mmF~?2Cn#fmqb-VmwW#uo$lktkeaM>Bg{LY^SC+UD@`KCTzrr zygjlS2F^C-Zd`%w5gI^70V&*fZ*8)FzpV178o&g=$$I3lz^2 zv!PMIcKzV!s6luf3)6?xy#bal9G~AA7`%F{go?~ZyuiC!`)^O^BfQaFkr7pnw~v%m z*C(xHs0U>ZIe{%$m|2(bxq4TRCB z-?|-G&O7L9cmBYc!soP)UV=l*i;z^iDrZ%*fNn*OWY-c~8u-$@P|b!v+4PXw9i=$O z*X{M3^Z+W6GfDYD%K?|>8ad~M(3j{IeSZnlnuV~26OoTnlpP zk;1?)Q7#=NhhYe$H(7AFFux_f4`c5x4kik&T;9dx?xnS^xhhVY5`t`&B8T9qhaW3?{tazJ*85t=!>w%tJV3=7FQ`WWaw4nXnhCy9+gQ78e zz>{j8ekuSny!>Twpj~@hlgzm-G0QdOb7HB$23f=&LI1X|IHY?%KAhH~Qt8 z72>G;V1&feNiI0CfoWutn5HGyapBTXu@!L``w{Gp_mc?jQEUm(7oUQhT$E zyPMJ^-JU(dc*@d-?e{V?4WsuU`{>XciDyMW1@W?oZ5drx+o;5n3Kl$%zN$^&mkXJB zHZhxYF~%H8TYRNMAMwU9-7!q~+JxV4MV8)InU<6wNjE?;{ZH-Y;2NiO7qgD!kAy5w zgn8C^{u|`+hqu;55V{?&sXt8F=Dj%HV^V`&jgJ!ilLesdcW0jX*gy7Q7N`vZ;DL|d zzXB;Ce66eo{kzoQ?=(u3-nRUEYL?NS#;7kkI6G#Cs*FxCHJ zqBf9ZIjUfUaKr9Q4rD8IH+VTEXup3c=4(Kr*xj#T^ImLyh3Y>SE(0pEwVwtAIN40y z(<&ljbsHp>o|h<1$nJb8z=1CrnI{bIP0*Ui-YrTu3GwS<$TEdfq3F)#cG=YVrg&_6 zET~kX)Kp-$+%p%QxjC;P_3a%B6KG%OgBj&GoajiKZ;J&s9mmp9 zQ^`O|K${f#xHYkjM7$%Fx5;2Kec>@W^Ohxct%w8$K~~4|L%*; z>%+cgcj6O+z-(RvhkjS~YV8=!wIHqTI9EJI7F&>mvUkO*pCX|Ko;L-CtvYX)lW7duo&1yHjYWERNw}c~&Yw8)E z3UvJZ)i{fmFc7uQY%`8zR;`2wapG28R zx1m08S%=xl@H&qTshwK41gPku{{*9{;$%Bf@bn3p*EoeM3fF}Qj+kj4d9`PWlGks! zPDWKmZl05&2P|)!phFekcne$S#tfK7^hh=&N89d&t?1p0%)Z8!ri%G(A;?>XB~nM_ zxQmUJ;bdrE#uYvz={^}QPO5kqX^mj3+KyAdn?T7$Ope(bpF)7Lixi-Q*UD$OamWC5 zX3NF~hc44~Ri$gJrWD8vZU4?6l8yK%W(VrE6$|NUT)IaYm^p^B4!-%l0{j7#lFZ&| zIcH^GlcXW`?0Bm&n>e}!xFb53@x%d`QFkv@a0O!fO}HoZXPr}RRd>D{&2}L3xni0t z@3zAKp$+^6ZO03x(r>u}002n@KwT2o5~S!eAu0g1kVH?62@|18?oO From 52ad61c4e62a70ce5720555d6d61d3e3b7597a25 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 31 May 2019 11:40:42 +0800 Subject: [PATCH 17/17] IntegrationTest4Contract.java can run OK. for String[]; --- .../contract/ContractSerializeUtils.java | 25 +++--- .../blockchain/ledger/ContractBizContent.java | 25 +----- .../transaction/ContractInvocationProxy.java | 1 - .../sdk/test/SDK_Contract_Test.java | 71 ++++++++++++------ .../src/test/resources/contract.jar | Bin 7914 -> 7937 bytes 5 files changed, 63 insertions(+), 59 deletions(-) diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index 2a09cd1b..da3297bf 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -7,7 +7,7 @@ import com.jd.blockchain.ledger.*; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.IllegalDataException; import org.springframework.util.ReflectionUtils; -import java.math.BigDecimal; + import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashMap; @@ -110,6 +110,11 @@ public class ContractSerializeUtils { } + /** + * the param types that we can support; + * @param + * @return + */ public static Map > getDataIntf(){ DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT8, CONTRACT_INT8.class); DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT16, CONTRACT_INT16.class); @@ -128,6 +133,7 @@ public class ContractSerializeUtils { private static Object regenObj(DataContract dataContract, Object object){ if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT8.class)){ + return (CONTRACT_INT8) () -> Byte.parseByte(object.toString()); }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT16.class)){ return (CONTRACT_INT16) () -> Short.parseShort(object.toString()); @@ -139,8 +145,6 @@ public class ContractSerializeUtils { return (CONTRACT_TEXT) () -> object.toString(); }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BINARY.class)){ return (CONTRACT_BINARY) () -> (Bytes) object; - }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BIG_INT.class)){ - return (CONTRACT_BIG_INT) () -> new BigDecimal(object.toString()); }else if(getDataIntf().get(dataContract.code()).equals(ContractBizContent.class)){ ContractBizContent contractBizContent = (ContractBizContent)object; return contractBizContent; @@ -169,26 +173,19 @@ public class ContractSerializeUtils { return CONTRACT_TEXT.class; }else if(classType.equals(Bytes.class)){ return CONTRACT_BINARY.class; - }else if(classType.equals(BigDecimal.class)){ - return CONTRACT_BIG_INT.class; + }else { + throw new IllegalDataException(String.format("no support the classType=%s, please check @DataContract.",classType.toString())); } - return null; } public static DataContract parseDataContract(Class classType){ - DataContract dataContract = classType.getDeclaredAnnotation(DataContract.class); + DataContract dataContract = classType.getAnnotation(DataContract.class); //if the param's class Type don't contain @DataContract, then check parameterAnnotations of this method. if(dataContract == null){ boolean canPass = false; //if parameterAnnotations don't contain @DataContract, is it primitive type? Class contractType = getContractTypeByPrimitiveType(classType); - dataContract = contractType.getDeclaredAnnotation(DataContract.class); - if(dataContract != null){ - canPass = true; - } - if(!canPass){ - throw new IllegalArgumentException("must set @DataContract for each param of contract."); - } + dataContract = contractType.getAnnotation(DataContract.class); } if(!getDataIntf().containsKey(dataContract.code())){ throw new IllegalArgumentException(String.format( diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java index ab2ff4c3..56e6bc24 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java @@ -4,34 +4,17 @@ import com.jd.blockchain.binaryproto.DataContract; import com.jd.blockchain.binaryproto.DataField; import com.jd.blockchain.binaryproto.PrimitiveType; import com.jd.blockchain.consts.DataCodes; -import com.jd.blockchain.crypto.HashDigest; /** - * build complex param Object; + * build complex param Object, provide more String attributes; */ @DataContract(code = DataCodes.CONTRACT_BIZ_CONTENT) public interface ContractBizContent { - - /** - * 执行交易的账本地址; - * 注:除了账本的创世交易之外,任何交易的账本地址都不允许为 null; - * - * @return - */ - @DataField(order = 1, primitiveType = PrimitiveType.BYTES) - HashDigest getLedgerHash(); - /** - * 地址; + * param lists; * @return */ - @DataField(order = 2, primitiveType = PrimitiveType.TEXT) - String getAddr(); + @DataField(order = 1, list = true, primitiveType = PrimitiveType.TEXT, genericContract = true) + String[] getAttrs(); - /** - * 年龄; - * @return - */ - @DataField(order = 3, primitiveType = PrimitiveType.INT32) - int getAge(); } 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 acabd5b4..f5f83708 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 @@ -46,7 +46,6 @@ public class ContractInvocationProxy implements InvocationHandler { } private byte[] serializeArgs(Object[] args, Method method) { - // TODO 根据方法参数的定义序列化参数; if(args == null || args.length==0){ return null; } diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index 12954711..76bdceed 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -1,12 +1,11 @@ package test.com.jd.blockchain.sdk.test; +import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.contract.samples.AssetContract; import com.jd.blockchain.contract.samples.AssetContract2; import com.jd.blockchain.crypto.*; -import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; import com.jd.blockchain.ledger.*; import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.BlockchainServiceFactory; import com.jd.blockchain.sdk.client.GatewayServiceFactory; import com.jd.blockchain.sdk.samples.SDKDemo_Contract; import com.jd.blockchain.utils.Bytes; @@ -23,7 +22,6 @@ import org.springframework.core.io.ClassPathResource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.math.BigDecimal; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -66,36 +64,20 @@ public class SDK_Contract_Test { /** * 演示合约执行的过程; */ -// @Test + @Test public void demoContract1() { String dataAddress = registerData4Contract(); // 发起交易; TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); String contractAddress = "LdeNg8JHFCKABJt6AaRNVCZPgY4ofGPd8MgcR"; AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); - ContractBizContent contractBizContent = new ContractBizContent() { - @Override - public HashDigest getLedgerHash() { - return new HashDigest(ClassicAlgorithm.SHA256, "zhaogw".getBytes()); - } - - @Override - public String getAddr() { - return "jinghailu street."; - } - - @Override - public int getAge() { - return 100; - } - }; // assetContract.issue(transactionContentBody,contractAddress); // assetContract.issue(transactionContentBody,contractAddress,888888); // assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); // assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); Byte byteObj = Byte.parseByte("127"); assetContract.issue(byteObj,dataAddress,321123); - assetContract.issue(contractBizContent,dataAddress); +// assetContract.issue(contractBizContent,dataAddress); assetContract.issue(Byte.parseByte("126"),dataAddress,Bytes.fromString("100.234")); // TX 准备就绪; @@ -109,6 +91,34 @@ public class SDK_Contract_Test { assertEquals("100",dataEntries[0].getValue().toString()); } + /** + * 演示合约执行的过程; + */ + @Test + public void demoContract2() throws IOException { + String contractAddress = deploy(); + String dataAddress = registerData4Contract(); + System.out.println("dataAddress="+dataAddress); + // 发起交易; + TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); + + AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); + ContractBizContent contractBizContent = () -> new String[]{"param1","param2"}; + assetContract.issue(contractBizContent,dataAddress,123456); + + // TX 准备就绪; + PreparedTransaction prepTx = txTemp.prepare(); + prepTx.sign(signKeyPair); + // 提交交易; + TransactionResponse transactionResponse = prepTx.commit(); + + //check; + assertTrue(transactionResponse.isSuccess()); + KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,contractBizContent.getAttrs()[0],contractBizContent.getAttrs()[1]); + assertEquals("value1",dataEntries[0].getValue().toString()); + assertEquals(888,dataEntries[1].getValue()); + } + @Test public void registerData(){ // 在本地定义 TX 模板 @@ -146,6 +156,8 @@ public class SDK_Contract_Test { BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); txTemp.dataAccounts().register(dataAccount.getIdentity()); txTemp.dataAccount(dataAccount.getAddress()).set("total", 200, -1); + txTemp.dataAccount(dataAccount.getAddress()).set("param1", "v", -1); + txTemp.dataAccount(dataAccount.getAddress()).set("param2", 123, -1); // TX 准备就绪; PreparedTransaction prepTx = txTemp.prepare(); prepTx.sign(signKeyPair); @@ -173,8 +185,7 @@ public class SDK_Contract_Test { assertTrue(transactionResponse.isSuccess()); } - @Test - public void deploy() throws IOException { + private String deploy() throws IOException { ClassPathResource classPathResource = new ClassPathResource("contract.jar"); byte[] chainCode = this.getChainCode(classPathResource.getURL().getPath()); TransactionTemplate txTpl = this.bcsrv.newTransaction(ledgerHash); @@ -186,6 +197,7 @@ public class SDK_Contract_Test { System.out.println("contract's address=" + contractIdentity.getAddress()); String contractAddr = contractIdentity.getAddress().toBase58(); log.info("contractAddr="+contractAddr); + return contractAddr; } public byte[] getChainCode(String path) { @@ -333,4 +345,17 @@ public class SDK_Contract_Test { } + @Test + public void testStringArr(){ + String[] strArr = {"1","2","you are welcome!"}; + ContractBizContent contractBizContent = new ContractBizContent() { + @Override + public String[] getAttrs() { + return strArr; + } + }; + byte[] bizBytes = BinaryProtocol.encode(contractBizContent,ContractBizContent.class); + ContractBizContent actualObj = BinaryProtocol.decodeAs(bizBytes,ContractBizContent.class); + assertEquals(contractBizContent,actualObj); + } } diff --git a/source/sdk/sdk-samples/src/test/resources/contract.jar b/source/sdk/sdk-samples/src/test/resources/contract.jar index 3f21f9b388229093ba00383b91e01b4389f40378..3ff8a821d9f4980f3a642b3b392901b723979a78 100644 GIT binary patch delta 2113 zcmV-H2)_5~J%K(AP)h>@3IG5A002izzmW|j14c`~u{1pa14T=}lXL+#14T=}v#kL? z0Ru%#zq9WGgaHFZOTV*r1WgDHMN7X<>RoA0ZwCMXjg!y}Jbwv$8`Tv(W6K^{9s)Q{ zXj&5NBm&8nqr@ZyvbdG)fVbilyGmTQg^@IICXqB^W@KWz&;`0Lbl*2hTe>#^l$bP> z;{MMzVRR?-FOmq1Psec$#vt~_)Zw#Rq;I)-&gSi1zpo87apIVoqtcwDCn6vuP^J#yk1;N&bhW( zTso#eGnS2_J7yJKn8nbeSg4<`zqVZ_CkTL9eJ(D+teJiWy)4FYncYiVDo--W<$<6Gh9LI3i zjZYRz`F~+r?JymuOn}i?fNI{zEg5!|@TmE;q+4{4HOD}3?#VVuDj3=lFhO*|bHd8! z3_F#}*@i>Mc0E=ux@N&hn~q6`Q^lg?>aJ-O`E8)(U=ux5)C+X?HtF_|G&OWk!Pu?3 zKPCK+WOe79mn;R!l!ER$GYXCb87aGF-bs$GxPOLoBiN3N_^RNZo2WOqHLT#?SRJGg zx{(Q0n3&C+S8zw8Mg!{o3dUPNy$Mxev+Kh0Nk-NbuHCnIaf$8}d1qAMg5&X(3a8O=0Z&%5`WI3)6k=Z&#O9~gWMoE;pG}vL- zwtvOSI!-p3VCMDKcl3?X2;zDJIQb&12+%$i9MTD@KlKID+@8_@Ra$ z;m3q)tenxZDLP;DPO(&W`*eSkpQ`wohM(gXDt@Wq1^h}}UR3dG4Zp!}ndABq zOpW_-Sj9^keuv+y_=AQ&;zhc$WVk8UwSS$XeN13N_vXt94)8>+ccr;MDM-k^I}vpf z%_B*y)@ej@?3|h_Ug2$6^1M^=XAOVBUquuyskp4+WxS%{Ra97pvPfg`b+frv%&NGe z;VM>Dye6=&{eLj*!0qfSn*r>bksUO_uZ+Xra9zV846Aru!{6}+v)oe8iM@b$vVT$g zmJQosSrP6Zc$2dxv8?CI24C0kPYwUVzg4`Y;cfhfCGL8yJ+!5Lj2qu3^0Mnr*;ba0 zGX<%qOq+EaZ`H!^#x$-tu2JA7ZI$Wd4sY<8R`L|H>oUiNUJ!e^UMd+y*2GXOV5e+a z@@t-ogIm~z*rV&!OeV4TV$i|Fqkk?&Z!%@u`U*wEuH}8^1dY`z`Qx&gA8~qPfy>(i z{AY$s;w@hkw1Q6xo8>ELT9N>L9rH@GR-wX!c+l9fS4ysx6e8p1lHrIwU|$PjGB~5U zV;p%eKVs1uR+p)z_;rq54=8Pq>pvr!jJdE%T@aA!?ol0jb*LwILwvL4M}CtMfP;pKsIGB^k8 z`SiqU2i;h!vLsC_>zltkCpdvSSyQ$*57T-bwtVIgyGGg@Vlr4$UhDbM+t?b_Ge>uh z2&rt=DvMT~4;%!|_8Eqv!+%K7RC2rqFrA(=+}V<0%R_Ii2uE%Wf!@fIX*z)2)YL8W zLqC6d^`Z?)9OSi2>?Hh!)h704-n*fQ!vL=j@GZ%^!h6TS6)2aa*n_-w%EcXch*!-M zz)>9IUBPjjpp;O~@h4(C?|Uz!?Hbw_t{~LYQ9R> z9*N%PA^7OxX$0?+7Wd-)B;JOUPkNO9#vF`G3MYLEFChf+8}dvYg>IT1cm>)jZc|Xf zwknG{ncEv^_T0fsLOk5bOMeADjl{P}qWiF)e@`PS$q&#vZCA;ksgghAlNV19;}PmM zxG^E!nDpH!BP`vBlYe5*_Rj0*U1-0C9SegM?7V`z<`zPUxrL7Yt9aMkRqP4~=m26E ztm71~a*AUL(~?uX$|)YqX-0DTfY0eksFG7uaC*1LiG1F36?fm9&p}4%P#vFWl}{9p zVpj5rR{2DO`J9q`KIrjL9w47i3akk}yMy=)Rj|kBQoG<3tRP1$@}YnxIU( z#8LvV1eJ7M&o^UB0 rPHzVQ0F9G19#jKGOTUwh9vcFA6q7F<9g~|B4wKX#5C*Xu00000NF@Z+ delta 2116 zcmZXWX*kq-8^=dunfWs*yOAwR#@>uWw&|oNJC)^xEE%#S*$16r4lfpD)|tD5X9pJ`m_Mc}&0vzw5zZ zNyl>YLMi1MPXFQ*5=w#{C`bD`z+-4qCGZVGZ z$?4G1bRq}Zp;C{oTD14X!Aqb^w4Fi%oj<>jpam({0!FkVmR{^6CpX;KagiWyM8Mu2 zTMYs-^*I|?r8n@63p=`9l*M+{u1e;fYHVp~0BhtKZ8L0>LIZB&eYD_erYC(xa)d1C zRKThi2oLL5k6Oa^ptODmWb#MncKiBoo-CrFa*;0xj^^GwW2cesn2ykp3fshEMU}Pj zD`_fz=>v9v$r5(PA$YddQM*KQWwHVlR329GD9AU}bvRf(#KT!2`bAES9JOfS^6W32 zHcR%qm|J&$GgQaVY8=0&4lgZ0(X1-$m5h8k<=A2!i!2GqOXGZH3!VhSBg%K>qikQd z*0NK5Xe9Oo^*cQaD9+Zi&j}b`95?CtOMu?UkJB9seUv1lDiPh*Zq;V2Vgp0hUfZ`_ zC=vTXL=oE8Pg%tw>q^^Srp61OGqo(v4iomODQ3R`n(+!6#i~*7bU(mu!4PMJ>Jmgu zT99Rca2PuU_;hQ^@7EZIp8xPaY$;Q{iFI?)?|ts_>@iU+Nctdu>dvC1NqDw*ll4%( z@0T!#wxXlbNR&H;Z!kZ%DY^%1?JNS2_*Sm(VYByBn%5lVCJc#w7K@<+>dDAlUPJ3a zsDrmsOPN$tp2CF!T#qM}-BJ4)`DmuqIo z<1+mrqE9C{Kx`dT&mcBM?L^y=AKtQLNxgk%d{{xRk^7pL|F=kh*~oX%Y(8o;N~k6R zp0O@g5qrFPr;~K{U3xsb#9`lg&|~9@^p%jbty489IHM^eu%D28C8C2c>zKte^ZJ0V zcZShR2$iVna(-n%##vT2c)1NKNZ4@*B&i*#NroLQ$>xu!#`Al>Sr1+}KK@Dh&GNk@ ze1k-5<`CoQl7{p_H$zo7d|&tg6Zm`VMZr&g;3ZN^TF1>68mXvkNj+zLRfEWLB4GO2 z*i8J@2xAm|;g#n2kUO5~jAg2?jd}f2VCsI8X-f4Ia{?ud|Dn<7UuC!MVAPiIk(l9% zG|srp^E+kq;hi-YQmgGX?Ykk%xEp*DFW&D~|0u>gffwF-Z~BRc^7#W=^Ss%>|;o*BQ$>7=g5vV6`V5NAVDw3u_q5_l@uanm80eQ4$ zNRFynR(=dR1CT|FU%F^Q5aar%k`&rM}Kwcg^T&gS=#CzK&8k$-kzL? z8O!Y}oEI;uHmj)>u1{faY<6=*3lm0h-!P9O$Ng#=6>Ze+@6qOm7rI9)5DW&)h;OG~T}y^3)+ytsYddz*n1Jp?fa{OF|1Qt*1afb{3QO z)e1;Btvb=g=SA{kQoCRBfNOX?=Gh-qJLl}es#h{mNx zLW@O<4S8ouU9&Oin{x>9?RQX_2oKPy(<8Ka`!hC(vW}5yY;n5lc?PUWt5$w$^0MhF z>>| z4T5bei<@wkP0SAP5giKA(tF?sk}E;AB>UQ71i^pA+?J|Z>7-rhJjCu4wWV_mU4xS$ zwx7T1XV7D2L*D&`Bb~NQGC*gjmOzRJ3YUeez9eyP>Z|Q`&{ru&rsyJ(xnsCbf=rat zKo3yTW^^{V#$`i%x7sNNF1X-5#%L%z+e+d)e@61P>~wC{&z-eO76guJ$plr7yN@#7~r z3-zYK6nIbC4Q@S&9!U;fyl@a@j$|oWj?%svz$pbxw$U4pe2{{JIH(A0<}p}5po6}! zWnqCS!D~4xjU!f*@?`jTe&q?sM1B;qf_7U91$5Of-lz6WpG2Gc$9*dUK0uQaSi4P^ z%&e>85kk*SHS4oT!&{)cg0pE)Y#?bh_mlZnge|uPx{`m?*i~0_<~q?W`_iAwr8t6j zWdCby$WLS2UMZG%%i#rq$S@EHLCX?B@Ew}FTT17r$;sPNti$~7gy|s>($0rWly*5J hQ`+r+G;S^9Ap3ud4-bTYOL-iI{8Yw>w?OJ={u^eO?9TuI