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 8cdfebfb..a0e2ab0a 100644 Binary files a/source/test/test-integration/src/test/resources/contract.jar and b/source/test/test-integration/src/test/resources/contract.jar differ