@@ -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); | |||
} |