From 91ea158efca743e0d631bfcdc95a62b1827dc9c5 Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Wed, 8 May 2019 19:37:34 +0800 Subject: [PATCH 01/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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/23] 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 zcmb7IWmHsM+a3mnMjGjokOt|Jhwg5MkP_6PhXxTux|D9DyE~Ld8io!Lkggd<6eRS+ zC)DTtd|m6k&pLbWwa#_jwSSy@U0SNBXxM;nwrNnQ@#o?11?zfOm)Dc#Qr1x5(fS*P z3D~%XjZp<^C0~Djb^Vh33{#iZP*#xF)#FxIkRR>1@syqBmWJteVV3TK%y9Vx_@@v60A2gv^`c!DV(sMcz107Y!1x>S(B?NF zq8}hDh?DgrYkSKFjz8hQ_3s+;-Kefl-@;xy{RwaF(whxI@n~p2RVZrF5Tqhw{&j|JA{*HN0&ACIGNQ2msvqA3CV);0*bziv@-kZp3q>Un;pC7{b;?fVe?u z!=MOUG!U;lZ|wR_{3VGXJ?+qXC|AW{19L@d8+wM2f85;{6P_@P2j?nu%Gp?Ke9UT7 zUnWvVPG0ZCX6~v5jN+>;!H-mGAtf=XQHO8c;F8{!rblH*`=6mUPwMP^&P9P{skj9_AOuDx9{LK4q=AJQD zvUw?VB{S}HmPhampBge6#a5~8UPCncKCo8~4_1|&wfY6f_6h6zsV)YHN5EG>q&%f( zl|gW}vsXcMnB}{gMWOu3=b<5E_(fB|ni`6$+AQ{+f)c&OhEdow13R7x^T3R%qXEwd z1#oS0?N~LnF7*o^%4jnr!IZtZU*GT^+-Quw@IJC6JSZ`JRDJ(GTjKlNitXj;d-CL! z{4XyiEbDAq6+tHPZ;b;xa}u{%@S{?h-;bEObXW7A%XP)gmuHy2*=uAQNF013?jQ#A zHCSwV=YreR`nklarBhx1hRRsJB@R=3w6yS8loG^bu=zy|I+S~(xrLlCOk>fYMk>1r zFI1$vQa@hSXEKe0k4^e*mMb?_y(u;QJy8N9-x}k>TT`w4k~SI?H%1$UBL}m1+6?w= z)T0&F7KVGGMg?{}2KrbOK)0l9=SwCJ;*R!o+|5lkw;i-27|g4gO6a9S?Q7$$sPQ9&T3tN!Le2?XW1?n9W(mJSuOmL z3bRnPhaZzwdiP*i+DE2>!4jlHbdo^oL!OH zr%)zE%3Yqf1MNMc4@i+AW*qs&cKVV{N{eZAZv8I0Ndbzo4)EuXziJ+H;vdF^bj%m6 zGUG}04g)jqvrVq@YBOupg1ce`F3F`PYms6#tLM(Up<($%`5M9kI^AlHSR7fZzNtKy~*?B?JFC)xI1 ze|od!begxGE3Gdi>%PhfIc=faX=XH5*}Tm{Zm5;8`sX%ha|y(MbV32Wo<&eyCK+4k z(=i}7DX3ETH=lnff8QhiBUl5#)!H`nrOU$n%dc6VPsKt zJ&N)Nsr96HDGw#VW3QggiGt@ci4=(-hYjd`FGE1f1_)L>PlQktq(9Oh7?FK>OZB!^ zG+%=ZtmC1S9at2ZK6z@v=kP+bWzm{wzBR%JtTN&~AQ;hZT_MU{ep)tOud|)vpKNz; zM}BsDk!1?Ej#CkI$I(B&Oeg73rABDq`9##V`D#U-T*+hDmoKGVgx(C4>DmRg)qPN_ zKc(tMV}>W>QNUYt#fOvQ9a<`LGDG%S$v`ZOxpjlkv&6h?1@Az>p%ky9nlFx}#=YuX z2!D68R(l9X0>>+pN#@46VU%$`Tq2#ls&CVOu0=?Ym!u7FDn)46-z)rr`J)| zy|(*74}}8+G)JylGQOH6JcwxEv#LVjKZQQ0G=cJ_sZ$*-)LQyxgCa3wAM@g)9lhmW zVA)YnxXXJNdQ2C{WHJ$*Y2U|k(Cvs=J`0e=v7&~TP*rWxRZ$MHZ+jUYw`Av$ybFS_ zjx7-gOU}^Vm0j7Oq+ZqiK#CwdL2@C;Z|Fq!S8!d%TGJF&z79_^+6Mx~ofy0@7y@72 zlQ`oB3d3b6VlkX#qvgp64sqO{S@=;rI+CG^t!RmEeC>QmG~?HXVPAA+B`&p;V8nT1 zx7gG_TR4E)27BN2c30f!<{#OVhTzjH(*28W7r|Am=gpKS!M9&7%MYA6K*AhM|B#?H z?<@pC%sXX!Z?Zg))Z?L8=Vw+MYGiEaqB5Q8I-Ij`kdUNzff z9EU*-vyMZZx-wydqEm*FIrFJ9@B+J`RYRf)qg9Rg{A`dJjfvs~4FrF!8(Hv{#({<} zK$+IE%rjWi5+|F=YsDq&3k#(8z6yRk*OJ%Xl6ROmLL0eF?#-`~lrWg=U1@qtwKATe zYI2y1XqAS#zfB}4K#zymUdR%^^!;EJ|~K18Xpc0S6I+D`3* zYe0q^`J5bi(QSF>Om4;7^5LgWQM&{s7qsRGLV~hrK9xf`3Du}jqg!^E+n6$^N&p`4?q+kx(@+?zFq>(_zwZbtzmaka4s*JpSrxt>g-c- zr?G`_)n<4c`QUW*AtSu%V)=(Ym{*GVRXhy2Ejg$gm-rdWuXcT($=yWKA~(E>)87o? z$Lv>uZlTi}tf>w5nc*tcsu}r?f3J9%mY`by{zTmV??6Cl_$vz#bcHWK2PEJW?ZH? zG(qxmDkUT3n#CuJOc8i2!L@0v1uCrRd}{Lt5YPLBCScXb0!;amM(pC-eT-*`02UO! z*Pk-J(BK7TpW~mLoV0i*GpCR;Y;SbH{oxl^4Iiq$nx&ys-$>3y%bS@GkBX_e4Scib z400v9vL*5M0zO6q9l(xtNM^`M=efoui7r)E=a7D)5${%;fK_tG;s?>|7iS%vbQ>)^ zGKf;N0Frqg1ZyBFunLQsM1%=p7uW-=!f9u4mRsckI$^gnBMbvyW3_W3Vmh@0t$_oe z6;dzFRsTR@vAYw;FJs~WbCU;pM}UbY zIneM;npP}(g`n~~75G7uD?6*0&_nxq71FU3$sMm756l+I_shg47E6~trQHuQeiZef z(nF%^UK2RWZfbNsjO$jbwi({Xjb3;Eqx95_((kNe8#NF=w-) zWT?cup(!gR^IhMMaaXzNO^KeAN%ncw2d&YSS!mX)JNHYTsF1uDzTopOlx-7nvEvibF5 z2h=ekujnWZxTp0InNi6*jS}F7VCFjW8JN|oz};Dw{!U}RZe-K`*>tDfnQ0Hqi5<=@ zl4_YA?ps|@Ag^Jc9`Epq7X8@lNTbbI-Lbu)LWFko>RA*VN_hr+Po&1n;P8-%)A^A<%Pr?aBu20sMhvmJq)&?TrUTWH{Mjm5sdG#cP-&e) zsf4qxCelsL3*^vqem8!LiQL`+o{q`beEUtSJST+V#h27#z!*m>i1W@@@x){g}1q`=5&J{t?gE(u~B97JkmDR zmu0k~VM*=jjgqkihdzUYOHE0|0>OQxlLd{|yesUUwzpqZfIs=a8MdXqBSB!%ENsH@ zrE_{E=VQwPVGDh;+5w}vq4H>9I_o`rVVWj`POb?@v*+(zh{10TbbA~7H^x&EhZhzs z@eUIOxakvpvVw-+r#pV+^lMUDe-&xCoEXU=(u=mW!4-d%M36ctFI?O)avqlP$4i|l zj?m^@BOU_;suhiZL@>L+kjvVfYF-9;79p%f5mOkEv|4hETagwdB%O~POB6yn*=dc< zjxG^HcRW4u%+Xcb$T!JP8+O;&pHQFjeCbR0YOf(?{$e44Ku`RHa1(}DAp`A=MvNH> zM|^i^1iGcd**t}4=#F8rhI$w8BNlBiT{*sZeDiSBF^nFQrN*9UOQNw4$;_C@ovL8Q z9OKi+Fv|5HEI1-cbvWuy?-T5rr-3NLIeCHEHqq@|tnE~%YqaIv9V2S|{EfgR<%LMH z$~TGZG++jsHw93oatuvgF0m$L{Cx49$7q^-b0{jbow1XV^nyoyELN6#{uG*du_m;E zp^uUB)u}#c^+8PPJbOJO`vTY0w;<>$W2n?iNHDXfwtp3o7GEqHif%939Z^sEHghBZz&mEb_5@2U)_I(dSCYrsX#KTF2jc-8+OP_yxQ(o$6x|)dVGn|ys30?`Y9oH-7{XRN~Wl^ zQ(}YkcdDP71cmULMmM&+!Q(8bb-Dbk+8*{?Z^`rFu#2r+4qOW#i{WL7s&=~kVV=0x zDt&}c$e3Nk#p}s?WJ~jEsvCT_Hsv_xbb5I7xCD(hv5YHrNcAKHoy6*qP$P17th<%e zrSxYf?O|k#Nk)`C32{RQaBQ1ZFz`8hGdsdcl)zZ?vnS_$)0jeF4Kr%VJ;?DN>?CDW zO3ya+lT*TG@T;HH6a=>h$#f|}C@l5XW;R4)ZEMo3I3(!74BX(C`i?>VueGOd;BS^6$a=kgr~RZv{T%pLqR*f7KLaDKkAF!( z|HS;Y2=s$NbS=dEt={}D%r{Z!2TAw`=_kqOXa285q91&_U-EyFjQ+{~*P_usspJRd z{NB+oB%~in{#s7?;d>qUy)!=*`8~;h`TilU{HOo_9It-(zk~Bz|NkDgv{XUYGa3MZ 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/23] 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/23] 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/23] 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/23] 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: Thu, 23 May 2019 18:25:15 +0800 Subject: [PATCH 12/23] Fix ParticipantNodes return ID error ! --- .../jd/blockchain/ledger/core/ParticipantCertData.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantCertData.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantCertData.java index 96d30caf..05fd0611 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantCertData.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantCertData.java @@ -12,7 +12,6 @@ import com.jd.blockchain.ledger.ParticipantNode; public class ParticipantCertData implements ParticipantNode { private int id; - private String address; private String name; private PubKey pubKey; @@ -21,6 +20,7 @@ public class ParticipantCertData implements ParticipantNode { } public ParticipantCertData(ParticipantNode participantNode) { + this.id = participantNode.getId(); this.address = participantNode.getAddress(); this.name = participantNode.getName(); this.pubKey = participantNode.getPubKey(); @@ -31,8 +31,6 @@ public class ParticipantCertData implements ParticipantNode { this.name = name; this.pubKey = pubKey; } - - @Override public String getAddress() { @@ -49,16 +47,11 @@ public class ParticipantCertData implements ParticipantNode { return pubKey; } - - public int getId() { return id; } - - public void setId(int id) { this.id = id; } - } \ No newline at end of file From 38c54c18aaf53d5397e385009b3fc9a96002650b Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 24 May 2019 18:51:00 +0800 Subject: [PATCH 13/23] 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 14/23] 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 15/23] 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 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 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 16/23] 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 7db6392a58e7aeb9032c0bfa306fb353a6c5333e Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Thu, 30 May 2019 10:36:47 +0800 Subject: [PATCH 17/23] Adding Tool-Mocker module, which can be used for mocker test contract function !!! --- .../peer/web/ControllerTestConfiguration.java | 2 +- .../peer/web/LedgerInitializingTest.java | 4 +- .../sdk/proxy/BlockchainServiceProxyTest.java | 4 +- .../sdk/client/ClientOperationUtil.java | 280 +++++++++++ .../test/resources/ledger_init_test_web2.init | 1 - source/tools/pom.xml | 3 +- .../initializer/LedgerInitProperties.java | 2 +- .../tools/initializer/LocalConfig.java | 2 +- source/tools/tools-mocker/pom.xml | 44 ++ .../mocker/MockerLedgerInitializer.java | 342 +++++++++++++ .../blockchain/mocker/MockerNodeContext.java | 460 ++++++++++++++++++ .../config/LedgerInitWebConfiguration.java | 22 + .../mocker/config/MockerConstant.java | 67 +++ .../mocker/config/PresetAnswerPrompter.java | 32 ++ .../mocker/contracts/AccountContract.java | 17 + .../mocker/contracts/AccountContractImpl.java | 81 +++ .../mocker/contracts/WriteContract.java | 14 + .../mocker/contracts/WriteContractImpl.java | 41 ++ .../com/jd/blockchain/mocker/data/KvData.java | 54 ++ .../blockchain/mocker/data/ResponseData.java | 38 ++ .../handler/MockerContractExeHandle.java | 136 ++++++ .../mocker/handler/MockerNodeHandler.java | 189 +++++++ .../MockerOperationHandleRegister.java | 51 ++ .../mocker/handler/MockerServiceHandler.java | 216 ++++++++ .../mocker/node/GatewayNodeRunner.java | 75 +++ .../mocker/node/NodeWebContext.java | 106 ++++ .../mocker/node/PeerNodeRunner.java | 62 +++ .../mocker/proxy/ContractProxy.java | 80 +++ .../mocker/proxy/ExecutorProxy.java | 34 ++ .../src/main/resources/bftsmart4.config | 167 +++++++ .../src/main/resources/bftsmart8.config | 208 ++++++++ .../src/main/resources/ledger4.init | 72 +++ .../src/main/resources/ledger8.init | 125 +++++ .../jd/blockchain/test/AccountMockerTest.java | 50 ++ .../java/com/jd/blockchain/test/MockTest.java | 54 ++ .../com/jd/blockchain/test/SampleTest.java | 47 ++ 36 files changed, 3173 insertions(+), 9 deletions(-) create mode 100644 source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java create mode 100644 source/tools/tools-mocker/pom.xml create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/LedgerInitWebConfiguration.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/MockerConstant.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/PresetAnswerPrompter.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContract.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/KvData.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/ResponseData.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerNodeHandler.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerOperationHandleRegister.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerServiceHandler.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/GatewayNodeRunner.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/NodeWebContext.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/PeerNodeRunner.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java create mode 100644 source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ExecutorProxy.java create mode 100644 source/tools/tools-mocker/src/main/resources/bftsmart4.config create mode 100644 source/tools/tools-mocker/src/main/resources/bftsmart8.config create mode 100644 source/tools/tools-mocker/src/main/resources/ledger4.init create mode 100644 source/tools/tools-mocker/src/main/resources/ledger8.init create mode 100644 source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/AccountMockerTest.java create mode 100644 source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/MockTest.java create mode 100644 source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/SampleTest.java diff --git a/source/peer/src/test/java/test/com/jd/blockchain/peer/web/ControllerTestConfiguration.java b/source/peer/src/test/java/test/com/jd/blockchain/peer/web/ControllerTestConfiguration.java index 612c97f4..46dad9bc 100644 --- a/source/peer/src/test/java/test/com/jd/blockchain/peer/web/ControllerTestConfiguration.java +++ b/source/peer/src/test/java/test/com/jd/blockchain/peer/web/ControllerTestConfiguration.java @@ -1,6 +1,6 @@ //package test.com.jd.blockchain.peer.web; // -//import org.springframework.boot.test.mock.mockito.MockBean; +//import org.springframework.boot.test.mocker.mockito.MockBean; //import org.springframework.context.annotation.Bean; //import org.springframework.context.annotation.Configuration; // diff --git a/source/peer/src/test/java/test/com/jd/blockchain/peer/web/LedgerInitializingTest.java b/source/peer/src/test/java/test/com/jd/blockchain/peer/web/LedgerInitializingTest.java index 6aa8cbdb..0595ced1 100644 --- a/source/peer/src/test/java/test/com/jd/blockchain/peer/web/LedgerInitializingTest.java +++ b/source/peer/src/test/java/test/com/jd/blockchain/peer/web/LedgerInitializingTest.java @@ -2,7 +2,7 @@ // //import static org.mockito.Matchers.any; //import static org.mockito.Matchers.anyInt; -//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.mocker; //import static org.mockito.Mockito.spy; //import static org.mockito.Mockito.when; // @@ -211,7 +211,7 @@ // //when(keystoreService.getBlockchainKey(key.getAddress())).thenReturn(keyInfo); // //when(keystoreService.sign(any(), key.getAddress())).then(answerSignature(key)); // -// msgBroadcaster = mock(MessageBroadcaster.class); +// msgBroadcaster = mocker(MessageBroadcaster.class); // // LedgerInitializingController ctrl = new LedgerInitializingController(peerSettings, keystoreService, // ledgerService, msgBroadcaster); diff --git a/source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java b/source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java index b6235493..a4a5c45a 100644 --- a/source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java +++ b/source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java @@ -35,8 +35,8 @@ public class BlockchainServiceProxyTest { // // ArgCaptorMatcher txReqCaptor = new ArgCaptorMatcher<>(); // -// TransactionService consensusService = Mockito.mock(TransactionService.class); -// BlockchainQueryService queryService = Mockito.mock(BlockchainQueryService.class); +// TransactionService consensusService = Mockito.mocker(TransactionService.class); +// BlockchainQueryService queryService = Mockito.mocker(BlockchainQueryService.class); // // HashDigest txContentHash =CryptoUtils.hash(CryptoAlgorithm.SHA_256).hash(UUID.randomUUID().toString().getBytes("UTF-8")); // TxResponseMessage expectedResponse = new TxResponseMessage(txContentHash); diff --git a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java new file mode 100644 index 00000000..f5790c06 --- /dev/null +++ b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java @@ -0,0 +1,280 @@ +/** + * Copyright: Copyright 2016-2020 JD.COM All Right Reserved + * FileName: com.jd.blockchain.sdk.client.ClientOperationUtil + * Author: shaozhuguang + * Department: Y事业部 + * Date: 2019/3/27 下午4:12 + * Description: + */ +package com.jd.blockchain.sdk.client; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jd.blockchain.crypto.CryptoProvider; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.transaction.*; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.codec.Base58Utils; +import com.jd.blockchain.utils.codec.HexUtils; +import com.jd.blockchain.utils.io.BytesSlice; +import org.apache.commons.codec.binary.Base64; + +import java.lang.reflect.Field; + +/** + * + * @author shaozhuguang + * @create 2019/3/27 + * @since 1.0.0 + */ + +public class ClientOperationUtil { + + public static Operation read(Operation operation) { + + try { + // Class + Class clazz = operation.getClass(); + Field field = clazz.getSuperclass().getDeclaredField("h"); + field.setAccessible(true); + Object object = field.get(operation); + if (object instanceof JSONObject) { + JSONObject jsonObject = (JSONObject) object; + if (jsonObject.containsKey("accountID")) { + return convertDataAccountRegisterOperation(jsonObject); + } else if (jsonObject.containsKey("userID")) { + return convertUserRegisterOperation(jsonObject); + } else if (jsonObject.containsKey("contractID")) { + return convertContractCodeDeployOperation(jsonObject); + } else if (jsonObject.containsKey("writeSet")) { + return convertDataAccountKVSetOperation(jsonObject); + } else if (jsonObject.containsKey("initSetting")) { + return convertLedgerInitOperation(jsonObject); + } else if (jsonObject.containsKey("contractAddress")) { + return convertContractEventSendOperation(jsonObject); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + return null; + } + + public static Object readValueByBytesValue(BytesValue bytesValue) { + BytesValueType dataType = bytesValue.getType(); + BytesSlice saveVal = bytesValue.getValue(); + Object showVal; + switch (dataType) { + case BYTES: + // return hex + showVal = HexUtils.encode(saveVal.getBytesCopy()); + break; + case TEXT: + case JSON: + showVal = saveVal.getString(); + break; + case INT64: + showVal = saveVal.getLong(); + break; + default: + showVal = HexUtils.encode(saveVal.getBytesCopy()); + break; + } + return showVal; + } + + public static DataAccountRegisterOperation convertDataAccountRegisterOperation(JSONObject jsonObject) { + JSONObject account = jsonObject.getJSONObject("accountID"); + return new DataAccountRegisterOpTemplate(blockchainIdentity(account)); + } + + public static DataAccountKVSetOperation convertDataAccountKVSetOperation(JSONObject jsonObject) { + // 写入集合处理 + JSONArray writeSetObj = jsonObject.getJSONArray("writeSet"); + JSONObject accountAddrObj = jsonObject.getJSONObject("accountAddress"); + String addressBase58 = accountAddrObj.getString("value"); + Bytes address = Bytes.fromBase58(addressBase58); + + DataAccountKVSetOpTemplate kvOperation = new DataAccountKVSetOpTemplate(address); + for (int i = 0; i tools-initializer tools-initializer-booter tools-capability - + tools-mocker + \ No newline at end of file diff --git a/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java b/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java index 2ee028b2..c0f5b5a0 100644 --- a/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java +++ b/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java @@ -127,7 +127,7 @@ public class LedgerInitProperties { return resolve(props); } - private static LedgerInitProperties resolve(Properties props) { + public static LedgerInitProperties resolve(Properties props) { String hexLedgerSeed = PropertiesUtils.getRequiredProperty(props, LEDGER_SEED).replace("-", ""); byte[] ledgerSeed = HexUtils.decode(hexLedgerSeed); LedgerInitProperties initProps = new LedgerInitProperties(ledgerSeed); diff --git a/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LocalConfig.java b/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LocalConfig.java index c3ad268e..08b00bd7 100644 --- a/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LocalConfig.java +++ b/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LocalConfig.java @@ -78,7 +78,7 @@ public class LocalConfig { return resolve(props, null); } - private static LocalConfig resolve(Properties props, String initSettingFile) { + public static LocalConfig resolve(Properties props, String initSettingFile) { LocalConfig conf = new LocalConfig(); diff --git a/source/tools/tools-mocker/pom.xml b/source/tools/tools-mocker/pom.xml new file mode 100644 index 00000000..65235636 --- /dev/null +++ b/source/tools/tools-mocker/pom.xml @@ -0,0 +1,44 @@ + + + + + tools + com.jd.blockchain + 0.9.0-SNAPSHOT + + 4.0.0 + + tools-mocker + + tools-mocker + + + + com.jd.blockchain + peer + ${project.version} + + + com.jd.blockchain + gateway + ${project.version} + + + com.jd.blockchain + tools-initializer + ${project.version} + + + com.jd.blockchain + sdk-client + ${project.version} + + + com.jd.blockchain + crypto-classic + ${project.version} + + + + diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java new file mode 100644 index 00000000..b03d88af --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java @@ -0,0 +1,342 @@ +package com.jd.blockchain.mocker; + +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.consensus.ConsensusProvider; +import com.jd.blockchain.consensus.ConsensusProviders; +import com.jd.blockchain.consensus.ConsensusSettings; +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; +import com.jd.blockchain.crypto.service.sm.SMCryptoService; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.ledger.core.impl.LedgerManager; +import com.jd.blockchain.storage.service.DbConnection; +import com.jd.blockchain.storage.service.DbConnectionFactory; +import com.jd.blockchain.tools.initializer.*; +import com.jd.blockchain.tools.initializer.LedgerInitProperties.ConsensusParticipantConfig; +import com.jd.blockchain.tools.initializer.web.LedgerInitConsensusService; +import com.jd.blockchain.tools.initializer.web.LedgerInitDecisionData; +import com.jd.blockchain.transaction.DigitalSignatureBlob; +import com.jd.blockchain.transaction.LedgerInitSettingData; +import com.jd.blockchain.transaction.TxBuilder; +import com.jd.blockchain.transaction.TxRequestBuilder; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.concurrent.InvocationResult; +import com.jd.blockchain.utils.io.BytesUtils; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.*; + +/** + * 账本初始化控制器; + * + * @author huanghaiquan + * + */ +public class MockerLedgerInitializer implements LedgerInitProcess, LedgerInitConsensusService { + + static { + DataContractRegistry.register(TransactionRequest.class); + } + + private static final String[] SUPPORTED_PROVIDERS = { + ClassicCryptoService.class.getName(), + SMCryptoService.class.getName() }; + + private static final String DEFAULT_SIGN_ALGORITHM = "ED25519"; + + private final SignatureFunction SIGN_FUNC; + + private volatile LedgerInitPermission localPermission; + + private TransactionContent initTxContent; + + private volatile int currentId = -1; + + private volatile LedgerInitSetting ledgerInitSetting; + +// private volatile LedgerInitPermission[] permissions; +// private volatile LedgerInitPermission permission; + + private volatile Prompter prompter; + + private volatile ConsensusProvider consensusProvider; + + private volatile LedgerBlock genesisBlock; + + private volatile LedgerInitDecision localDecision; + + private volatile DecisionResultHandle[] decisions; + + private volatile DbConnection dbConn; + + private volatile LedgerEditor ledgerEditor; + + private LedgerManager ledgerManager; + + private DbConnectionFactory dbConnFactory; + + public MockerLedgerInitializer() { + this.SIGN_FUNC = Crypto.getSignatureFunction(DEFAULT_SIGN_ALGORITHM); + } + + public MockerLedgerInitializer(DbConnectionFactory dbConnFactory, LedgerManager ledgerManager) { + this.SIGN_FUNC = Crypto.getSignatureFunction(DEFAULT_SIGN_ALGORITHM); + this.dbConnFactory = dbConnFactory; + this.ledgerManager = ledgerManager; + } + + public int getId() { + return currentId; + } + + public TransactionContent getInitTxContent() { + return initTxContent; + } + + public LedgerInitPermission getLocalPermission() { + return localPermission; + } + + public LedgerInitDecision getLocalDecision() { + return localDecision; + } + + public void setPrompter(Prompter prompter) { + this.prompter = prompter; + } + + private void setConsensusProvider(ConsensusProvider consensusProvider) { + this.consensusProvider = consensusProvider; + } + + @Override + public HashDigest initialize(int currentId, PrivKey privKey, LedgerInitProperties ledgerInitProps, + DBConnectionConfig dbConnConfig, Prompter prompter) { + return initialize(currentId, privKey, ledgerInitProps, dbConnConfig, prompter, createDefaultCryptoSetting()); + } + + @Override + public synchronized HashDigest initialize(int currentId, PrivKey privKey, LedgerInitProperties ledgerInitProps, + DBConnectionConfig dbConnConfig, Prompter prompter, CryptoSetting cryptoSetting) { + + if (this.ledgerInitSetting != null) { + throw new IllegalStateException("ledger init process has already started."); + } + + setPrompter(prompter); + + ConsensusProvider csProvider = ConsensusProviders.getProvider(ledgerInitProps.getConsensusProvider()); + setConsensusProvider(csProvider); + + prompter.info("Init settings and sign permision..."); + + prepareLocalPermission(currentId, privKey, ledgerInitProps, null, cryptoSetting); + + try { + // 连接数据库; + connectDb(dbConnConfig); + + // 生成账本; + makeLocalDecision(privKey); + + // 获取其它参与方的账本生成结果; + return consensusDecisions(); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + closeDb(); + } + } + + public DbConnection connectDb(DBConnectionConfig dbConnConfig) { + this.dbConn = dbConnFactory.connect(dbConnConfig.getUri(), dbConnConfig.getPassword()); + return dbConn; + } + + public LedgerInitDecision makeLocalDecision(PrivKey privKey) { + // 生成账本; + this.ledgerEditor = ledgerManager.newLedger(this.ledgerInitSetting, dbConn.getStorageService()); + this.genesisBlock = initLedgerDataset(ledgerEditor); + + // 生成签名决定; + this.localDecision = makeDecision(currentId, genesisBlock.getHash(), privKey); + this.decisions = new DecisionResultHandle[this.ledgerInitSetting.getConsensusParticipants().length]; + for (int i = 0; i < decisions.length; i++) { + // 参与者的 id 是依次递增的; + this.decisions[i] = new DecisionResultHandle(i); + } + // 预置当前参与方的“决定”到列表,避免向自己发起请求; + this.decisions[currentId].setValue(localDecision); + return localDecision; + } + + public HashDigest consensusDecisions() { + // 执行提交提交; + ledgerEditor.commit(); + return genesisBlock.getHash(); + } + + public void closeDb() { + if (dbConn != null) { + DbConnection connection = dbConn; + dbConn = null; + try { + connection.close(); + } catch (IOException e) { + prompter.error(e, "Error occurred on closing db connection! --" + e.getMessage()); + } + } + } + + public CryptoSetting createDefaultCryptoSetting() { + CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; + for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { + supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); + } + CryptoConfig defCryptoSetting = new CryptoConfig(); + defCryptoSetting.setSupportedProviders(supportedProviders); + defCryptoSetting.setAutoVerifyHash(true); + defCryptoSetting.setHashAlgorithm(Crypto.getAlgorithm("SHA256")); + + return defCryptoSetting; + } + + public LedgerInitPermission prepareLocalPermission(int currentId, PrivKey privKey, LedgerInitProperties ledgerProps, + ConsensusSettings csSettings, CryptoSetting cryptoSetting) { + // 创建初始化配置; + LedgerInitSettingData initSetting = new LedgerInitSettingData(); + initSetting.setLedgerSeed(ledgerProps.getLedgerSeed()); + initSetting.setCryptoSetting(cryptoSetting); + + List partiList = ledgerProps.getConsensusParticipants(); + ConsensusParticipantConfig[] parties = partiList.toArray(new ConsensusParticipantConfig[partiList.size()]); + ConsensusParticipantConfig[] orderedParties = sortAndVerify(parties); + initSetting.setConsensusParticipants(orderedParties); + + // 创建默认的共识配置; + try { + byte[] csSettingBytes = new byte[1024]; + new Random().nextBytes(csSettingBytes); + + initSetting.setConsensusProvider(consensusProvider.getName()); + initSetting.setConsensusSettings(new Bytes(csSettingBytes)); + } catch (Exception e) { + throw new LedgerInitException("Create default consensus config failed! --" + e.getMessage(), e); + } + + if (currentId < 0 || currentId >= orderedParties.length) { + throw new LedgerInitException("Your id is out of bound of participant list!"); + } + this.currentId = currentId; + this.ledgerInitSetting = initSetting; + + // 校验当前的公钥、私钥是否匹配; + byte[] testBytes = BytesUtils.toBytes(currentId); + SignatureDigest testSign = SIGN_FUNC.sign(privKey, testBytes); + PubKey myPubKey = orderedParties[currentId].getPubKey(); + if (!SIGN_FUNC.verify(testSign, myPubKey, testBytes)) { + throw new LedgerInitException("Your pub-key specified in the init-settings isn't match your priv-key!"); + } + // 生成初始化交易,并签署许可; + TransactionBuilder initTxBuilder = new TxBuilder(null);// 账本初始化交易的账本 hash 为 null; + initTxBuilder.ledgers().create(initSetting); + for (ParticipantNode p : initSetting.getConsensusParticipants()) { + // TODO:暂时只支持注册用户的初始化操作; + BlockchainIdentity superUserId = new BlockchainIdentityData(p.getPubKey()); + initTxBuilder.users().register(superUserId); + } + this.initTxContent = initTxBuilder.prepareContent(); + + // 对初始交易签名,生成当前参与者的账本初始化许可; + SignatureDigest permissionSign = TxRequestBuilder.sign(initTxContent, privKey); + localPermission = new LedgerInitPermissionData(currentId, permissionSign); + + this.currentId = currentId; + return localPermission; + } + + private LedgerInitDecision makeDecision(int participantId, HashDigest ledgerHash, PrivKey privKey) { + byte[] dataBytes = getDecisionBytes(participantId, ledgerHash); + SignatureFunction signFunc = Crypto.getSignatureFunction(privKey.getAlgorithm()); + SignatureDigest signature = signFunc.sign(privKey, dataBytes); + + LedgerInitDecisionData decision = new LedgerInitDecisionData(); + decision.setParticipantId(participantId); + decision.setLedgerHash(ledgerHash); + decision.setSignature(signature); + return decision; + } + + private LedgerBlock initLedgerDataset(LedgerEditor ledgerEditor) { + // 初始化时,自动将参与方注册为账本的用户; + TxRequestBuilder txReqBuilder = new TxRequestBuilder(this.initTxContent); +// ParticipantNode[] parties = this.ledgerInitSetting.getConsensusParticipants(); + ParticipantNode parti = this.ledgerInitSetting.getConsensusParticipants()[currentId]; + + PubKey pubKey = parti.getPubKey(); + SignatureDigest signDigest = this.localPermission.getTransactionSignature(); + DigitalSignatureBlob digitalSignature = new DigitalSignatureBlob(pubKey, signDigest); + txReqBuilder.addNodeSignature(digitalSignature); + + TransactionRequest txRequest = txReqBuilder.buildRequest(); + + LedgerTransactionContext txCtx = ledgerEditor.newTransaction(txRequest); + Operation[] ops = txRequest.getTransactionContent().getOperations(); + // 注册用户; 注:第一个操作是 LedgerInitOperation; + // TODO:暂时只支持注册用户的初始化操作; + for (int i = 1; i < ops.length; i++) { + UserRegisterOperation userRegOP = (UserRegisterOperation) ops[i]; + txCtx.getDataSet().getUserAccountSet().register(userRegOP.getUserID().getAddress(), + userRegOP.getUserID().getPubKey()); + } + + txCtx.commit(TransactionState.SUCCESS); + + return ledgerEditor.prepare(); + } + + private byte[] getDecisionBytes(int participantId, HashDigest ledgerHash) { + return BytesUtils.concat(BytesUtils.toBytes(participantId), ledgerHash.toBytes()); + } + + @Override + public LedgerInitPermission requestPermission(int requesterId, SignatureDigest signature) { + return localPermission; + } + + @Override + public LedgerInitDecision synchronizeDecision(@RequestBody LedgerInitDecision initDecision) { + return localDecision; + } + + /** + * 对参与者列表按照 id 进行升序排列,并校验id是否从 1 开始且没有跳跃; + * + * @param parties + * @return + */ + private ConsensusParticipantConfig[] sortAndVerify(ConsensusParticipantConfig[] parties) { + Arrays.sort(parties, (o1, o2) -> o1.getId() - o2.getId()); + for (int i = 0; i < parties.length; i++) { + if (parties[i].getId() != i) { + throw new LedgerInitException( + "The ids of participants are not match their positions in the participant-list!"); + } + } + return parties; + } + + private static class DecisionResultHandle extends InvocationResult { + + private final int PARTICIPANT_ID; + + public DecisionResultHandle(int participantId) { + this.PARTICIPANT_ID = participantId; + } + + } + +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java new file mode 100644 index 00000000..08df2cc5 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java @@ -0,0 +1,460 @@ +package com.jd.blockchain.mocker; + +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.consensus.ClientIdentification; +import com.jd.blockchain.consensus.ClientIdentifications; +import com.jd.blockchain.consensus.action.ActionRequest; +import com.jd.blockchain.consensus.action.ActionResponse; +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; +import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; +import com.jd.blockchain.crypto.service.sm.SMCryptoService; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.core.CryptoConfig; +import com.jd.blockchain.ledger.core.LedgerDataSet; +import com.jd.blockchain.ledger.core.LedgerEditor; +import com.jd.blockchain.ledger.core.LedgerRepository; +import com.jd.blockchain.ledger.core.impl.LedgerManager; +import com.jd.blockchain.ledger.core.impl.LedgerQueryService; +import com.jd.blockchain.ledger.core.impl.TransactionBatchProcessor; +import com.jd.blockchain.mocker.config.MockerConstant; +import com.jd.blockchain.mocker.config.PresetAnswerPrompter; +import com.jd.blockchain.mocker.handler.MockerContractExeHandle; +import com.jd.blockchain.mocker.handler.MockerOperationHandleRegister; +import com.jd.blockchain.mocker.proxy.ContractProxy; +import com.jd.blockchain.service.TransactionBatchResultHandle; +import com.jd.blockchain.storage.service.DbConnectionFactory; +import com.jd.blockchain.storage.service.utils.MemoryDBConnFactory; +import com.jd.blockchain.tools.initializer.DBConnectionConfig; +import com.jd.blockchain.tools.initializer.LedgerInitProperties; +import com.jd.blockchain.tools.keygen.KeyGenCommand; +import com.jd.blockchain.transaction.*; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.web.serializes.ByteArrayObjectUtil; + +import java.util.*; + +import static java.lang.reflect.Proxy.newProxyInstance; + +public class MockerNodeContext implements BlockchainQueryService { + + private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), + SMCryptoService.class.getName() }; + + private static final DBConnectionConfig dbConnectionConfig = new DBConnectionConfig("memory://local/0"); + + private DbConnectionFactory dbConnFactory = new MemoryDBConnFactory(); + + private MockerOperationHandleRegister opHandler = new MockerOperationHandleRegister(); + + private MockerContractExeHandle contractExeHandle = new MockerContractExeHandle(); + + private Map participants = new HashMap<>(); + + private LedgerManager ledgerManager = new LedgerManager(); + + private BlockchainKeypair defaultKeypair; + + private LedgerRepository ledgerRepository; + + private LedgerQueryService queryService; + + private HashDigest ledgerHash; + + private String ledgerSeed; + + static { + DataContractRegistry.register(TransactionContent.class); + DataContractRegistry.register(TransactionContentBody.class); + DataContractRegistry.register(TransactionRequest.class); + DataContractRegistry.register(NodeRequest.class); + DataContractRegistry.register(EndpointRequest.class); + DataContractRegistry.register(TransactionResponse.class); + + DataContractRegistry.register(Operation.class); + DataContractRegistry.register(ContractCodeDeployOperation.class); + DataContractRegistry.register(ContractEventSendOperation.class); + DataContractRegistry.register(DataAccountRegisterOperation.class); + DataContractRegistry.register(UserRegisterOperation.class); + DataContractRegistry.register(DataAccountKVSetOperation.class); + DataContractRegistry.register(DataAccountKVSetOperation.KVWriteEntry.class); + + DataContractRegistry.register(ActionRequest.class); + DataContractRegistry.register(ActionResponse.class); + DataContractRegistry.register(ClientIdentifications.class); + DataContractRegistry.register(ClientIdentification.class); + + ByteArrayObjectUtil.init(); + } + + public MockerNodeContext() { + } + + public MockerNodeContext(String ledgerSeed) { + this.ledgerSeed = ledgerSeed; + } + + public MockerNodeContext participants(String name, BlockchainKeypair partiKey) { + participants.put(name, partiKey); + return this; + } + + public MockerNodeContext participants(BlockchainKeypair partiKey) { + participants.put(partiKey.getPubKey().toBase58(), partiKey); + return this; + } + + public MockerNodeContext build() { + if (ledgerSeed == null || ledgerSeed.length() == 0) { + ledgerSeed = MockerConstant.DEFAULT_LEDGER_SEED; + } + if (participants.size() < 4) { + // 缺少的需要补充,使用常量中的内容进行补充 + for (int i = 0; i < MockerConstant.PUBLIC_KEYS.length; i++) { + String pubKeyString = MockerConstant.PUBLIC_KEYS[i]; + boolean isExist = false; + // 通过公钥进行判断 + for (Map.Entry entry : participants.entrySet()) { + String existPubKey = KeyGenCommand.encodePubKey(entry.getValue().getPubKey()); + if (pubKeyString.equals(existPubKey)) { + isExist = true; + } + } + if (!isExist) { + // 加入系统中 + PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(MockerConstant.PRIVATE_KEYS[i], MockerConstant.PASSWORD); + PubKey pubKey = KeyGenCommand.decodePubKey(MockerConstant.PUBLIC_KEYS[i]); + participants(new BlockchainKeypair(pubKey, privKey)); + } + if (participants.size() >= 4) { + break; + } + } + } + + LedgerInitProperties ledgerInitProperties = loadInitSetting(); + + MockerLedgerInitializer mockLedgerInitializer = new MockerLedgerInitializer(dbConnFactory, ledgerManager); + + ledgerHash = mockLedgerInitializer.initialize(0, defaultKeypair.getPrivKey(), + ledgerInitProperties, dbConnectionConfig, new PresetAnswerPrompter("N"), cryptoConfig()); + + ledgerRepository = registerLedger(ledgerHash, dbConnectionConfig); + + queryService = new LedgerQueryService(ledgerManager); + + contractExeHandle.initLedger(ledgerManager, ledgerHash); + + opHandler.registerHandler(contractExeHandle); + + return this; + } + + public String registerUser(BlockchainKeypair user) { + TxBuilder txBuilder = txBuilder(); + txBuilder.users().register(user.getIdentity()); + txProcess(txRequest(txBuilder)); + return user.getAddress().toBase58(); + } + + public String registerDataAccount(BlockchainKeypair dataAccount) { + TxBuilder txBuilder = txBuilder(); + txBuilder.dataAccounts().register(dataAccount.getIdentity()); + txProcess(txRequest(txBuilder)); + return dataAccount.getAddress().toBase58(); + } + + public String registerDataAccount() { + return registerDataAccount(BlockchainKeyGenerator.getInstance().generate()); + } + + public void writeKv(String address, String key, String value, long version) { + TxBuilder txBuilder = txBuilder(); + txBuilder.dataAccount(address).set(key, value, version); + txProcess(txRequest(txBuilder)); + } + + public void writeKv(String address, String key, long value, long version) { + TxBuilder txBuilder = txBuilder(); + txBuilder.dataAccount(address).set(key, value, version); + txProcess(txRequest(txBuilder)); + } + + public void writeKv(String address, String key, byte[] value, long version) { + TxBuilder txBuilder = txBuilder(); + txBuilder.dataAccount(address).set(key, value, version); + txProcess(txRequest(txBuilder)); + } + + public void writeKv(String address, String key, Bytes value, long version) { + TxBuilder txBuilder = txBuilder(); + txBuilder.dataAccount(address).set(key, value, version); + txProcess(txRequest(txBuilder)); + } + + public T deployContract(T contract) { + // 首先发布合约 + BlockchainIdentity identity = deployContract2Ledger(contract); + // 生成代理对象 + ContractProxy contractProxy = new ContractProxy<>(identity, this, + contract, contractExeHandle); + + T proxy = (T) newProxyInstance(contract.getClass().getClassLoader(), + contract.getClass().getInterfaces(), contractProxy); + + return proxy; + } + + private BlockchainIdentity deployContract2Ledger(Object contract) { + BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity(); + // 合约发布 + // 注意此处只是将其放入内存中,而不需要真正编译为字节码 + TxBuilder txBuilder = txBuilder(); + txBuilder.contracts().deploy(contractIdentity, contract.getClass().getName().getBytes()); + // 执行 + txProcess(txRequest(txBuilder)); + return contractIdentity; + } + + public String getLedgerSeed() { + return ledgerSeed; + } + + public HashDigest getLedgerHash() { + return ledgerHash; + } + + @Override + public HashDigest[] getLedgerHashs() { + return queryService.getLedgerHashs(); + } + + @Override + public LedgerInfo getLedger(HashDigest ledgerHash) { + return queryService.getLedger(ledgerHash); + } + + @Override + public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { + return queryService.getConsensusParticipants(ledgerHash); + } + + @Override + public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { + return queryService.getLedgerMetadata(ledgerHash); + } + + @Override + public LedgerBlock getBlock(HashDigest ledgerHash, long height) { + return queryService.getBlock(ledgerHash, height); + } + + @Override + public LedgerBlock getBlock(HashDigest ledgerHash, HashDigest blockHash) { + return queryService.getBlock(ledgerHash, blockHash); + } + + @Override + public long getTransactionCount(HashDigest ledgerHash, long height) { + return queryService.getTransactionCount(ledgerHash, height); + } + + @Override + public long getTransactionCount(HashDigest ledgerHash, HashDigest blockHash) { + return queryService.getTransactionCount(ledgerHash, blockHash); + } + + @Override + public long getTransactionTotalCount(HashDigest ledgerHash) { + return queryService.getTransactionTotalCount(ledgerHash); + } + + @Override + public long getDataAccountCount(HashDigest ledgerHash, long height) { + return queryService.getDataAccountCount(ledgerHash, height); + } + + @Override + public long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash) { + return queryService.getDataAccountCount(ledgerHash, blockHash); + } + + @Override + public long getDataAccountTotalCount(HashDigest ledgerHash) { + return queryService.getDataAccountTotalCount(ledgerHash); + } + + @Override + public long getUserCount(HashDigest ledgerHash, long height) { + return queryService.getUserCount(ledgerHash, height); + } + + @Override + public long getUserCount(HashDigest ledgerHash, HashDigest blockHash) { + return queryService.getUserCount(ledgerHash, blockHash); + } + + @Override + public long getUserTotalCount(HashDigest ledgerHash) { + return queryService.getUserTotalCount(ledgerHash); + } + + @Override + public long getContractCount(HashDigest ledgerHash, long height) { + return queryService.getContractCount(ledgerHash, height); + } + + @Override + public long getContractCount(HashDigest ledgerHash, HashDigest blockHash) { + return queryService.getContractCount(ledgerHash, blockHash); + } + + @Override + public long getContractTotalCount(HashDigest ledgerHash) { + return queryService.getContractTotalCount(ledgerHash); + } + + @Override + public LedgerTransaction[] getTransactions(HashDigest ledgerHash, long height, int fromIndex, int count) { + return queryService.getTransactions(ledgerHash, height, fromIndex, count); + } + + @Override + public LedgerTransaction[] getTransactions(HashDigest ledgerHash, HashDigest blockHash, int fromIndex, int count) { + return queryService.getTransactions(ledgerHash, blockHash, fromIndex, count); + } + + @Override + public LedgerTransaction getTransactionByContentHash(HashDigest ledgerHash, HashDigest contentHash) { + return queryService.getTransactionByContentHash(ledgerHash, contentHash); + } + + @Override + public TransactionState getTransactionStateByContentHash(HashDigest ledgerHash, HashDigest contentHash) { + return queryService.getTransactionStateByContentHash(ledgerHash, contentHash); + } + + @Override + public UserInfo getUser(HashDigest ledgerHash, String address) { + return queryService.getUser(ledgerHash, address); + } + + @Override + public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { + return queryService.getDataAccount(ledgerHash, address); + } + + @Override + public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { + return queryService.getDataEntries(ledgerHash, address, keys); + } + + @Override + public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { + return queryService.getDataEntries(ledgerHash, address, kvInfoVO); + } + + @Override + public long getDataEntriesTotalCount(HashDigest ledgerHash, String address) { + return queryService.getDataEntriesTotalCount(ledgerHash, address); + } + + @Override + public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { + return queryService.getDataEntries(ledgerHash, address, fromIndex, count); + } + + @Override + public AccountHeader getContract(HashDigest ledgerHash, String address) { + return queryService.getContract(ledgerHash, address); + } + + @Override + public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { + return queryService.getUsers(ledgerHash, fromIndex, count); + } + + @Override + public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { + return queryService.getDataAccounts(ledgerHash, fromIndex, count); + } + + @Override + public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { + return queryService.getContractAccounts(ledgerHash, fromIndex, count); + } + + public TxBuilder txBuilder() { + return new TxBuilder(ledgerHash); + } + + public TransactionRequest txRequest(TxBuilder txBuilder) { + TransactionRequestBuilder reqBuilder = txBuilder.prepareRequest(); + reqBuilder.signAsEndpoint(defaultKeypair); + return reqBuilder.buildRequest(); + } + + public void txProcess(TransactionRequest txRequest) { + LedgerEditor newEditor = ledgerRepository.createNextBlock(); + LedgerBlock latestBlock = ledgerRepository.getLatestBlock(); + LedgerDataSet previousDataSet = ledgerRepository.getDataSet(latestBlock); + TransactionBatchProcessor txProc = new TransactionBatchProcessor(newEditor, previousDataSet, opHandler, + ledgerManager); + txProc.schedule(txRequest); + TransactionBatchResultHandle handle = txProc.prepare(); + handle.commit(); + } + + private LedgerRepository registerLedger(HashDigest ledgerHash, DBConnectionConfig dbConnConf) { + return ledgerManager.register(ledgerHash, dbConnFactory.connect(dbConnConf.getUri()).getStorageService()); + } + + private CryptoConfig cryptoConfig() { + CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; + for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { + supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); + } + CryptoConfig cryptoSetting = new CryptoConfig(); + cryptoSetting.setSupportedProviders(supportedProviders); + cryptoSetting.setAutoVerifyHash(false); + cryptoSetting.setHashAlgorithm(ClassicAlgorithm.SHA256); + return cryptoSetting; + } + + private LedgerInitProperties loadInitSetting() { + + Properties ledgerProp = new Properties(); + + ledgerProp.put(LedgerInitProperties.LEDGER_SEED, ledgerSeed); + + ledgerProp.put("ledger.name", MockerConstant.LEDGER_NAME); + + ledgerProp.put(LedgerInitProperties.CONSENSUS_SERVICE_PROVIDER, "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"); + + ledgerProp.put(LedgerInitProperties.CONSENSUS_CONFIG, "classpath:bftsmart.config"); + + ledgerProp.put(LedgerInitProperties.CRYPTO_SERVICE_PROVIDERS, "com.jd.blockchain.crypto.service.classic.ClassicCryptoService," + + "com.jd.blockchain.crypto.service.sm.SMCryptoService"); + + ledgerProp.put(LedgerInitProperties.PART_COUNT, String.valueOf(participants.size())); + + int partiIndex = 0; + for (Map.Entry entry : participants.entrySet()) { + String name = entry.getKey(); + BlockchainKeypair keypair = entry.getValue(); + if (partiIndex == 0) { + defaultKeypair = keypair; + } + String partiPrefix = String.format(LedgerInitProperties.PART_ID_PATTERN, partiIndex) + "."; + ledgerProp.put(partiPrefix + LedgerInitProperties.PART_NAME, name); + ledgerProp.put(partiPrefix + LedgerInitProperties.PART_PUBKEY_PATH, ""); + ledgerProp.put(partiPrefix + LedgerInitProperties.PART_PUBKEY, KeyGenCommand.encodePubKey(keypair.getPubKey())); + ledgerProp.put(partiPrefix + LedgerInitProperties.PART_INITIALIZER_HOST, MockerConstant.LOCAL_ADDRESS); + ledgerProp.put(partiPrefix + LedgerInitProperties.PART_INITIALIZER_PORT, String.valueOf(MockerConstant.LEDGER_INIT_PORT_START + partiIndex * 10)); + ledgerProp.put(partiPrefix + LedgerInitProperties.PART_INITIALIZER_SECURE, String.valueOf(false)); + partiIndex++; + } + + return LedgerInitProperties.resolve(ledgerProp); + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/LedgerInitWebConfiguration.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/LedgerInitWebConfiguration.java new file mode 100644 index 00000000..11f6a762 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/LedgerInitWebConfiguration.java @@ -0,0 +1,22 @@ +package com.jd.blockchain.mocker.config; + +import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; +import com.jd.blockchain.tools.initializer.web.InitWebSecurityConfiguration; +import com.jd.blockchain.tools.initializer.web.InitWebServerConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@SpringBootApplication +@Configuration +@EnableConfigurationProperties +@Import(value = { InitWebServerConfiguration.class, InitWebSecurityConfiguration.class }) +public class LedgerInitWebConfiguration { + + @Bean + public CompositeConnectionFactory getCompositeConnectionFactory() { + return new CompositeConnectionFactory(); + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/MockerConstant.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/MockerConstant.java new file mode 100644 index 00000000..e52f02bd --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/MockerConstant.java @@ -0,0 +1,67 @@ +package com.jd.blockchain.mocker.config; + +public class MockerConstant { + + public static final String DEFAULT_LEDGER_SEED = "932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffa"; + + public static final int PEER_PORT_START = 12000; + + public static final int LEDGER_INIT_PORT_START = 1600; + + public static final int GATEWAY_PORT = 11000; + + public static final String LOCAL_ADDRESS = "127.0.0.1"; + + public static final String LEDGER_NAME = "JDChain"; + + public static final String LEDGER_INIT_FORMATTER = "ledger%s.init"; + + public static final String[] CONSENSUS_PROVIDERS = new String[] {"com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"}; + + public static final String PASSWORD = "abc"; + + public static final String PASSWORD_ENCODE = "DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY"; + + public static final String[] PUBLIC_KEYS = { + "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", + "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", + "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", + "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk", + "3snPdw7i7PXPRMp3EAjsxJkHe7aZJRLNzdW8kEHBWeQsSgcPAiHP2J", + "3snPdw7i7PmmQoPgUpUmmAUj6nakHj8wMSQmiMi1RaiZp4YU1D4AXk", + "3snPdw7i7PiJKsa94q3EcLT1y6GRJ7LeFGe799hdzRRHmf6LNodyiM", + "3snPdw7i7Pm2wJwEnKn8kK8eGTkN36C2BZRRjVTr9FPB2rqtcgTq7h" + }; + + public static final String[] ADDRESS_ARRAY = { + "LdeP3fY7jJbNwL8CiL2wU21AF9unDWQjVEW5w", + "LdeNnz88dH6CA6PwkVdn3nFRibUKP3sFT2byG", + "LdeNmdpT4DiTwLUP9jRQhwdRBRiXeHno456vy", + "LdeNekdXMHqyz9Qxc2jDSBnkvvZLbty6pRDdP", + "LdeNryu2DK96tDvtLJfBz7ArWynAWPJAep38n", + "LdeNkoQpXffVF9qjsa4A7wZVgT9W2vnhpEEm5", + "LdeNzfFrsJT7Ni1L7k1EP3NuxUfK8QGAxMGpt", + "LdeNuLhR5AoyhQoVeS15haJvvGC5ByoPezrGq" + }; + + public static final String[] PRIVATE_KEYS = { + "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", + "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", + "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", + "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns", + "177gjwyHzfmsD4g3MVB655seYWXua2KBdQEqTf9kHgeMc6gdRZADKb6cL13L5koqMsBtkGX", + "177gk2C9V7gwPhAGgawL53W8idDpSo63jnbg8finbZkk4zermr5aqgTeKspN45fbymey8t6", + "177gjtz29TXa2E3FFBpCNr5LpU5zYxkNPAgcAJZW7tCGUgWQr4gcVv8PHmoVVPeSVVnyZV5", + "177gjzpHnqGEuSKyi3pW69WhpEPmeFPxLNVmUfXQb4DDV2EfnMgY7T4NFsyRsThjJFsau7X"}; + + public static final String[] DB_MEMS = { + "memory://127.0.0.1/0", + "memory://127.0.0.1/1", + "memory://127.0.0.1/2", + "memory://127.0.0.1/3", + "memory://127.0.0.1/4", + "memory://127.0.0.1/5", + "memory://127.0.0.1/6", + "memory://127.0.0.1/7" + }; +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/PresetAnswerPrompter.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/PresetAnswerPrompter.java new file mode 100644 index 00000000..bb93d7e1 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/PresetAnswerPrompter.java @@ -0,0 +1,32 @@ +package com.jd.blockchain.mocker.config; + +import com.jd.blockchain.tools.initializer.ConsolePrompter; + +import java.util.Properties; + +public class PresetAnswerPrompter extends ConsolePrompter { + + private Properties answers = new Properties(); + + private String defaultAnswer; + + public PresetAnswerPrompter(String defaultAnswer) { + this.defaultAnswer = defaultAnswer; + } + + public void setAnswer(String tag, String answer) { + answers.setProperty(tag, answer); + } + + public void setDefaultAnswer(String defaultAnswer) { + this.defaultAnswer = defaultAnswer; + } + + @Override + public String confirm(String tag, String format, Object... args) { + System.out.print(String.format(format, args)); + String answer = answers.getProperty(tag, defaultAnswer); + System.out.println(String.format("\r\n [Mocked answer:%s]", answer)); + return answer; + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContract.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContract.java new file mode 100644 index 00000000..d42d6458 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContract.java @@ -0,0 +1,17 @@ +package com.jd.blockchain.mocker.contracts; + +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; + +@Contract +public interface AccountContract { + + @ContractEvent(name = "create") + void create(String address, String account, long money); + + @ContractEvent(name = "transfer") + void transfer(String address, String from, String to, long money); + + @ContractEvent(name = "print") + void print(String address, String from, String to); +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java new file mode 100644 index 00000000..15132de2 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java @@ -0,0 +1,81 @@ +package com.jd.blockchain.mocker.contracts; + +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.KVDataEntry; + +public class AccountContractImpl implements EventProcessingAwire, AccountContract { + + private ContractEventContext eventContext; + + private HashDigest ledgerHash; + + @Override + public void create(String address, String account, long money) { + // 暂不处理该账户已经存在的问题 + eventContext.getLedger().dataAccount(address).set(account, money, -1); + } + + @Override + public void transfer(String address, String from, String to, long money) { + // 首先分别查询from与to的结果 + KVDataEntry[] dataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); + long currentFromMoney = 0L, currentToMoney = 0L, currentFromVer = -1L, currentToVer = -1L; + if (dataEntries != null && dataEntries.length > 0) { + for (KVDataEntry dataEntry : dataEntries) { + String key = dataEntry.getKey(); + Object value = dataEntry.getValue(); + long version = dataEntry.getVersion(); + if (key.equals(from)) { + currentFromMoney = (long) value; + currentFromVer = version; + } + if (key.equals(to)) { + currentToMoney = (long) value; + currentToVer = version; + } + } + } + currentFromMoney -= money; + currentToMoney += money; + // 重新设置结果 + eventContext.getLedger().dataAccount(address).set(from, currentFromMoney, currentFromVer) + .set(to, currentToMoney, currentToVer); + } + + @Override + public void print(String address, String from, String to) { + KVDataEntry[] dataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); + if (dataEntries != null && dataEntries.length > 0) { + for (KVDataEntry dataEntry : dataEntries) { + String key = dataEntry.getKey(); + Object value = dataEntry.getValue(); + long version = dataEntry.getVersion(); + System.out.printf("Key = %s Value = %s Version = %s \r\n", key, value, version); + } + } + } + + @Override + public void beforeEvent(ContractEventContext eventContext) { + this.eventContext = eventContext; + this.ledgerHash = this.eventContext.getCurrentLedgerHash(); + } + + @Override + public void postEvent(ContractEventContext eventContext, ContractException error) { + + } + + @Override + public void postEvent(ContractException error) { + + } + + @Override + public void postEvent() { + + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java new file mode 100644 index 00000000..2dbd8ae5 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java @@ -0,0 +1,14 @@ +package com.jd.blockchain.mocker.contracts; + +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; + +@Contract +public interface WriteContract { + + @ContractEvent(name = "print") + void print(String name); + + @ContractEvent(name = "writeKv") + void writeKv(String address, String key, String value); +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java new file mode 100644 index 00000000..fd850d19 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java @@ -0,0 +1,41 @@ +package com.jd.blockchain.mocker.contracts; + +import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.contract.EventProcessingAwire; + +public class WriteContractImpl implements EventProcessingAwire, WriteContract { + + private ContractEventContext eventContext; + + @Override + public void print(String name) { + System.out.printf("My Name is %s \r\n", name); + System.out.printf("My Ledger Hash is %s \r\n", eventContext.getCurrentLedgerHash().toBase58()); + } + + @Override + public void writeKv(String address, String key, String value) { + eventContext.getLedger().dataAccount(address).set(key, value, -1); + } + + @Override + public void beforeEvent(ContractEventContext eventContext) { + this.eventContext = eventContext; + } + + @Override + public void postEvent(ContractEventContext eventContext, ContractException error) { + System.out.println("----- postEvent1 -----"); + } + + @Override + public void postEvent(ContractException error) { + System.out.println("----- postEvent2 -----"); + } + + @Override + public void postEvent() { + System.out.println("----- postEvent3 -----"); + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/KvData.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/KvData.java new file mode 100644 index 00000000..ec6cce3d --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/KvData.java @@ -0,0 +1,54 @@ +package com.jd.blockchain.mocker.data; + +public class KvData { + + private String dataAccount; + + private String key; + + private byte[] value; + + private long version; + + public KvData() { + } + + public KvData(String dataAccount, String key, byte[] value, long version) { + this.dataAccount = dataAccount; + this.key = key; + this.value = value; + this.version = version; + } + + public String getDataAccount() { + return dataAccount; + } + + public String getKey() { + return key; + } + + public byte[] getValue() { + return value; + } + + public long getVersion() { + return version; + } + + public void setDataAccount(String dataAccount) { + this.dataAccount = dataAccount; + } + + public void setKey(String key) { + this.key = key; + } + + public void setValue(byte[] value) { + this.value = value; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/ResponseData.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/ResponseData.java new file mode 100644 index 00000000..61cf6893 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/ResponseData.java @@ -0,0 +1,38 @@ +package com.jd.blockchain.mocker.data; + +import com.jd.blockchain.ledger.TransactionResponse; + +public class ResponseData { + + private TransactionResponse txResponse; + + private T data; + + public ResponseData() { + } + + public ResponseData(TransactionResponse txResponse) { + this.txResponse = txResponse; + } + + public ResponseData(TransactionResponse txResponse, T data) { + this.txResponse = txResponse; + this.data = data; + } + + public TransactionResponse getTxResponse() { + return txResponse; + } + + public T getData() { + return data; + } + + public void setTxResponse(TransactionResponse txResponse) { + this.txResponse = txResponse; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java new file mode 100644 index 00000000..53bc9417 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java @@ -0,0 +1,136 @@ +package com.jd.blockchain.mocker.handler; + +import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.contract.EventProcessingAwire; +import com.jd.blockchain.contract.LedgerContext; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.ContractEventSendOperation; +import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.ledger.core.impl.LedgerManager; +import com.jd.blockchain.ledger.core.impl.LedgerQueryService; +import com.jd.blockchain.ledger.core.impl.OperationHandleContext; +import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext; +import com.jd.blockchain.mocker.proxy.ExecutorProxy; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + + +public class MockerContractExeHandle implements OperationHandle { + + private Map executorProxyMap = new ConcurrentHashMap<>(); + + private LedgerManager ledgerManager; + + private HashDigest ledgerHash; + + @Override + public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { + ContractEventSendOperation contractOP = (ContractEventSendOperation) op; + + HashDigest txHash = requestContext.getRequest().getTransactionContent().getHash(); + + ExecutorProxy executorProxy = executorProxyMap.get(txHash); + + if (executorProxy != null) { + LedgerQueryService queryService = new LedgerQueryService(ledgerManager); + ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext); + + MockerContractEventContext contractEventContext = new MockerContractEventContext( + ledgerHash, contractOP.getEvent(), requestContext.getRequest(), ledgerContext); + + EventProcessingAwire eventProcessingAwire = (EventProcessingAwire) executorProxy.getInstance(); + try { + // + // Before处理过程 + eventProcessingAwire.beforeEvent(contractEventContext); + executorProxy.invoke(); + + // After处理过程 + eventProcessingAwire.postEvent(); + } catch (Exception e) { + eventProcessingAwire.postEvent(new ContractException(e.getMessage())); + } finally { + removeExecutorProxy(txHash); + } + } + } + + @Override + public boolean support(Class operationType) { + return ContractEventSendOperation.class.isAssignableFrom(operationType); + } + + public void initLedger(LedgerManager ledgerManager, HashDigest ledgerHash) { + this.ledgerManager = ledgerManager; + this.ledgerHash = ledgerHash; + } + + public void registerExecutorProxy(HashDigest hashDigest, ExecutorProxy executorProxy) { + executorProxyMap.put(hashDigest, executorProxy); + } + + public ExecutorProxy removeExecutorProxy(HashDigest hashDigest) { + return executorProxyMap.remove(hashDigest); + } + + public static class MockerContractEventContext implements ContractEventContext { + + private HashDigest ledgeHash; + + private String event; + + private TransactionRequest transactionRequest; + + private LedgerContext ledgerContext; + + public MockerContractEventContext(HashDigest ledgeHash, String event, + TransactionRequest transactionRequest, LedgerContext ledgerContext) { + this.ledgeHash = ledgeHash; + this.event = event; + this.transactionRequest = transactionRequest; + this.ledgerContext = ledgerContext; + } + + @Override + public HashDigest getCurrentLedgerHash() { + return ledgeHash; + } + + @Override + public TransactionRequest getTransactionRequest() { + return transactionRequest; + } + + @Override + public Set getTxSigners() { + return null; + } + + @Override + public String getEvent() { + return event; + } + + @Override + public byte[] getArgs() { + return null; + } + + @Override + public LedgerContext getLedger() { + return ledgerContext; + } + + @Override + public Set getContracOwners() { + return null; + } + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerNodeHandler.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerNodeHandler.java new file mode 100644 index 00000000..bd1bea24 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerNodeHandler.java @@ -0,0 +1,189 @@ +package com.jd.blockchain.mocker.handler; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.gateway.GatewayConfigProperties; +import com.jd.blockchain.mocker.config.MockerConstant; +import com.jd.blockchain.mocker.config.PresetAnswerPrompter; +import com.jd.blockchain.mocker.node.GatewayNodeRunner; +import com.jd.blockchain.mocker.node.NodeWebContext; +import com.jd.blockchain.mocker.node.PeerNodeRunner; +import com.jd.blockchain.tools.initializer.DBConnectionConfig; +import com.jd.blockchain.tools.initializer.LedgerBindingConfig; +import com.jd.blockchain.tools.initializer.LedgerInitProperties; +import com.jd.blockchain.tools.initializer.Prompter; +import com.jd.blockchain.tools.keygen.KeyGenCommand; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import com.jd.blockchain.utils.net.NetworkAddress; +import org.springframework.util.ResourceUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static com.jd.blockchain.mocker.config.MockerConstant.*; + +public class MockerNodeHandler { + + private static final String LEDGER_BINDING_FORMAT = "binding.%s."; + + private static final String PARTI_FORMAT = LEDGER_BINDING_FORMAT + "parti."; + + private static final String BINDING_ID_FORMAT = PARTI_FORMAT + "id"; + + private static final String BINDING_PK_PATH_FORMAT = PARTI_FORMAT + "pk-path"; + + private static final String BINDING_PK_FORMAT = PARTI_FORMAT + "pk"; + + private static final String BINDING_PWD_FORMAT = PARTI_FORMAT + "pwd"; + + private static final String BINDING_ADDRESS_FORMAT = PARTI_FORMAT + "address"; + + private static final String DB_FORMAT = LEDGER_BINDING_FORMAT + "db."; + + private static final String BINDING_DB_URI_FORMAT = DB_FORMAT + "uri"; + + private static final String BINDING_DB_PWD_FORMAT = DB_FORMAT + "pwd"; + + private PeerNodeRunner[] peerNodes; + + private GatewayNodeRunner gatewayNodeRunner; + + public void start(int nodeSize) throws Exception { + + HashDigest ledgerHash = ledgerInit(nodeSize); + + // 启动Peer节点 + peerNodes = peerNodeStart(nodeSize, ledgerHash); + + // 启动网关节点 + gatewayNodeRunner = gatewayNodeStart(peerNodes[0].getServiceAddress()); + } + + public LedgerInitProperties initLedgerProperties(int nodeSize) throws Exception { + + File ledgerInitFile = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + + String.format(MockerConstant.LEDGER_INIT_FORMATTER, nodeSize)); + + final LedgerInitProperties ledgerInitProperties = LedgerInitProperties.resolve(new FileInputStream(ledgerInitFile)); + + return ledgerInitProperties; + } + + private HashDigest ledgerInit(int nodeSize) throws Exception { + + System.out.println("----------- is daemon=" + Thread.currentThread().isDaemon()); + + Prompter consolePrompter = new PresetAnswerPrompter("N"); // new ConsolePrompter(); + + LedgerInitProperties initSetting = initLedgerProperties(nodeSize); + + Set hashDigestSet = new HashSet<>(); + + CountDownLatch quitLatch = new CountDownLatch(nodeSize); + + ExecutorService peerThreads = Executors.newFixedThreadPool(nodeSize); + + for (int i = 0; i < nodeSize; i++) { + final int nodeIndex = i; + peerThreads.execute(() -> { + // 启动服务器; + NetworkAddress initAddr = initSetting.getConsensusParticipant(nodeIndex).getInitializerAddress(); + NodeWebContext node = new NodeWebContext(nodeIndex, initAddr); + PrivKey privkey = KeyGenCommand.decodePrivKeyWithRawPassword(PRIVATE_KEYS[nodeIndex], PASSWORD); + DBConnectionConfig dbConn = new DBConnectionConfig(); + dbConn.setConnectionUri(MockerConstant.DB_MEMS[nodeIndex]); + ThreadInvoker.AsyncCallback nodeCallback = node.startInit(privkey, initSetting, dbConn, consolePrompter, + quitLatch); + hashDigestSet.add(nodeCallback.waitReturn()); + }); + } + + quitLatch.await(); + + if (hashDigestSet.size() != 1) { + throw new IllegalStateException(String.format("%s Node Ledger Init Fail !!!", nodeSize)); + } + return hashDigestSet.toArray(new HashDigest[hashDigestSet.size()])[0]; + } + + + public PeerNodeRunner[] peerNodeStart(int nodeSize, HashDigest ledgerHash) { + + int portStart = PEER_PORT_START; + + List> threadInvokers = new ArrayList<>(); + + final PeerNodeRunner[] peerNodeRunners = new PeerNodeRunner[nodeSize]; + + for (int i = 0; i < nodeSize; i++) { + NetworkAddress peerSrvAddr = new NetworkAddress(LOCAL_ADDRESS, portStart); + LedgerBindingConfig bindingConfig = loadBindingConfig(i, ledgerHash); + PeerNodeRunner peerNodeRunner = new PeerNodeRunner(peerSrvAddr, bindingConfig); + peerNodeRunners[i] = peerNodeRunner; + portStart += 10; + threadInvokers.add(peerNodeRunner.start()); + } + + // 等待结果 + for (ThreadInvoker.AsyncCallback threadInvoker : threadInvokers) { + threadInvoker.waitReturn(); + } + + return peerNodeRunners; + } + + public GatewayNodeRunner gatewayNodeStart(NetworkAddress peerAddress) { + GatewayConfigProperties.KeyPairConfig gwKeyPair = new GatewayConfigProperties.KeyPairConfig(); + gwKeyPair.setPubKeyValue(PUBLIC_KEYS[0]); + gwKeyPair.setPrivKeyValue(PRIVATE_KEYS[0]); + gwKeyPair.setPrivKeyPassword(PASSWORD_ENCODE); + GatewayNodeRunner gateway = new GatewayNodeRunner(LOCAL_ADDRESS, GATEWAY_PORT, gwKeyPair, + peerAddress, CONSENSUS_PROVIDERS,null); + + ThreadInvoker.AsyncCallback gwStarting = gateway.start(); + + gwStarting.waitReturn(); + + return gateway; + } + + public void stop() { + if (peerNodes != null) { + for (PeerNodeRunner peerNodeRunner : peerNodes) { + peerNodeRunner.stop(); + } + } + if (gatewayNodeRunner != null) { + gatewayNodeRunner.stop(); + } + } + + private LedgerBindingConfig loadBindingConfig(int nodeIndex, HashDigest ledgerHash) { + + Properties properties = new Properties(); + + String ledgerHashBase58 = ledgerHash.toBase58(); + + properties.put("ledger.bindings", ledgerHashBase58); + + properties.put(String.format(BINDING_ID_FORMAT, ledgerHashBase58), nodeIndex); + + properties.put(String.format(BINDING_PK_PATH_FORMAT, ledgerHashBase58), ""); + + properties.put(String.format(BINDING_PK_FORMAT, ledgerHashBase58), PUBLIC_KEYS[nodeIndex]); + + properties.put(String.format(BINDING_PWD_FORMAT, ledgerHashBase58), PASSWORD_ENCODE); + + properties.put(String.format(BINDING_ADDRESS_FORMAT, ledgerHashBase58), ADDRESS_ARRAY[nodeIndex]); + + properties.put(String.format(BINDING_DB_URI_FORMAT, ledgerHashBase58), DB_MEMS[nodeIndex]); + + properties.put(String.format(BINDING_DB_PWD_FORMAT, ledgerHashBase58), ""); + + return LedgerBindingConfig.resolve(properties); + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerOperationHandleRegister.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerOperationHandleRegister.java new file mode 100644 index 00000000..fe902c1f --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerOperationHandleRegister.java @@ -0,0 +1,51 @@ +package com.jd.blockchain.mocker.handler; + +import com.jd.blockchain.ledger.core.LedgerException; +import com.jd.blockchain.ledger.core.OperationHandle; +import com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration; +import com.jd.blockchain.ledger.core.impl.handles.*; + +import java.util.ArrayList; +import java.util.List; + +public class MockerOperationHandleRegister implements OperationHandleRegisteration { + + private List opHandles = new ArrayList<>(); + + public MockerOperationHandleRegister() { + initDefaultHandles(); + } + + /** + * 针对不采用bean依赖注入的方式来处理; + */ + private void initDefaultHandles(){ + opHandles.add(new DataAccountKVSetOperationHandle()); + opHandles.add(new DataAccountRegisterOperationHandle()); + opHandles.add(new UserRegisterOperationHandle()); + opHandles.add(new ContractCodeDeployOperationHandle()); +// opHandles.add(new ContractEventSendOperationHandle()); + } + + public List getOpHandles() { + return opHandles; + } + + public void registerHandler(OperationHandle operationHandle) { + opHandles.add(operationHandle); + } + + public void removeHandler(OperationHandle operationHandle) { + opHandles.remove(operationHandle); + } + + @Override + public OperationHandle getHandle(Class operationType) { + for (OperationHandle handle : opHandles) { + if (handle.support(operationType)) { + return handle; + } + } + throw new LedgerException("Unsupported operation type[" + operationType.getName() + "]!"); + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerServiceHandler.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerServiceHandler.java new file mode 100644 index 00000000..0334d914 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerServiceHandler.java @@ -0,0 +1,216 @@ +package com.jd.blockchain.mocker.handler; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.mocker.config.MockerConstant; +import com.jd.blockchain.mocker.data.KvData; +import com.jd.blockchain.mocker.data.ResponseData; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.tools.keygen.KeyGenCommand; + +public class MockerServiceHandler { + + private BlockchainKeypair defaultParticipant; + + private BlockchainKeypair defaultUser; + + private BlockchainKeypair defaultDataAccount; + + private String gatewayHost; + + private int gatewayPort; + + private GatewayServiceFactory gatewayServiceFactory; + + private BlockchainService blockchainService; + + private HashDigest ledgerHash; + + public MockerServiceHandler(String gatewayHost, int gatewayPort) { + this.gatewayHost = gatewayHost; + this.gatewayPort = gatewayPort; + init(); + } + + public BlockchainKeypair getDefaultParticipant() { + return defaultParticipant; + } + + public BlockchainKeypair getDefaultUser() { + return defaultUser; + } + + public BlockchainKeypair getDefaultDataAccount() { + return defaultDataAccount; + } + + public String getDefaultDataAccountAddress() { + return defaultDataAccount.getAddress().toBase58(); + } + + public String getGatewayHost() { + return gatewayHost; + } + + public int getGatewayPort() { + return gatewayPort; + } + + public GatewayServiceFactory getGatewayServiceFactory() { + return gatewayServiceFactory; + } + + public BlockchainService getBlockchainService() { + return blockchainService; + } + + public HashDigest getLedgerHash() { + return ledgerHash; + } + + private void init() { + + defaultParticipant = defaultParticipant(); + + gatewayServiceFactory = GatewayServiceFactory.connect(gatewayHost, gatewayPort, + false, defaultParticipant); + + blockchainService = gatewayServiceFactory.getBlockchainService(); + + HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); + + ledgerHash = ledgerHashs[0]; + + // 默认注册部分内容 + // 注册一个用户和一个数据账户 + TransactionTemplate txTemplate = blockchainService.newTransaction(ledgerHash); + + defaultUser = newKeypair(); + + defaultDataAccount = newKeypair(); + + // 注册用户 + txTemplate.users().register(defaultUser.getIdentity()); + + // 注册数据账户 + txTemplate.dataAccounts().register(defaultDataAccount.getIdentity()); + + // TX 准备就绪; + PreparedTransaction prepTx = txTemplate.prepare(); + + // 使用私钥进行签名; + prepTx.sign(defaultParticipant); + + // 提交交易; + TransactionResponse txResponse = prepTx.commit(); + + System.out.printf("Commit Transaction Result = %s \r\n", txResponse.isSuccess()); + } + + public BlockchainKeypair newKeypair() { + return BlockchainKeyGenerator.getInstance().generate(); + } + + private BlockchainKeypair defaultParticipant() { + PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(MockerConstant.PRIVATE_KEYS[0], MockerConstant.PASSWORD); + PubKey pubKey = KeyGenCommand.decodePubKey(MockerConstant.PUBLIC_KEYS[0]); + return new BlockchainKeypair(pubKey, privKey); + } + + public ResponseData writeKv(String key, byte[] value) { + return writeKv(key, value, -1); + } + + public ResponseData writeKv(String key, byte[] value, long version) { + return writeKv(getDefaultDataAccountAddress(), key, value, version); + } + + public ResponseData writeKv(String dataAccount, String key, byte[] value) { + return writeKv(dataAccount, key, value, -1); + } + + public ResponseData writeKv(String dataAccount, String key, byte[] value, long version) { + + TransactionTemplate txTemplate = newTxTemplate(); + + txTemplate.dataAccount(dataAccount).set(key, value, version); + + TransactionResponse txResponse = txPrepareAndCommit(txTemplate); + + long saveVersion = version; + + if (txResponse.isSuccess()) { + saveVersion = version + 1; + } + + KvData kvData = new KvData(dataAccount, key, value, saveVersion); + + return new ResponseData(txResponse, kvData); + } + + public ResponseData registerUser() { + + BlockchainKeypair newUser = BlockchainKeyGenerator.getInstance().generate(); + + return registerUser(newUser); + } + + public ResponseData registerUser(BlockchainKeypair user) { + + TransactionTemplate txTemplate = newTxTemplate(); + + // 注册 + txTemplate.users().register(user.getIdentity()); + + TransactionResponse txResponse = txPrepareAndCommit(txTemplate); + + return new ResponseData(txResponse, user); + } + + public ResponseData registerDataAccount() { + + BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); + + return registerDataAccount(newDataAccount); + } + + public ResponseData registerDataAccount(BlockchainKeypair dataAccount) { + + TransactionTemplate txTemplate = newTxTemplate(); + + // 注册 + txTemplate.dataAccounts().register(dataAccount.getIdentity()); + + TransactionResponse txResponse = txPrepareAndCommit(txTemplate); + + return new ResponseData(txResponse, dataAccount); + } + + public ResponseData deployContract() { + return null; + } + + public ResponseData executeContract() { + return null; + } + + private TransactionTemplate newTxTemplate() { + return blockchainService.newTransaction(ledgerHash); + } + + private TransactionResponse txPrepareAndCommit(TransactionTemplate txTemplate) { + // TX 准备就绪; + PreparedTransaction prepTx = txTemplate.prepare(); + + // 使用私钥进行签名; + prepTx.sign(defaultParticipant); + + // 提交交易; + TransactionResponse txResponse = prepTx.commit(); + + return txResponse; + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/GatewayNodeRunner.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/GatewayNodeRunner.java new file mode 100644 index 00000000..61520c4b --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/GatewayNodeRunner.java @@ -0,0 +1,75 @@ +package com.jd.blockchain.mocker.node; + +import com.jd.blockchain.gateway.GatewayConfigProperties; +import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; +import com.jd.blockchain.gateway.GatewayServerBooter; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback; +import com.jd.blockchain.utils.net.NetworkAddress; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.CollectionUtils; + +import java.util.Map; + +public class GatewayNodeRunner { + + private NetworkAddress serviceAddress; + + private GatewayServerBooter gatewayServer; + + public GatewayNodeRunner(String host, int port, KeyPairConfig gatewayDefaultKey, NetworkAddress masterPeerAddres) { + this(host, port, gatewayDefaultKey, masterPeerAddres, null,null); + } + + public GatewayNodeRunner(String host, int port, KeyPairConfig gatewayDefaultKey, NetworkAddress masterPeerAddres, String[] providers, + Map otherMap) { + this.serviceAddress = new NetworkAddress(host, port); + GatewayConfigProperties config = new GatewayConfigProperties(); + + config.http().setHost(host); + config.http().setPort(port); + + if (providers != null) { + for (String provider : providers) { + config.providerConfig().add(provider); + } + } + + config.setMasterPeerAddress(masterPeerAddres); + + config.keys().getDefault().setPubKeyValue(gatewayDefaultKey.getPubKeyValue()); + config.keys().getDefault().setPrivKeyValue(gatewayDefaultKey.getPrivKeyValue()); + config.keys().getDefault().setPrivKeyPassword(gatewayDefaultKey.getPrivKeyPassword()); + + if(!CollectionUtils.isEmpty(otherMap)){ + config.setDataRetrievalUrl(otherMap.get("DATA_RETRIEVAL_URL").toString()); + } + + + //get the springConfigLocation; + ClassPathResource configResource = new ClassPathResource("application-gw.properties"); + String springConfigLocation = "classPath:"+configResource.getPath(); + + this.gatewayServer = new GatewayServerBooter(config,springConfigLocation); + } + + public AsyncCallback start() { + ThreadInvoker invoker = new ThreadInvoker() { + @Override + protected Object invoke() throws Exception { + gatewayServer.start(); + return null; + } + }; + + return invoker.start(); + } + + public void stop() { + gatewayServer.close(); + } + + public NetworkAddress getServiceAddress() { + return serviceAddress; + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/NodeWebContext.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/NodeWebContext.java new file mode 100644 index 00000000..93096613 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/NodeWebContext.java @@ -0,0 +1,106 @@ +package com.jd.blockchain.mocker.node; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.ledger.TransactionContent; +import com.jd.blockchain.ledger.core.LedgerInitDecision; +import com.jd.blockchain.ledger.core.LedgerInitPermission; +import com.jd.blockchain.ledger.core.LedgerRepository; +import com.jd.blockchain.ledger.core.impl.LedgerManager; +import com.jd.blockchain.mocker.config.LedgerInitWebConfiguration; +import com.jd.blockchain.storage.service.DbConnection; +import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory; +import com.jd.blockchain.tools.initializer.DBConnectionConfig; +import com.jd.blockchain.tools.initializer.LedgerInitProcess; +import com.jd.blockchain.tools.initializer.LedgerInitProperties; +import com.jd.blockchain.tools.initializer.Prompter; +import com.jd.blockchain.tools.initializer.web.LedgerInitializeWebController; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import com.jd.blockchain.utils.net.NetworkAddress; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; + +import java.util.concurrent.CountDownLatch; + +public class NodeWebContext { + + private NetworkAddress serverAddress; + + private DBConnectionConfig dbConnConfig; + + private volatile ConfigurableApplicationContext ctx; + + private volatile LedgerInitProcess initProcess; + + private volatile LedgerInitializeWebController controller; + + private volatile LedgerManager ledgerManager; + + private volatile CompositeConnectionFactory db; + + private int id; + + public int getId() { + return controller.getId(); + } + + public TransactionContent getInitTxContent() { + return controller.getInitTxContent(); + } + + public LedgerInitPermission getLocalPermission() { + return controller.getLocalPermission(); + } + + public LedgerInitDecision getLocalDecision() { + return controller.getLocalDecision(); + } + + public NodeWebContext(int id, NetworkAddress serverAddress) { + this.id = id; + this.serverAddress = serverAddress; + } + + public LedgerRepository registLedger(HashDigest ledgerHash) { + DbConnection conn = db.connect(dbConnConfig.getUri()); + LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, conn.getStorageService()); + return ledgerRepo; + } + + public ThreadInvoker.AsyncCallback startInit(PrivKey privKey, LedgerInitProperties setting, + DBConnectionConfig dbConnConfig, Prompter prompter, CountDownLatch quitLatch) { + + ThreadInvoker invoker = new ThreadInvoker() { + @Override + protected HashDigest invoke() throws Exception { + doStartServer(); + + NodeWebContext.this.dbConnConfig = dbConnConfig; + HashDigest ledgerHash = NodeWebContext.this.initProcess.initialize(id, privKey, setting, + dbConnConfig, prompter); + + System.out.printf("ledgerHash = %s \r\n", ledgerHash.toBase58()); + + quitLatch.countDown(); + return ledgerHash; + } + }; + + return invoker.start(); + } + + public void doStartServer() { + String argServerAddress = String.format("--server.address=%s", serverAddress.getHost()); + String argServerPort = String.format("--server.port=%s", serverAddress.getPort()); + String nodebug = "--debug=false"; + String[] innerArgs = { argServerAddress, argServerPort, nodebug }; + + ctx = SpringApplication.run(LedgerInitWebConfiguration.class, innerArgs); + + ctx.setId("Node-" + id); + controller = ctx.getBean(LedgerInitializeWebController.class); + ledgerManager = ctx.getBean(LedgerManager.class); + db = ctx.getBean(CompositeConnectionFactory.class); + initProcess = ctx.getBean(LedgerInitProcess.class); + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/PeerNodeRunner.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/PeerNodeRunner.java new file mode 100644 index 00000000..ba90d280 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/PeerNodeRunner.java @@ -0,0 +1,62 @@ +package com.jd.blockchain.mocker.node; + +import com.jd.blockchain.peer.PeerServerBooter; +import com.jd.blockchain.storage.service.DbConnectionFactory; +import com.jd.blockchain.tools.initializer.LedgerBindingConfig; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; +import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback; +import com.jd.blockchain.utils.net.NetworkAddress; + +public class PeerNodeRunner { + + private NetworkAddress serviceAddress; + + private volatile PeerServerBooter peerServer; + + private LedgerBindingConfig ledgerBindingConfig; + + public DbConnectionFactory getDBConnectionFactory() { + return peerServer.getDBConnectionFactory(); + } + + public NetworkAddress getServiceAddress() { + return serviceAddress; + } + + public LedgerBindingConfig getLedgerBindingConfig() { + return ledgerBindingConfig; + } + + public PeerNodeRunner(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig) { + this(serviceAddress, ledgerBindingConfig, null); + } + + public PeerNodeRunner(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig, + DbConnectionFactory dbConnectionFactory) { + this.serviceAddress = serviceAddress; + this.ledgerBindingConfig = ledgerBindingConfig; + if (dbConnectionFactory == null) { + this.peerServer = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), serviceAddress.getPort(),null); + }else { + this.peerServer = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), serviceAddress.getPort(),null, + dbConnectionFactory); + } + } + + public AsyncCallback start() { + ThreadInvoker invoker = new ThreadInvoker() { + @Override + protected Object invoke() throws Exception { + peerServer.start(); + + return null; + } + }; + + return invoker.start(); + } + + public void stop() { + peerServer.close(); + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java new file mode 100644 index 00000000..69fc305c --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java @@ -0,0 +1,80 @@ +package com.jd.blockchain.mocker.proxy; + +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.mocker.MockerNodeContext; +import com.jd.blockchain.mocker.handler.MockerContractExeHandle; +import com.jd.blockchain.transaction.TxBuilder; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +public class ContractProxy implements InvocationHandler { + + private BlockchainIdentity identity; + + private MockerNodeContext mockerNodeContext; + + private T instance; + + private MockerContractExeHandle operationHandle; + + public ContractProxy(BlockchainIdentity identity, MockerNodeContext mockerNodeContext, + T instance, MockerContractExeHandle operationHandle) { + this.identity = identity; + this.mockerNodeContext = mockerNodeContext; + this.instance = instance; + this.operationHandle = operationHandle; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // 实际执行时,首先判断执行的是否是添加注解的方法 + if (!isExecuteContractMethod(method)) { + return method.invoke(instance, args); + } + + // 首先发送一次执行的请求 + TxBuilder txBuilder = mockerNodeContext.txBuilder(); + + Class contractInft = null; + + Class[] instanceInfts = instance.getClass().getInterfaces(); + + for (Class instanceInft : instanceInfts) { + if (instanceInft.isAnnotationPresent(Contract.class)) { + contractInft = instanceInft; + break; + } + } + + if (contractInft == null) { + throw new IllegalStateException("This object does not implement the interface for the @Contract annotation !!!"); + } + + // 生成代理类 + Object proxyInstance = txBuilder.contract(identity.getAddress().toBase58(), contractInft); + // 代理方式执行一次 + method.invoke(proxyInstance, args); + + TransactionRequest txRequest = mockerNodeContext.txRequest(txBuilder); + + // 放入到Map中 + HashDigest txHash = txRequest.getTransactionContent().getHash(); + operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args)); + + // 提交该请求至整个区块链系统 + mockerNodeContext.txProcess(txRequest); + // 不处理返回值 + return null; + } + + private boolean isExecuteContractMethod(Method method) { + Annotation annotation = method.getAnnotation(ContractEvent.class); + return annotation != null; + } +} diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ExecutorProxy.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ExecutorProxy.java new file mode 100644 index 00000000..04873be5 --- /dev/null +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ExecutorProxy.java @@ -0,0 +1,34 @@ +package com.jd.blockchain.mocker.proxy; + +import java.lang.reflect.Method; + +public class ExecutorProxy { + + private Object instance; + + private Method method; + + private Object[] args; + + public ExecutorProxy(Object instance, Method method, Object[] args) { + this.instance = instance; + this.method = method; + this.args = args; + } + + public Object getInstance() { + return instance; + } + + public Method getMethod() { + return method; + } + + public Object[] getArgs() { + return args; + } + + public Object invoke() throws Exception { + return method.invoke(instance, args); + } +} diff --git a/source/tools/tools-mocker/src/main/resources/bftsmart4.config b/source/tools/tools-mocker/src/main/resources/bftsmart4.config new file mode 100644 index 00000000..870fcde2 --- /dev/null +++ b/source/tools/tools-mocker/src/main/resources/bftsmart4.config @@ -0,0 +1,167 @@ +# Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +############################################ +###### Consensus Commit Block Parameters: transaction count ###### +############################################ +system.block.txsize=500 + +############################################ +###### Consensus Commit Block Parameters: delay time ###### +############################################ +system.block.maxdelay=5000 + +############################################ +###### #Consensus Participant0 ###### +############################################ + +system.server.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 +system.server.0.network.host=127.0.0.1 +system.server.0.network.port=16000 +system.server.0.network.secure=false + +############################################ +###### #Consensus Participant1 ###### +############################################ + +system.server.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX +system.server.1.network.host=127.0.0.1 +system.server.1.network.port=16100 +system.server.1.network.secure=false + +############################################ +###### #Consensus Participant2 ###### +############################################ + +system.server.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x +system.server.2.network.host=127.0.0.1 +system.server.2.network.port=16200 +system.server.2.network.secure=false + +############################################ +###### #Consensus Participant3 ###### +############################################ + +system.server.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk +system.server.3.network.host=127.0.0.1 +system.server.3.network.port=16300 +system.server.3.network.secure=false + +############################################ +####### Communication Configurations ####### +############################################ + +#HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value) +#This parameter is not currently being used +#system.authentication.hmacAlgorithm = HmacSHA1 + +#Specify if the communication system should use a thread to send data (true or false) +system.communication.useSenderThread = true + +#Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments +#and benchmarks, but must not be used in production systems. +system.communication.defaultkeys = true + +############################################ +### Replication Algorithm Configurations ### +############################################ + +#Number of servers in the group +system.servers.num = 4 + +#Maximum number of faulty replicas +system.servers.f = 1 + +#Timeout to asking for a client request +system.totalordermulticast.timeout = 2000 + +#Maximum batch size (in number of messages) +system.totalordermulticast.maxbatchsize = 500 + +#Number of nonces (for non-determinism actions) generated +system.totalordermulticast.nonces = 10 + +#if verification of leader-generated timestamps are increasing +#it can only be used on systems in which the network clocks +#are synchronized +system.totalordermulticast.verifyTimestamps = false + +#Quantity of messages that can be stored in the receive queue of the communication system +system.communication.inQueueSize = 500000 + +# Quantity of messages that can be stored in the send queue of each replica +system.communication.outQueueSize = 500000 + +#Set to 1 if SMaRt should use signatures, set to 0 if otherwise +system.communication.useSignatures = 0 + +#Set to 1 if SMaRt should use MAC's, set to 0 if otherwise +system.communication.useMACs = 1 + +#Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise +system.debug = 0 + +#Print information about the replica when it is shutdown +system.shutdownhook = true + +############################################ +###### State Transfer Configurations ####### +############################################ + +#Activate the state transfer protocol ('true' to activate, 'false' to de-activate) +system.totalordermulticast.state_transfer = true + +#Maximum ahead-of-time message not discarded +system.totalordermulticast.highMark = 10000 + +#Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered) +system.totalordermulticast.revival_highMark = 10 + +#Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs +system.totalordermulticast.timeout_highMark = 200 + +############################################ +###### Log and Checkpoint Configurations ### +############################################ + +system.totalordermulticast.log = true +system.totalordermulticast.log_parallel = false +system.totalordermulticast.log_to_disk = false +system.totalordermulticast.sync_log = false + +#Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol) +system.totalordermulticast.checkpoint_period = 1000 +system.totalordermulticast.global_checkpoint_period = 120000 + +system.totalordermulticast.checkpoint_to_disk = false +system.totalordermulticast.sync_ckp = false + + +############################################ +###### Reconfiguration Configurations ###### +############################################ + +#Replicas ID for the initial view, separated by a comma. +# The number of replicas in this parameter should be equal to that specified in 'system.servers.num' +system.initial.view = 0,1,2,3 + +#The ID of the trust third party (TTP) +system.ttp.id = 7002 + +#This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults +system.bft = true + +#Custom View Storage; +#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage \ No newline at end of file diff --git a/source/tools/tools-mocker/src/main/resources/bftsmart8.config b/source/tools/tools-mocker/src/main/resources/bftsmart8.config new file mode 100644 index 00000000..814a6c3d --- /dev/null +++ b/source/tools/tools-mocker/src/main/resources/bftsmart8.config @@ -0,0 +1,208 @@ +# Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +############################################ +###### Consensus Commit Block Parameters: transaction count ###### +############################################ +system.block.txsize=500 + +############################################ +###### Consensus Commit Block Parameters: delay time ###### +############################################ +system.block.maxdelay=5000 + +############################################ +###### #Consensus Participant0 ###### +############################################ + +system.server.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 +system.server.0.network.host=127.0.0.1 +system.server.0.network.port=16000 +system.server.0.network.secure=false + +############################################ +###### #Consensus Participant1 ###### +############################################ + +system.server.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX +system.server.1.network.host=127.0.0.1 +system.server.1.network.port=16100 +system.server.1.network.secure=false + +############################################ +###### #Consensus Participant2 ###### +############################################ + +system.server.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x +system.server.2.network.host=127.0.0.1 +system.server.2.network.port=16200 +system.server.2.network.secure=false + +############################################ +###### #Consensus Participant3 ###### +############################################ + +system.server.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk +system.server.3.network.host=127.0.0.1 +system.server.3.network.port=16300 +system.server.3.network.secure=false + + +############################################ +###### #Consensus Participant4 ###### +############################################ + +system.server.4.pubkey=3snPdw7i7PXPRMp3EAjsxJkHe7aZJRLNzdW8kEHBWeQsSgcPAiHP2J +system.server.4.network.host=127.0.0.1 +system.server.4.network.port=16400 +system.server.4.network.secure=false + + +############################################ +###### #Consensus Participant5 ###### +############################################ + +system.server.5.pubkey=3snPdw7i7PmmQoPgUpUmmAUj6nakHj8wMSQmiMi1RaiZp4YU1D4AXk +system.server.5.network.host=127.0.0.1 +system.server.5.network.port=16500 +system.server.5.network.secure=false + + +############################################ +###### #Consensus Participant6 ###### +############################################ + +system.server.6.pubkey=3snPdw7i7PiJKsa94q3EcLT1y6GRJ7LeFGe799hdzRRHmf6LNodyiM +system.server.6.network.host=127.0.0.1 +system.server.6.network.port=16600 +system.server.6.network.secure=false + + +############################################ +###### #Consensus Participant7 ###### +############################################ + +system.server.7.pubkey=3snPdw7i7Pm2wJwEnKn8kK8eGTkN36C2BZRRjVTr9FPB2rqtcgTq7h +system.server.7.network.host=127.0.0.1 +system.server.7.network.port=16700 +system.server.7.network.secure=false + + +############################################ +####### Communication Configurations ####### +############################################ + +#HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value) +#This parameter is not currently being used +#system.authentication.hmacAlgorithm = HmacSHA1 + +#Specify if the communication system should use a thread to send data (true or false) +system.communication.useSenderThread = true + +#Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments +#and benchmarks, but must not be used in production systems. +system.communication.defaultkeys = true + +############################################ +### Replication Algorithm Configurations ### +############################################ + +#Number of servers in the group +system.servers.num = 8 + +#Maximum number of faulty replicas +system.servers.f = 2 + +#Timeout to asking for a client request +system.totalordermulticast.timeout = 2000 + +#Maximum batch size (in number of messages) +system.totalordermulticast.maxbatchsize = 500 + +#Number of nonces (for non-determinism actions) generated +system.totalordermulticast.nonces = 10 + +#if verification of leader-generated timestamps are increasing +#it can only be used on systems in which the network clocks +#are synchronized +system.totalordermulticast.verifyTimestamps = false + +#Quantity of messages that can be stored in the receive queue of the communication system +system.communication.inQueueSize = 500000 + +# Quantity of messages that can be stored in the send queue of each replica +system.communication.outQueueSize = 500000 + +#Set to 1 if SMaRt should use signatures, set to 0 if otherwise +system.communication.useSignatures = 0 + +#Set to 1 if SMaRt should use MAC's, set to 0 if otherwise +system.communication.useMACs = 1 + +#Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise +system.debug = 0 + +#Print information about the replica when it is shutdown +system.shutdownhook = true + +############################################ +###### State Transfer Configurations ####### +############################################ + +#Activate the state transfer protocol ('true' to activate, 'false' to de-activate) +system.totalordermulticast.state_transfer = true + +#Maximum ahead-of-time message not discarded +system.totalordermulticast.highMark = 10000 + +#Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered) +system.totalordermulticast.revival_highMark = 10 + +#Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs +system.totalordermulticast.timeout_highMark = 200 + +############################################ +###### Log and Checkpoint Configurations ### +############################################ + +system.totalordermulticast.log = true +system.totalordermulticast.log_parallel = false +system.totalordermulticast.log_to_disk = false +system.totalordermulticast.sync_log = false + +#Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol) +system.totalordermulticast.checkpoint_period = 1000 +system.totalordermulticast.global_checkpoint_period = 120000 + +system.totalordermulticast.checkpoint_to_disk = false +system.totalordermulticast.sync_ckp = false + + +############################################ +###### Reconfiguration Configurations ###### +############################################ + +#Replicas ID for the initial view, separated by a comma. +# The number of replicas in this parameter should be equal to that specified in 'system.servers.num' +system.initial.view = 0,1,2,3,4,5,6,7 + +#The ID of the trust third party (TTP) +system.ttp.id = 7002 + +#This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults +system.bft = true + +#Custom View Storage; +#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage \ No newline at end of file diff --git a/source/tools/tools-mocker/src/main/resources/ledger4.init b/source/tools/tools-mocker/src/main/resources/ledger4.init new file mode 100644 index 00000000..4ed4cd06 --- /dev/null +++ b/source/tools/tools-mocker/src/main/resources/ledger4.init @@ -0,0 +1,72 @@ +#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取; +ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffa + +#账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; +ledger.name=JDChain + + +#共识服务提供者;必须; +consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider + +#共识服务的参数配置;必须; +consensus.conf=classpath:bftsmart4.config + +#密码服务提供者列表,以英文逗点“,”分隔;必须; +crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ +com.jd.blockchain.crypto.service.sm.SMCryptoService + + +#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; +cons_parti.count=4 + +#第0个参与方的名称; +cons_parti.0.name=jd.com +#第0个参与方的公钥文件路径; +cons_parti.0.pubkey-path= +#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 +#第0个参与方的账本初始服务的主机; +cons_parti.0.initializer.host=127.0.0.1 +#第0个参与方的账本初始服务的端口; +cons_parti.0.initializer.port=1601 +#第0个参与方的账本初始服务是否开启安全连接; +cons_parti.0.initializer.secure=false + +#第1个参与方的名称; +cons_parti.1.name=at.com +#第1个参与方的公钥文件路径; +cons_parti.1.pubkey-path= +#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX +#第1个参与方的账本初始服务的主机; +cons_parti.1.initializer.host=127.0.0.1 +#第1个参与方的账本初始服务的端口; +cons_parti.1.initializer.port=1611 +#第1个参与方的账本初始服务是否开启安全连接; +cons_parti.1.initializer.secure=false + +#第2个参与方的名称; +cons_parti.2.name=bt.com +#第2个参与方的公钥文件路径; +cons_parti.2.pubkey-path= +#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x +#第2个参与方的账本初始服务的主机; +cons_parti.2.initializer.host=127.0.0.1 +#第2个参与方的账本初始服务的端口; +cons_parti.2.initializer.port=1621 +#第2个参与方的账本初始服务是否开启安全连接; +cons_parti.2.initializer.secure=false + +#第3个参与方的名称; +cons_parti.3.name=xt.com +#第3个参与方的公钥文件路径; +cons_parti.3.pubkey-path= +#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk +#第3个参与方的账本初始服务的主机; +cons_parti.3.initializer.host=127.0.0.1 +#第3个参与方的账本初始服务的端口; +cons_parti.3.initializer.port=1631 +#第3个参与方的账本初始服务是否开启安全连接; +cons_parti.3.initializer.secure=false \ No newline at end of file diff --git a/source/tools/tools-mocker/src/main/resources/ledger8.init b/source/tools/tools-mocker/src/main/resources/ledger8.init new file mode 100644 index 00000000..dacbfeca --- /dev/null +++ b/source/tools/tools-mocker/src/main/resources/ledger8.init @@ -0,0 +1,125 @@ +#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取; +ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe + +#账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; +ledger.name=JDChain + + +#共识服务提供者;必须; +consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider + +#共识服务的参数配置;必须; +consensus.conf=classpath:bftsmart8.config + +#密码服务提供者列表,以英文逗点“,”分隔;必须; +crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ +com.jd.blockchain.crypto.service.sm.SMCryptoService + + +#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; +cons_parti.count=8 + +#第0个参与方的名称; +cons_parti.0.name=jd.com +#第0个参与方的公钥文件路径; +cons_parti.0.pubkey-path= +#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 +#第0个参与方的账本初始服务的主机; +cons_parti.0.initializer.host=127.0.0.1 +#第0个参与方的账本初始服务的端口; +cons_parti.0.initializer.port=1601 +#第0个参与方的账本初始服务是否开启安全连接; +cons_parti.0.initializer.secure=false + +#第1个参与方的名称; +cons_parti.1.name=at.com +#第1个参与方的公钥文件路径; +cons_parti.1.pubkey-path= +#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX +#第1个参与方的账本初始服务的主机; +cons_parti.1.initializer.host=127.0.0.1 +#第1个参与方的账本初始服务的端口; +cons_parti.1.initializer.port=1611 +#第1个参与方的账本初始服务是否开启安全连接; +cons_parti.1.initializer.secure=false + +#第2个参与方的名称; +cons_parti.2.name=bt.com +#第2个参与方的公钥文件路径; +cons_parti.2.pubkey-path= +#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x +#第2个参与方的账本初始服务的主机; +cons_parti.2.initializer.host=127.0.0.1 +#第2个参与方的账本初始服务的端口; +cons_parti.2.initializer.port=1621 +#第2个参与方的账本初始服务是否开启安全连接; +cons_parti.2.initializer.secure=false + +#第3个参与方的名称; +cons_parti.3.name=xt.com +#第3个参与方的公钥文件路径; +cons_parti.3.pubkey-path= +#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk +#第3个参与方的账本初始服务的主机; +cons_parti.3.initializer.host=127.0.0.1 +#第3个参与方的账本初始服务的端口; +cons_parti.3.initializer.port=1631 +#第3个参与方的账本初始服务是否开启安全连接; +cons_parti.3.initializer.secure=false + + +#第4个参与方的名称; +cons_parti.4.name=mt.com +#第4个参与方的公钥文件路径; +cons_parti.4.pubkey-path= +#第4个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.4.pubkey=3snPdw7i7PXPRMp3EAjsxJkHe7aZJRLNzdW8kEHBWeQsSgcPAiHP2J +#第4个参与方的账本初始服务的主机; +cons_parti.4.initializer.host=127.0.0.1 +#第4个参与方的账本初始服务的端口; +cons_parti.4.initializer.port=1641 +#第4个参与方的账本初始服务是否开启安全连接; +cons_parti.4.initializer.secure=false + +#第5个参与方的名称; +cons_parti.5.name=nt.com +#第5个参与方的公钥文件路径; +cons_parti.5.pubkey-path= +#第5个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.5.pubkey=3snPdw7i7PmmQoPgUpUmmAUj6nakHj8wMSQmiMi1RaiZp4YU1D4AXk +#第5个参与方的账本初始服务的主机; +cons_parti.5.initializer.host=127.0.0.1 +#第5个参与方的账本初始服务的端口; +cons_parti.5.initializer.port=1651 +#第5个参与方的账本初始服务是否开启安全连接; +cons_parti.5.initializer.secure=false + +#第6个参与方的名称; +cons_parti.6.name=yt.com +#第6个参与方的公钥文件路径; +cons_parti.6.pubkey-path= +#第6个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.6.pubkey=3snPdw7i7PiJKsa94q3EcLT1y6GRJ7LeFGe799hdzRRHmf6LNodyiM +#第6个参与方的账本初始服务的主机; +cons_parti.6.initializer.host=127.0.0.1 +#第6个参与方的账本初始服务的端口; +cons_parti.6.initializer.port=1661 +#第6个参与方的账本初始服务是否开启安全连接; +cons_parti.6.initializer.secure=false + +#第7个参与方的名称; +cons_parti.7.name=zt.com +#第7个参与方的公钥文件路径; +cons_parti.7.pubkey-path= +#第7个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.7.pubkey=3snPdw7i7Pm2wJwEnKn8kK8eGTkN36C2BZRRjVTr9FPB2rqtcgTq7h +#第7个参与方的账本初始服务的主机; +cons_parti.7.initializer.host=127.0.0.1 +#第7个参与方的账本初始服务的端口; +cons_parti.7.initializer.port=1671 +#第7个参与方的账本初始服务是否开启安全连接; +cons_parti.7.initializer.secure=false \ No newline at end of file diff --git a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/AccountMockerTest.java b/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/AccountMockerTest.java new file mode 100644 index 00000000..55699a40 --- /dev/null +++ b/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/AccountMockerTest.java @@ -0,0 +1,50 @@ +package com.jd.blockchain.test; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.mocker.MockerNodeContext; +import com.jd.blockchain.mocker.contracts.AccountContract; +import com.jd.blockchain.mocker.contracts.AccountContractImpl; +import org.junit.Before; +import org.junit.Test; + +public class AccountMockerTest { + + String accountFrom = "zhangsan"; + + String accountTo = "lisi"; + + MockerNodeContext mockerNodeContext = null; + + HashDigest ledgerHash = null; + + @Before + public void init() { + mockerNodeContext = new MockerNodeContext().build(); + ledgerHash = mockerNodeContext.getLedgerHash(); + } + + @Test + public void test() { + // 首先创建一个数据账户 + String address = mockerNodeContext.registerDataAccount(); + + // 处理合约 + AccountContract accountContract = new AccountContractImpl(); + + // 发布合约 + accountContract = mockerNodeContext.deployContract(accountContract); + + //首先创建账户 + accountContract.create(address, accountFrom, 1000L); + + accountContract.create(address, accountTo, 1000L); + + accountContract.print(address, accountFrom, accountTo); + + // 开始转账 + accountContract.transfer(address, accountFrom, accountTo, 500); + + // 打印转账后结果 + accountContract.print(address, accountFrom, accountTo); + } +} diff --git a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/MockTest.java b/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/MockTest.java new file mode 100644 index 00000000..7cd85dbc --- /dev/null +++ b/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/MockTest.java @@ -0,0 +1,54 @@ +package com.jd.blockchain.test; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.mocker.MockerNodeContext; +import com.jd.blockchain.mocker.config.MockerConstant; +import com.jd.blockchain.mocker.contracts.WriteContract; +import com.jd.blockchain.mocker.contracts.WriteContractImpl; +import org.junit.Test; + +public class MockTest { + + @Test + public void test() { + // 准备环境 + BlockchainKeypair blockchainKeypair = BlockchainKeyGenerator.getInstance().generate(); + MockerNodeContext mockerNodeContext = + new MockerNodeContext(MockerConstant.DEFAULT_LEDGER_SEED) + .participants("zhangsan", blockchainKeypair) + .build(); + HashDigest ledgerHash = mockerNodeContext.getLedgerHash(); + + System.out.printf("LedgerHash = %s \r\n", ledgerHash.toBase58()); + System.out.printf("LedgerSeed = %s \r\n", mockerNodeContext.getLedgerSeed()); + + // 注册用户 + String userAddress = mockerNodeContext.registerUser(BlockchainKeyGenerator.getInstance().generate()); + System.out.printf("----- 注册用户地址 {%s} -----\r\n", userAddress); + + // 注册数据账户 + String dataAccountAddress = mockerNodeContext.registerDataAccount(BlockchainKeyGenerator.getInstance().generate()); + System.out.printf("----- 注册数据账户地址 {%s} -----\r\n", dataAccountAddress); + + WriteContract writeContract = new WriteContractImpl(); + + // 发布合约 + writeContract = mockerNodeContext.deployContract(writeContract); + + writeContract.print("张三"); + + String key = "Hello", value = "World"; + + writeContract.writeKv(dataAccountAddress, key, value); + + // 查询 + KVDataEntry[] kvDataEntries = mockerNodeContext.getDataEntries(ledgerHash, dataAccountAddress, key); + + for (KVDataEntry kvDataEntry : kvDataEntries) { + System.out.printf("Key = %s, Value = %s \r\n", kvDataEntry.getKey(), kvDataEntry.getValue()); + } + } +} diff --git a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/SampleTest.java b/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/SampleTest.java new file mode 100644 index 00000000..e66d534e --- /dev/null +++ b/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/SampleTest.java @@ -0,0 +1,47 @@ +package com.jd.blockchain.test; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.mocker.MockerNodeContext; +import com.jd.blockchain.mocker.contracts.WriteContract; +import com.jd.blockchain.mocker.contracts.WriteContractImpl; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class SampleTest { + + MockerNodeContext mockerNodeContext = null; + + HashDigest ledgerHash = null; + + @Before + public void init() { + mockerNodeContext = new MockerNodeContext().build(); + ledgerHash = mockerNodeContext.getLedgerHash(); + } + + @Test + public void writeTest() { + + String key = "MyKey-" + System.currentTimeMillis(), value = "JDChain"; + + WriteContract writeContract = new WriteContractImpl(); + + String dataAccountAddress = mockerNodeContext.registerDataAccount(); + + writeContract = mockerNodeContext.deployContract(writeContract); + + writeContract.writeKv(dataAccountAddress, key, value); + + // 查询结果 + KVDataEntry[] dataEntries = mockerNodeContext.getDataEntries(ledgerHash, dataAccountAddress, key); + + for (KVDataEntry kvDataEntry : dataEntries) { + assertEquals(key, kvDataEntry.getKey()); + assertEquals(value, kvDataEntry.getValue()); + System.out.printf("Key = %s, Value = %s \r\n", kvDataEntry.getKey(), kvDataEntry.getValue()); + } + } +} From 06a932279c26f4007e477795c79d9c9d4da72a0d Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Thu, 30 May 2019 11:16:27 +0800 Subject: [PATCH 18/23] Change String.getBytes() to UTF-8 Encode ! --- .../blockchain/crypto/utils/sm/SM2Utils.java | 6 +- .../gateway/boot/GatewayBooter.java | 3 +- .../jd/blockchain/boot/peer/PeerBooter.java | 3 +- .../impl/handles/ContractLedgerContext.java | 9 +- .../sdk/client/ClientOperationUtil.java | 7 +- .../blockchain/mocker/MockerNodeContext.java | 3 +- .../src/main/resources/bftsmart.config | 167 ++++++++++++++++++ .../contract}/AccountMockerTest.java | 2 +- .../com/jd/blockchain/contract}/MockTest.java | 2 +- .../jd/blockchain/contract}/SampleTest.java | 2 +- .../blockchain/utils/security/DESUtils.java | 4 +- 11 files changed, 191 insertions(+), 17 deletions(-) create mode 100644 source/tools/tools-mocker/src/main/resources/bftsmart.config rename source/tools/tools-mocker/src/test/java/{com/jd/blockchain/test => test/com/jd/blockchain/contract}/AccountMockerTest.java (97%) rename source/tools/tools-mocker/src/test/java/{com/jd/blockchain/test => test/com/jd/blockchain/contract}/MockTest.java (98%) rename source/tools/tools-mocker/src/test/java/{com/jd/blockchain/test => test/com/jd/blockchain/contract}/SampleTest.java (97%) diff --git a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM2Utils.java b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM2Utils.java index 47fe9f6c..7a993c1d 100644 --- a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM2Utils.java +++ b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM2Utils.java @@ -1,5 +1,6 @@ package com.jd.blockchain.crypto.utils.sm; +import com.jd.blockchain.utils.io.BytesUtils; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; @@ -99,7 +100,7 @@ public class SM2Utils { public static byte[] sign(byte[] data, byte[] privateKey, SecureRandom random, String ID){ ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(new BigInteger(1,privateKey), DOMAIN_PARAMS); - CipherParameters params = new ParametersWithID(new ParametersWithRandom(privKey,random),ID.getBytes()); + CipherParameters params = new ParametersWithID(new ParametersWithRandom(privKey,random), BytesUtils.toBytes(ID)); return sign(data,params); } @@ -153,8 +154,7 @@ public class SM2Utils { ECPoint pubKeyPoint = resolvePubKeyBytes(publicKey); ECPublicKeyParameters pubKey = new ECPublicKeyParameters(pubKeyPoint, DOMAIN_PARAMS); - ParametersWithID params = new ParametersWithID(pubKey,ID.getBytes()); - + ParametersWithID params = new ParametersWithID(pubKey, BytesUtils.toBytes(ID)); return verify(data,params,signature); } diff --git a/source/deployment/deployment-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java b/source/deployment/deployment-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java index 2cec1a5f..93ca75ff 100644 --- a/source/deployment/deployment-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java +++ b/source/deployment/deployment-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.FileOutputStream; import java.lang.management.ManagementFactory; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -49,7 +50,7 @@ public class GatewayBooter { bootInfos.add(String.format("GW_BOOT_PID = [%s] \r\n", pid)); try (FileOutputStream outputStream = new FileOutputStream(pidFile)) { for (String bootInfo : bootInfos) { - outputStream.write(bootInfo.getBytes()); + outputStream.write(bootInfo.getBytes(StandardCharsets.UTF_8)); } outputStream.flush(); } diff --git a/source/deployment/deployment-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java b/source/deployment/deployment-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java index 1bde8881..c8784892 100644 --- a/source/deployment/deployment-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java +++ b/source/deployment/deployment-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -70,7 +71,7 @@ public class PeerBooter { bootInfos.add(String.format("PEER_BOOT_PID = [%s] \r\n", pid)); try (FileOutputStream outputStream = new FileOutputStream(pidFile)) { for (String bootInfo : bootInfos) { - outputStream.write(bootInfo.getBytes()); + outputStream.write(bootInfo.getBytes(StandardCharsets.UTF_8)); } outputStream.flush(); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java index 43595152..60d418a5 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java @@ -253,10 +253,10 @@ public class ContractLedgerContext implements LedgerContext { public boolean isJson(String str) { boolean result = false; try { - Object obj=JSON.parse(str); + Object obj = JSON.parse(str); result = true; } catch (Exception e) { - result=false; + result = false; } return result; } @@ -278,10 +278,11 @@ public class ContractLedgerContext implements LedgerContext { public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) { BytesValue bytesValue; if (isJson(value)) { - bytesValue = new BytesValueEntry(BytesValueType.JSON, value.getBytes()); + + bytesValue = new BytesValueEntry(BytesValueType.JSON, BytesUtils.toBytes(value)); } else { - bytesValue = new BytesValueEntry(BytesValueType.TEXT, value.getBytes()); + bytesValue = new BytesValueEntry(BytesValueType.TEXT, BytesUtils.toBytes(value)); } this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); generatedOpList.add(op); diff --git a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java index f5790c06..c8fd9de8 100644 --- a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java +++ b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java @@ -18,6 +18,7 @@ import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.codec.Base58Utils; import com.jd.blockchain.utils.codec.HexUtils; import com.jd.blockchain.utils.io.BytesSlice; +import com.jd.blockchain.utils.io.BytesUtils; import org.apache.commons.codec.binary.Base64; import java.lang.reflect.Field; @@ -120,7 +121,7 @@ public class ClientOperationUtil { String ledgerSeedStr = legerInitObj.getString("ledgerSeed"); // 种子需要做Base64转换 - ledgerInitSettingData.setLedgerSeed(Base64.decodeBase64(ledgerSeedStr.getBytes())); + ledgerInitSettingData.setLedgerSeed(Base64.decodeBase64(BytesUtils.toBytes(ledgerSeedStr))); String consensusProvider = legerInitObj.getString("consensusProvider"); @@ -175,7 +176,7 @@ public class ClientOperationUtil { BlockchainIdentityData blockchainIdentity = blockchainIdentity(contract); String chainCodeStr = jsonObject.getString("chainCode"); - ContractCodeDeployOpTemplate contractCodeDeployOpTemplate = new ContractCodeDeployOpTemplate(blockchainIdentity, chainCodeStr.getBytes()); + ContractCodeDeployOpTemplate contractCodeDeployOpTemplate = new ContractCodeDeployOpTemplate(blockchainIdentity, BytesUtils.toBytes(chainCodeStr)); return contractCodeDeployOpTemplate; } @@ -184,7 +185,7 @@ public class ClientOperationUtil { String contractAddress = contractAddressObj.getString("value"); String argsStr = jsonObject.getString("args"); String event = jsonObject.getString("event"); - return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, argsStr.getBytes()); + return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, BytesUtils.toBytes(argsStr)); } private static BlockchainIdentityData blockchainIdentity(JSONObject jsonObject) { diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java index 08df2cc5..7d91a198 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java @@ -30,6 +30,7 @@ import com.jd.blockchain.tools.initializer.LedgerInitProperties; import com.jd.blockchain.tools.keygen.KeyGenCommand; import com.jd.blockchain.transaction.*; import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; import com.jd.blockchain.web.serializes.ByteArrayObjectUtil; import java.util.*; @@ -210,7 +211,7 @@ public class MockerNodeContext implements BlockchainQueryService { // 合约发布 // 注意此处只是将其放入内存中,而不需要真正编译为字节码 TxBuilder txBuilder = txBuilder(); - txBuilder.contracts().deploy(contractIdentity, contract.getClass().getName().getBytes()); + txBuilder.contracts().deploy(contractIdentity, BytesUtils.toBytes(contract.getClass().getName())); // 执行 txProcess(txRequest(txBuilder)); return contractIdentity; diff --git a/source/tools/tools-mocker/src/main/resources/bftsmart.config b/source/tools/tools-mocker/src/main/resources/bftsmart.config new file mode 100644 index 00000000..870fcde2 --- /dev/null +++ b/source/tools/tools-mocker/src/main/resources/bftsmart.config @@ -0,0 +1,167 @@ +# Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +############################################ +###### Consensus Commit Block Parameters: transaction count ###### +############################################ +system.block.txsize=500 + +############################################ +###### Consensus Commit Block Parameters: delay time ###### +############################################ +system.block.maxdelay=5000 + +############################################ +###### #Consensus Participant0 ###### +############################################ + +system.server.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 +system.server.0.network.host=127.0.0.1 +system.server.0.network.port=16000 +system.server.0.network.secure=false + +############################################ +###### #Consensus Participant1 ###### +############################################ + +system.server.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX +system.server.1.network.host=127.0.0.1 +system.server.1.network.port=16100 +system.server.1.network.secure=false + +############################################ +###### #Consensus Participant2 ###### +############################################ + +system.server.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x +system.server.2.network.host=127.0.0.1 +system.server.2.network.port=16200 +system.server.2.network.secure=false + +############################################ +###### #Consensus Participant3 ###### +############################################ + +system.server.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk +system.server.3.network.host=127.0.0.1 +system.server.3.network.port=16300 +system.server.3.network.secure=false + +############################################ +####### Communication Configurations ####### +############################################ + +#HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value) +#This parameter is not currently being used +#system.authentication.hmacAlgorithm = HmacSHA1 + +#Specify if the communication system should use a thread to send data (true or false) +system.communication.useSenderThread = true + +#Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments +#and benchmarks, but must not be used in production systems. +system.communication.defaultkeys = true + +############################################ +### Replication Algorithm Configurations ### +############################################ + +#Number of servers in the group +system.servers.num = 4 + +#Maximum number of faulty replicas +system.servers.f = 1 + +#Timeout to asking for a client request +system.totalordermulticast.timeout = 2000 + +#Maximum batch size (in number of messages) +system.totalordermulticast.maxbatchsize = 500 + +#Number of nonces (for non-determinism actions) generated +system.totalordermulticast.nonces = 10 + +#if verification of leader-generated timestamps are increasing +#it can only be used on systems in which the network clocks +#are synchronized +system.totalordermulticast.verifyTimestamps = false + +#Quantity of messages that can be stored in the receive queue of the communication system +system.communication.inQueueSize = 500000 + +# Quantity of messages that can be stored in the send queue of each replica +system.communication.outQueueSize = 500000 + +#Set to 1 if SMaRt should use signatures, set to 0 if otherwise +system.communication.useSignatures = 0 + +#Set to 1 if SMaRt should use MAC's, set to 0 if otherwise +system.communication.useMACs = 1 + +#Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise +system.debug = 0 + +#Print information about the replica when it is shutdown +system.shutdownhook = true + +############################################ +###### State Transfer Configurations ####### +############################################ + +#Activate the state transfer protocol ('true' to activate, 'false' to de-activate) +system.totalordermulticast.state_transfer = true + +#Maximum ahead-of-time message not discarded +system.totalordermulticast.highMark = 10000 + +#Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered) +system.totalordermulticast.revival_highMark = 10 + +#Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs +system.totalordermulticast.timeout_highMark = 200 + +############################################ +###### Log and Checkpoint Configurations ### +############################################ + +system.totalordermulticast.log = true +system.totalordermulticast.log_parallel = false +system.totalordermulticast.log_to_disk = false +system.totalordermulticast.sync_log = false + +#Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol) +system.totalordermulticast.checkpoint_period = 1000 +system.totalordermulticast.global_checkpoint_period = 120000 + +system.totalordermulticast.checkpoint_to_disk = false +system.totalordermulticast.sync_ckp = false + + +############################################ +###### Reconfiguration Configurations ###### +############################################ + +#Replicas ID for the initial view, separated by a comma. +# The number of replicas in this parameter should be equal to that specified in 'system.servers.num' +system.initial.view = 0,1,2,3 + +#The ID of the trust third party (TTP) +system.ttp.id = 7002 + +#This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults +system.bft = true + +#Custom View Storage; +#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage \ No newline at end of file diff --git a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/AccountMockerTest.java b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java similarity index 97% rename from source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/AccountMockerTest.java rename to source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java index 55699a40..d52a3732 100644 --- a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/AccountMockerTest.java +++ b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java @@ -1,4 +1,4 @@ -package com.jd.blockchain.test; +package test.com.jd.blockchain.contract; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.mocker.MockerNodeContext; diff --git a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/MockTest.java b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/MockTest.java similarity index 98% rename from source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/MockTest.java rename to source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/MockTest.java index 7cd85dbc..b9362607 100644 --- a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/MockTest.java +++ b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/MockTest.java @@ -1,4 +1,4 @@ -package com.jd.blockchain.test; +package test.com.jd.blockchain.contract; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainKeyGenerator; diff --git a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/SampleTest.java b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java similarity index 97% rename from source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/SampleTest.java rename to source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java index e66d534e..c388ef99 100644 --- a/source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/SampleTest.java +++ b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java @@ -1,4 +1,4 @@ -package com.jd.blockchain.test; +package test.com.jd.blockchain.contract; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.KVDataEntry; diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/security/DESUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/security/DESUtils.java index fb74c378..064f8a1b 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/security/DESUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/security/DESUtils.java @@ -1,5 +1,7 @@ package com.jd.blockchain.utils.security; +import com.jd.blockchain.utils.io.BytesUtils; + import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; @@ -32,7 +34,7 @@ public class DESUtils { SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey secretKey = keyFactory.generateSecret(keySpec); cipher.init(Cipher.ENCRYPT_MODE, secretKey); - return cipher.doFinal(code.getBytes()); + return cipher.doFinal(BytesUtils.toBytes(code)); } /** DES解密 */ From a472334b7e4372c58d634e542493b75928b2b5ae Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 31 May 2019 11:37:40 +0800 Subject: [PATCH 19/23] 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 20/23] 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 From 28933c5627079ae3a2ad82b687058c4463b3aba7 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 31 May 2019 13:41:26 +0800 Subject: [PATCH 21/23] clean --- .../src/main/java/com/jd/blockchain/binaryproto/DataType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1129518b..9df9f7bd 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; From 5c3c12109c4d309b205a74aae22e0caaeb7c2e06 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 31 May 2019 13:59:14 +0800 Subject: [PATCH 22/23] clean the unnecessary test --- .../sdk/test/SDK_Contract_Test.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) 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 76bdceed..359b4dd4 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,8 +23,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * 演示合约执行的过程; @@ -64,7 +63,7 @@ public class SDK_Contract_Test { /** * 演示合约执行的过程; */ - @Test +// @Test public void demoContract1() { String dataAddress = registerData4Contract(); // 发起交易; @@ -94,7 +93,7 @@ public class SDK_Contract_Test { /** * 演示合约执行的过程; */ - @Test +// @Test public void demoContract2() throws IOException { String contractAddress = deploy(); String dataAddress = registerData4Contract(); @@ -119,7 +118,7 @@ public class SDK_Contract_Test { assertEquals(888,dataEntries[1].getValue()); } - @Test +// @Test public void registerData(){ // 在本地定义 TX 模板 TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); @@ -347,15 +346,9 @@ 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; - } - }; + ContractBizContent contractBizContent = () -> new String[]{"1","2","you are welcome!"}; byte[] bizBytes = BinaryProtocol.encode(contractBizContent,ContractBizContent.class); ContractBizContent actualObj = BinaryProtocol.decodeAs(bizBytes,ContractBizContent.class); - assertEquals(contractBizContent,actualObj); + assertArrayEquals(contractBizContent.getAttrs(),actualObj.getAttrs()); } } From 845e7a4537adee26cbf870096a0f22ec7b7c9e77 Mon Sep 17 00:00:00 2001 From: zhaoguangwei Date: Fri, 31 May 2019 13:59:52 +0800 Subject: [PATCH 23/23] add IntegrationTest4Contract; --- .../intgr/IntegrationTest4Contract.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest4Contract.java diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest4Contract.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest4Contract.java new file mode 100644 index 00000000..c0c29be7 --- /dev/null +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest4Contract.java @@ -0,0 +1,106 @@ +package test.com.jd.blockchain.intgr; + +import com.jd.blockchain.crypto.AsymmetricKeypair; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.gateway.GatewayConfigProperties; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.core.LedgerRepository; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.storage.service.DbConnectionFactory; +import com.jd.blockchain.tools.initializer.LedgerBindingConfig; +import com.jd.blockchain.tools.keygen.KeyGenCommand; +import com.jd.blockchain.utils.concurrent.ThreadInvoker; + +import org.junit.Test; +import test.com.jd.blockchain.intgr.initializer.LedgerInitializeTest; +import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4Nodes; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static test.com.jd.blockchain.intgr.IntegrationBase.*; + +public class IntegrationTest4Contract { + private static final boolean isContractDeployAndExe = true; + private static final String DB_TYPE_MEM = "mem"; + + @Test + public void test4Memory() { + test(LedgerInitConsensusConfig.bftsmartProvider, DB_TYPE_MEM, LedgerInitConsensusConfig.memConnectionStrings); + } + + public void test(String[] providers, String dbType, String[] dbConnections) { + final ExecutorService sendReqExecutors = Executors.newFixedThreadPool(10); + // 内存账本初始化 + HashDigest ledgerHash = initLedger(dbConnections); + // 启动Peer节点 + PeerTestRunner[] peerNodes = peerNodeStart(ledgerHash, dbType); + DbConnectionFactory dbConnectionFactory0 = peerNodes[0].getDBConnectionFactory(); + DbConnectionFactory dbConnectionFactory1 = peerNodes[1].getDBConnectionFactory(); + DbConnectionFactory dbConnectionFactory2 = peerNodes[2].getDBConnectionFactory(); + DbConnectionFactory dbConnectionFactory3 = peerNodes[3].getDBConnectionFactory(); + + String encodedBase58Pwd = KeyGenCommand.encodePasswordAsBase58(LedgerInitializeTest.PASSWORD); + + GatewayConfigProperties.KeyPairConfig gwkey0 = new GatewayConfigProperties.KeyPairConfig(); + gwkey0.setPubKeyValue(IntegrationBase.PUB_KEYS[0]); + gwkey0.setPrivKeyValue(IntegrationBase.PRIV_KEYS[0]); + gwkey0.setPrivKeyPassword(encodedBase58Pwd); + GatewayTestRunner gateway = new GatewayTestRunner("127.0.0.1", 11000, gwkey0, + peerNodes[0].getServiceAddress(), providers,null); + + ThreadInvoker.AsyncCallback gwStarting = gateway.start(); + + gwStarting.waitReturn(); + + // 执行测试用例之前,校验每个节点的一致性; + LedgerRepository[] ledgers = buildLedgers(new LedgerBindingConfig[]{ + peerNodes[0].getLedgerBindingConfig(), + peerNodes[1].getLedgerBindingConfig(), + peerNodes[2].getLedgerBindingConfig(), + peerNodes[3].getLedgerBindingConfig(), + }, + new DbConnectionFactory[]{ + dbConnectionFactory0, + dbConnectionFactory1, + dbConnectionFactory2, + dbConnectionFactory3}); + + IntegrationBase.testConsistencyAmongNodes(ledgers); + + LedgerRepository ledgerRepository = ledgers[0]; + + GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(gateway.getServiceAddress()); + + PrivKey privkey0 = KeyGenCommand.decodePrivKeyWithRawPassword(IntegrationBase.PRIV_KEYS[0], IntegrationBase.PASSWORD); + + PubKey pubKey0 = KeyGenCommand.decodePubKey(IntegrationBase.PUB_KEYS[0]); + + AsymmetricKeypair adminKey = new AsymmetricKeypair(pubKey0, privkey0); + + BlockchainService blockchainService = gwsrvFact.getBlockchainService(); + + if(isContractDeployAndExe){ + IntegrationBase.testSDK_Contract(adminKey,ledgerHash,blockchainService,ledgerRepository); + } + + try { + System.out.println("----------------- Init Completed -----------------"); + Thread.sleep(Integer.MAX_VALUE); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + IntegrationBase.testConsistencyAmongNodes(ledgers); + } + private HashDigest initLedger(String[] dbConnections) { + LedgerInitializeWeb4Nodes ledgerInit = new LedgerInitializeWeb4Nodes(); + HashDigest ledgerHash = ledgerInit.testInitWith4Nodes(LedgerInitConsensusConfig.bftsmartConfig, dbConnections); + System.out.printf("LedgerHash = %s \r\n", ledgerHash.toBase58()); + return ledgerHash; + } +}