| @@ -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; | |||
| @@ -7,7 +7,7 @@ public interface DataType { | |||
| */ | |||
| public static final byte NIL = (byte) 0x00; | |||
| /** | |||
| /**LdeNhjPGzHcHL6rLcJ7whHxUbn9Tv7qSKRfEA | |||
| * 布尔; | |||
| */ | |||
| public static final byte BOOLEAN = (byte) 0x01; | |||
| @@ -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<DataContract> 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<ContractEvent> contractEventClass = null; | |||
| // try { | |||
| // contractEventClass = (Class<ContractEvent>) c.getClassLoader().loadClass(ContractEvent.class.getName()); | |||
| // } catch (ClassNotFoundException e) { | |||
| // e.printStackTrace(); | |||
| // } | |||
| // Method[] classMethods = c.getMethods(); | |||
| // Map<Method, Annotation[]> methodAnnoMap = new HashMap<Method, Annotation[]>(); | |||
| // Map<String, Method> annoMethodMap = new HashMap<String, Method>(); | |||
| // 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; | |||
| // } | |||
| // } | |||
| } | |||
| } | |||
| @@ -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<DataContract> 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<DataContract> dataContractList) { | |||
| byte[][] result = new byte[objArr.length][]; | |||
| //将method中形参转换为实体对象,每个形参都必须为@DataContract类型;每个形参使用系统的BinaryProtocol来进行序列化,如果有5个参数,则使用5次序列化; | |||
| int sum = 0; | |||
| for(int i=0;i<classTypes.length;i++){ | |||
| Class <?> 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<objArr.length;i++){ | |||
| DataContract dataContract = dataContractList.get(i); | |||
| objArr[i] = regenObj(dataContract,objArr[i]); | |||
| //get data interface; | |||
| result[i] = BinaryProtocol.encode(objArr[i],getDataIntf().get(dataContract.code())); | |||
| sum += result[i].length; | |||
| @@ -91,9 +52,9 @@ public class ContractSerializeUtils { | |||
| 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 * (objArr.length); | |||
| ByteBuffer byteBuffer = ByteBuffer.allocate(bodyFirstPosition + sum); | |||
| byteBuffer.putInt(classTypes.length); | |||
| byteBuffer.putInt(objArr.length); | |||
| for(int j=0; j<result.length; j++) { | |||
| byte[] curResult = result[j]; | |||
| byteBuffer.putInt(curResult.length); | |||
| @@ -108,59 +69,26 @@ public class ContractSerializeUtils { | |||
| * deserialize the params bytes[]; | |||
| * params format: nums|first length| second length| third length| ... |bytes[0]| byte[1] | bytes[2]| ... | |||
| * @param params | |||
| * @param method | |||
| * @param dataContractList | |||
| * @return | |||
| */ | |||
| public static Object[] deserializeMethodParam(byte[] params, Method method) { | |||
| if (params == null) { | |||
| return null; | |||
| } | |||
| Class<?>[] classTypes = method.getParameterTypes(); | |||
| Object result[] = new Object[classTypes.length]; | |||
| public static Object[] deserializeMethodParam(byte[] params, List<DataContract> 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<classTypes.length; i++){ | |||
| Class<?> classType = classTypes[i]; | |||
| int offsetPosition = (1 + dataContractList.size())*4; //start position of real data; | |||
| for(int i=0; i<dataContractList.size(); i++){ | |||
| DataContract dataContract = dataContractList.get(i); | |||
| int curParamLength = byteBuffer.getInt((i+1)*4); | |||
| 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; | |||
| // 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."); | |||
| } | |||
| } | |||
| 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; | |||
| } | |||
| } | |||
| @@ -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(); | |||
| } | |||
| @@ -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)); | |||
| } | |||
| } | |||
| @@ -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<Method, Annotation[]> methodAnnoMap = new HashMap<Method, Annotation[]>(); | |||
| Map<String, Method> annoMethodMap = new HashMap<String, Method>(); | |||
| 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 | |||
| @@ -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<String, Method> events = new HashMap<>(); | |||
| private Map<Method, String> handleMethods = new HashMap<>();; | |||
| private Map<Method, String> handleMethods = new HashMap<>(); | |||
| private Map<Method, List<DataContract>> dataContractMap = new HashMap<>(); | |||
| /** | |||
| * 返回声明的所有事件; | |||
| @@ -25,6 +27,10 @@ public class ContractType { | |||
| return events.keySet(); | |||
| } | |||
| public Map<Method, List<DataContract>> getDataContractMap() { | |||
| return dataContractMap; | |||
| } | |||
| /** | |||
| * 返回指定方法声明的事件;<br> | |||
| * | |||
| @@ -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_); | |||
| } | |||
| @@ -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 | |||
| @@ -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 <T> void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, | |||
| private static <T> void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey, | |||
| BlockchainService blockchainService,LedgerRepository ledgerRepository,Class<T> 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; | |||
| @@ -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); | |||
| } | |||