Browse Source

Merge remote-tracking branch 'remotes/origin/feature/intf-contract' into develop

tags/1.0.0
zhaoguangwei 5 years ago
parent
commit
bfb28fc5a5
38 changed files with 1427 additions and 346 deletions
  1. +10
    -0
      source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
  2. +1
    -1
      source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataContract.java
  3. +1
    -1
      source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java
  4. +53
    -64
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java
  5. +16
    -16
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java
  6. +3
    -6
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java
  7. +196
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java
  8. +20
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java
  9. +19
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java
  10. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java
  11. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java
  12. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java
  13. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java
  14. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java
  15. +20
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java
  16. +12
    -5
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java
  17. +11
    -10
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java
  18. +53
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java
  19. +70
    -17
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java
  20. +15
    -4
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java
  21. +13
    -10
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java
  22. +7
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java
  23. +8
    -0
      source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java
  24. +93
    -0
      source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java
  25. +53
    -0
      source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java
  26. +20
    -13
      source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java
  27. +361
    -0
      source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java
  28. +8
    -8
      source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java
  29. BIN
      source/sdk/sdk-samples/src/test/resources/contract.jar
  30. +13
    -0
      source/sdk/sdk-samples/src/test/resources/sys-contract.properties
  31. +91
    -108
      source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java
  32. +57
    -18
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java
  33. +15
    -26
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java
  34. +14
    -35
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java
  35. +39
    -0
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract.java
  36. +44
    -0
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java
  37. BIN
      source/test/test-integration/src/test/resources/contract.jar
  38. +1
    -1
      source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java

+ 10
- 0
source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java View File

@@ -79,7 +79,17 @@ 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;
//...0xA19
public static final int CONTRACT_BIZ_CONTENT = 0xA20;

public static final int HASH = 0xB00;



+ 1
- 1
source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataContract.java View File

@@ -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 {



+ 1
- 1
source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java View File

@@ -7,7 +7,7 @@ public interface DataType {
*/
public static final byte NIL = (byte) 0x00;

/**
/**LdeNhjPGzHcHL6rLcJ7whHxUbn9Tv7qSKRfEA
* 布尔;
*/
public static final byte BOOLEAN = (byte) 0x01;


+ 53
- 64
source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java View File

@@ -1,24 +1,24 @@
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.binaryproto.DataContract;
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.utils.BaseConstant;
import com.jd.blockchain.transaction.ContractType;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.IllegalDataException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.List;

/**
* contract code based jvm
* @author zhaogw
*
* @author zhaogw
*/
public class JavaContractCode implements ContractCode {
private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class);
@@ -26,7 +26,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 +39,7 @@ public class JavaContractCode implements ContractCode {
public Bytes getAddress() {
return address;
}
@Override
public long getVersion() {
return version;
@@ -46,75 +48,62 @@ 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, List<DataContract> dataContractList) {
if(args == null || args.length == 0){
return null;
}
return ContractSerializeUtils.deserializeMethodParam(args,dataContractList);
}

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);
// 反序列化参数;
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(),
contractType.getDataContractMap().get(handleMethod));

LOGGER.info("合约执行,耗时:"+(System.currentTimeMillis()-startTime));
Object[] params = null;
if(args.getClass().isArray()){
params = (Object[])args;
}
ReflectionUtils.invokeMethod(handleMethod, contractMainClassObj, params);

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();
throw new IllegalArgumentException(e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}

//得到当前类中相关方法和注解对应关系;
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;
throw new IllegalDataException(e.getMessage());
}
}
}

}

+ 16
- 16
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java View File

@@ -49,22 +49,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();


+ 3
- 6
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java View File

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


+ 196
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java View File

@@ -0,0 +1,196 @@
package com.jd.blockchain.contract;

import com.jd.blockchain.binaryproto.BinaryProtocol;
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.nio.ByteBuffer;
import java.util.Arrays;
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<Integer, Class<?>> DATA_CONTRACT_MAP = new HashMap<>();
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 };

/**
* serialize the Object[] by List<DataContract> list;
* @param objArr
* @param dataContractList
* @return
*/
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<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;
}
/**
* 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);
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 * (objArr.length);
ByteBuffer byteBuffer = ByteBuffer.allocate(bodyFirstPosition + sum);
byteBuffer.putInt(objArr.length);
for(int j=0; j<result.length; j++) {
byte[] curResult = result[j];
byteBuffer.putInt(curResult.length);
}
for(int k=0; k<result.length; k++){
byteBuffer.put(result[k]);
}
return byteBuffer.array();
}

/**
* deserialize the params bytes[];
* params format: nums|first length| second length| third length| ... |bytes[0]| byte[1] | bytes[2]| ...
* @param params
* @param dataContractList
* @return
*/
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 != dataContractList.size()){
throw new IllegalArgumentException("deserialize Method param. params'length in byte[] != method's param length");
}

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


/**
* the param types that we can support;
* @param <T>
* @return
*/
public static <T> Map<Integer, Class<?> > getDataIntf(){
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.CONTRACT_BIZ_CONTENT, ContractBizContent.class);
return DATA_CONTRACT_MAP;
}

public static boolean isPrimitiveType(int dataContractCode){
return Arrays.asList(PRIMITIVE_DATA_CODES).contains(dataContractCode);
}

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());
}else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT32.class)){
return (CONTRACT_INT32) () -> Integer.parseInt(object.toString());
}else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT64.class)){
return (CONTRACT_INT64) () -> Long.parseLong(object.toString());
}else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_TEXT.class)){
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(ContractBizContent.class)){
ContractBizContent contractBizContent = (ContractBizContent)object;
return contractBizContent;
}else {
throw new IllegalDataException("cann't get new Object by dataContract and object.");
}
}

/**
* 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;
}else {
throw new IllegalDataException(String.format("no support the classType=%s, please check @DataContract.",classType.toString()));
}
}

public static DataContract parseDataContract(Class<?> classType){
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.getAnnotation(DataContract.class);
}
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;
}
}

+ 20
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java View File

@@ -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_BIG_INT)
public interface CONTRACT_BIG_INT {

@DataField(order=2, primitiveType= PrimitiveType.BIG_INT)
BigDecimal getValue();
}

+ 19
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java View File

@@ -0,0 +1,19 @@
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.utils.Bytes;

/**
* 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)
Bytes getValue();
}

+ 18
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java View File

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

+ 18
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java View File

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

+ 18
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java View File

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

+ 18
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java View File

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

+ 18
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java View File

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

+ 20
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java View File

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

/**
* build complex param Object, provide more String attributes;
*/
@DataContract(code = DataCodes.CONTRACT_BIZ_CONTENT)
public interface ContractBizContent {
/**
* param lists;
* @return
*/
@DataField(order = 1, list = true, primitiveType = PrimitiveType.TEXT, genericContract = true)
String[] getAttrs();

}

+ 12
- 5
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java View File

@@ -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<Operation> operationList = new ArrayList<>();
@Override
@@ -74,15 +75,18 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
return contractCodeDeployOpBuilder;
}
@Override
public ContractEventSendOperationBuilder contractEvents() {
return contractEventSendOpBuilder;
}
@Override
public <T> T contract(String address, Class<T> contractIntf) {
// TODO Auto-generated method stub
return null;
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder);
}
@Override
public <T> T contract(Bytes address, Class<T> contractIntf) {
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder);
}
public Collection<Operation> getOperations() {
@@ -153,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);
@@ -162,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);
@@ -171,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);


+ 11
- 10
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java View File

@@ -1,7 +1,8 @@
package com.jd.blockchain.transaction;

import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils;
import com.jd.blockchain.utils.IllegalDataException;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
@@ -19,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 对象的方法;
@@ -39,15 +38,17 @@ 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) {
// TODO 根据方法参数的定义序列化参数;
return BinarySerializeUtils.serialize(args);
private byte[] serializeArgs(Object[] args, Method method) {
if(args == null || args.length==0){
return null;
}
return ContractSerializeUtils.serializeMethodParam(args,contractType.getDataContractMap().get(method));
}
}

+ 53
- 1
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java View File

@@ -1,6 +1,58 @@
package com.jd.blockchain.transaction;
class ContractInvocationProxyBuilder {
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<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>();
public <T> T create(String address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) {
return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder);
}
@SuppressWarnings("unchecked")
public <T> T create(Bytes address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) {
ContractType contractType = resolveContractType(contractIntf);
ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType,
contractEventBuilder);
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 检查返回值类型;
ContractType contractType1 = ContractType.resolve(contractIntf);
contractTypes.put(contractIntf,contractType1);
return contractType1;
}
/**
* 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;
}
}

+ 70
- 17
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java View File

@@ -1,26 +1,36 @@
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.Set;
import java.util.SortedMap;
import java.util.*;

public class ContractType {

class ContractType {
private String name;
private SortedMap<String, Method> events;
private SortedMap<Method, String> handleMethods;
private Map<String, Method> events = new HashMap<>();
private Map<Method, String> handleMethods = new HashMap<>();
private Map<Method, List<DataContract>> dataContractMap = new HashMap<>();

/**
* 返回声明的所有事件;
*
* @return
*/
Set<String> getEvents() {
public Set<String> getEvents() {
return events.keySet();
}

public Map<Method, List<DataContract>> getDataContractMap() {
return dataContractMap;
}

/**
* 返回指定方法声明的事件;<br>
*
@@ -29,7 +39,7 @@ class ContractType {
* @param method
* @return
*/
String getEvent(Method method) {
public String getEvent(Method method) {
return handleMethods.get(method);
}

@@ -41,16 +51,59 @@ 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){
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) {
// if current method contains @ContractEvent,then put it in this map;
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("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_);
}
}
return contractType;
}

@Override
public String toString() {
return "ContractType{" +
"name='" + name + '\'' +
", events=" + events +
", handleMethods=" + handleMethods +
'}';
}
}

+ 15
- 4
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java View File

@@ -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> T contract(String address, Class<T> contractIntf);
/**
* 创建调用合约的代理实例;
@@ -17,6 +28,6 @@ public interface EventOperator {
* @param contractIntf
* @return
*/
<T> T contract(String address, Class<T> contractIntf);
<T> T contract(Bytes address, Class<T> contractIntf);

}

+ 13
- 10
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java View File

@@ -19,7 +19,7 @@ public class TxBuilder implements TransactionBuilder {
private BlockchainOperationFactory opFactory = new BlockchainOperationFactory();

private static final String DEFAULT_HASH_ALGORITHM = "SHA256";
private HashDigest ledgerHash;

public TxBuilder(HashDigest ledgerHash) {
@@ -36,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;
}

@@ -53,7 +53,7 @@ public class TxBuilder implements TransactionBuilder {
public LedgerInitOperationBuilder ledgers() {
return opFactory.ledgers();
}
@Override
public UserRegisterOperationBuilder users() {
return opFactory.users();
@@ -63,7 +63,7 @@ public class TxBuilder implements TransactionBuilder {
public DataAccountRegisterOperationBuilder dataAccounts() {
return opFactory.dataAccounts();
}
@Override
public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) {
return opFactory.dataAccount(accountAddress);
@@ -79,15 +79,18 @@ public class TxBuilder implements TransactionBuilder {
return opFactory.contracts();
}

@Override
public ContractEventSendOperationBuilder contractEvents() {
return opFactory.contractEvents();
}

@Override
public <T> T contract(Bytes address, Class<T> contractIntf) {
return opFactory.contract(address, contractIntf);
}

@Override
public <T> T contract(String address, Class<T> contractIntf) {
// TODO Auto-generated method stub
throw new IllegalStateException("Not implemented.");
return opFactory.contract(address, contractIntf);
}

}

+ 7
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java View File

@@ -53,9 +53,14 @@ public class TxTemplate implements TransactionTemplate {
return txBuilder.contracts();
}
// @Override
// public ContractEventSendOperationBuilder contractEvents() {
// return txBuilder.contractEvents();
// }
@Override
public ContractEventSendOperationBuilder contractEvents() {
return txBuilder.contractEvents();
public <T> T contract(Bytes address, Class<T> contractIntf) {
return txBuilder.contract(address, contractIntf);
}
@Override


+ 8
- 0
source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java View File

@@ -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(ContractBizContent.class);
ByteArrayObjectUtil.init();
}


+ 93
- 0
source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java View File

@@ -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<String> allKeys = pp.stringPropertyNames();
List<String> 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<String,String> 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<String,String> 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();
}
}
}

+ 53
- 0
source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java View File

@@ -0,0 +1,53 @@
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.ContractBizContent;
import com.jd.blockchain.ledger.TransactionContentBody;
import com.jd.blockchain.utils.Bytes;

import java.math.BigDecimal;

/**
* 示例:一个“资产管理”智能合约;
*
* @author zhaogw
*/
@Contract
public interface AssetContract2 {

/**
* 发行资产;
* 新发行的资产数量;
* @param assetHolderAddress
* 新发行的资产的持有账户;
*/
@ContractEvent(name = "issue-asset-0")
void issue(ContractBizContent contractBizContent, String assetHolderAddress);

/**
* issue asset;
* @param contractBizContent
* @param assetHolderAddress
* @param cashNumber
*/
@ContractEvent(name = "issue-asset")
public void issue(ContractBizContent contractBizContent, String assetHolderAddress, 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 issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber);
}

+ 20
- 13
source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java View File

@@ -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 = "ffkjhkeqwiuhivnsh3298josijdocaijsda==";
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) };
// 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 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";
// 此次待分配利润;
@@ -68,9 +72,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 准备就绪;


+ 361
- 0
source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java View File

@@ -0,0 +1,361 @@
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.ledger.*;
import com.jd.blockchain.sdk.BlockchainService;
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.assertEquals;
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 = "j5qHcS8jG6XwpE5wXv9HYMeGTb5Fs2gQao3TPQ3irqFpQL";
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() {
String dataAddress = registerData4Contract();
// 发起交易;
TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash);
String contractAddress = "LdeNg8JHFCKABJt6AaRNVCZPgY4ofGPd8MgcR";
AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class);
// 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(Byte.parseByte("126"),dataAddress,Bytes.fromString("100.234"));

// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
prepTx.sign(signKeyPair);
// 提交交易;
TransactionResponse transactionResponse = prepTx.commit();

//check;
KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,"total");
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 模板
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 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);
txTemp.dataAccount(dataAccount.getAddress()).set("param1", "v", -1);
txTemp.dataAccount(dataAccount.getAddress()).set("param2", 123, -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);
BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate();

for(int i=0; i<keys.length; i++){
txTemp.dataAccount(dataAddress).set(keys[i], values[i], version);
}

// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
prepTx.sign(signKeyPair);
// 提交交易;
TransactionResponse transactionResponse = prepTx.commit();
assertTrue(transactionResponse.isSuccess());
}

private String deploy() throws IOException {
ClassPathResource classPathResource = new ClassPathResource("contract.jar");
byte[] chainCode = this.getChainCode(classPathResource.getURL().getPath());
TransactionTemplate txTpl = this.bcsrv.newTransaction(ledgerHash);
BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity();
txTpl.contracts().deploy(contractIdentity, chainCode);
PreparedTransaction ptx = txTpl.prepare();
ptx.sign(signKeyPair);
TransactionResponse txResp = ptx.commit();
System.out.println("contract's address=" + contractIdentity.getAddress());
String contractAddr = contractIdentity.getAddress().toBase58();
log.info("contractAddr="+contractAddr);
return contractAddr;
}

public byte[] getChainCode(String path) {
byte[] chainCode = null;
File file = null;
FileInputStream input = null;

try {
file = new File(path);
input = new FileInputStream(file);
chainCode = new byte[input.available()];
input.read(chainCode);
} catch (IOException var14) {
var14.printStackTrace();
} finally {
try {
if (input != null) {
input.close();
}
} catch (IOException var13) {
var13.printStackTrace();
}

}

return chainCode;
}

/**
* 演示合约执行的过程;
*/
public static void demoContract() {
// 账本地址;
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 = "localhost";
final int GATEWAY_PORT = 11000;
final boolean SECURE = false;
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE,
CLIENT_CERT);
BlockchainService service = serviceFactory.getBlockchainService();

HashDigest ledgerHash = getLedgerHash();
// 发起交易;
TransactionTemplate txTemp = service.newTransaction(ledgerHash);

// --------------------------------------
// 一个贸易账户,贸易结算后的利润将通过一个合约账户来执行利润分配;
// 合约账户被设置为通用的账户,不具备对贸易结算账户的直接权限;
// 只有当前交易发起人具备对贸易账户的直接权限,当交易发起人对交易进行签名之后,权限被间接传递给合约账户;
String commerceAccount = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
// 处理利润分成的通用业务逻辑的合约账户;
String profitDistributionContract = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";

// 收益人账户;
String receiptorAccount1 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
String receiptorAccount2 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
// 资产编码;
String assetKey = "RMB-ASSET";
// 此次待分配利润;
long profit = 1000000;

// 备注信息;
Remark remark = new Remark();
String remarkJSON = JSONSerializeUtils.serializeToJSON(remark);
AssetContract assetContract = txTemp.contract(profitDistributionContract, AssetContract.class);
assetContract.issue(1000, receiptorAccount1);
assetContract.transfer(receiptorAccount1, receiptorAccount2, 600);
// assetContract.
// --------------------------------------

// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
String txHash = ByteArray.toBase64(prepTx.getHash().toBytes());

// 使用私钥进行签名;
AsymmetricKeypair keyPair = getSponsorKey();
prepTx.sign(keyPair);

// 提交交易;
prepTx.commit();
}

private static HashDigest getLedgerHash() {
return new HashDigest(Base58Utils.decode(ledgerAddress));
}

/**
* 交易发起人的私钥;<br>
*
* 注:私钥由调用方在本地保管和使用;
*
* @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;
}

}

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

+ 8
- 8
source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java View File

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


BIN
source/sdk/sdk-samples/src/test/resources/contract.jar View File


+ 13
- 0
source/sdk/sdk-samples/src/test/resources/sys-contract.properties View File

@@ -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


+ 91
- 108
source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java View File

@@ -1,38 +1,13 @@
package test.com.jd.blockchain.intgr;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

import org.springframework.core.io.ClassPathResource;

import com.jd.blockchain.consensus.ConsensusProvider;
import com.jd.blockchain.consensus.ConsensusProviders;
import com.jd.blockchain.consensus.ConsensusSettings;
import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInfo;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.UserInfo;
import com.jd.blockchain.ledger.core.DataAccountSet;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.LedgerManage;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
@@ -48,10 +23,18 @@ import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.codec.HexUtils;
import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback;
import com.jd.blockchain.utils.net.NetworkAddress;
import org.springframework.core.io.ClassPathResource;
import test.com.jd.blockchain.intgr.IntegratedContext.Node;
import test.com.jd.blockchain.intgr.perf.LedgerInitializeWebTest;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class IntegrationTest {
// 合约测试使用的初始化数据;
BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate();
@@ -547,87 +530,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) {


+ 57
- 18
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java View File

@@ -28,11 +28,14 @@ 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 test.com.jd.blockchain.intgr.contract.AssetContract2;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@@ -52,6 +55,7 @@ import static org.junit.Assert.*;
*/

public class IntegrationBase {
public static String KEY_TOTAL = "total";

static {
DataContractRegistry.register(LedgerInitOperation.class);
@@ -105,6 +109,9 @@ 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();
@@ -430,18 +437,16 @@ 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) {
KeyPairResponse keyPairResponse = testSDK_RegisterDataAccount(adminKey,ledgerHash,blockchainService);

System.out.println("adminKey="+ AddressEncoding.generateAddress(adminKey.getPubKey()));
BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate();
System.out.println("userKey="+userKey.getAddress());
@@ -460,22 +465,22 @@ public class IntegrationBase {
TransactionResponse txResp = ptx.commit();
assertTrue(txResp.isSuccess());

// 验证结果;
txResp.getContentHash();
// 验证结果hash请求的hash=相应的内容hash;
assertEquals(ptx.getHash(),txResp.getContentHash());

LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight());
byte[] contractCodeInDb = ledgerRepository.getContractAccountSet(block).getContract(contractDeployKey.getAddress())
.getChainCode();
assertArrayEquals(contractCode, contractCodeInDb);
txContentHash = ptx.getHash();

// execute the contract;
testContractExe(adminKey, ledgerHash, userKey, blockchainService, ledgerRepository);
testContractExe(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository);
testContractExe1(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository);

return block;
}

private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey,
private static <T> void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey,
BlockchainService blockchainService,LedgerRepository ledgerRepository) {
LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash);
LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1);
@@ -483,8 +488,38 @@ public class IntegrationBase {
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);

txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName,
("888##123##" + contractDataKey.getAddress()).getBytes());
Byte byteObj = Byte.parseByte("123");
// txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj,
// contractDeployKey.getAddress().toBase58(),321123);
txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj,
dataKey.getAddress().toBase58(),Bytes.fromString("123321"));

// 签名;
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(0,1);
assertEquals("100",kvDataEntries[0].getValue().toString());
}

private static <T> 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();
@@ -494,8 +529,12 @@ public class IntegrationBase {
TransactionResponse txResp = ptx.commit();

// 验证结果;
txResp.getContentHash();
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());
}

/**
@@ -503,7 +542,7 @@ public class IntegrationBase {
*
* @return
*/
private byte[] getChainCodeBytes() {
private static byte[] getChainCodeBytes() {
// 构建合约的字节数组;
byte[] contractCode = null;
File file = null;


+ 15
- 26
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java View File

@@ -1,34 +1,12 @@
package test.com.jd.blockchain.intgr;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.ClassPathResource;

import com.jd.blockchain.consensus.ConsensusProvider;
import com.jd.blockchain.consensus.ConsensusProviders;
import com.jd.blockchain.consensus.ConsensusSettings;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInfo;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.sdk.client.GatewayServiceFactory;
@@ -39,18 +17,29 @@ import com.jd.blockchain.tools.initializer.Prompter;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback;
import com.jd.blockchain.utils.net.NetworkAddress;

import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
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;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;

import static org.junit.Assert.*;

/**
* 测试合约,提交后不立即进行验证,因为此时可能还没有完成正式结块;
*/
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,7 +304,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();


+ 14
- 35
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java View File

@@ -1,36 +1,8 @@
package test.com.jd.blockchain.intgr;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;

import org.junit.Test;
import org.springframework.core.io.ClassPathResource;

import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.crypto.*;
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInfo;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionState;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.DataAccount;
import com.jd.blockchain.ledger.core.DataAccountSet;
import com.jd.blockchain.ledger.core.LedgerManage;
@@ -47,9 +19,19 @@ import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.codec.HexUtils;
import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback;
import com.jd.blockchain.utils.net.NetworkAddress;

import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import test.com.jd.blockchain.intgr.contract.AssetContract;
import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;

import static org.junit.Assert.*;

public class IntegrationTestAll4Redis {

public static final String PASSWORD = "abc";
@@ -450,10 +432,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();


+ 39
- 0
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract.java View File

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

}

+ 44
- 0
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java View File

@@ -0,0 +1,44 @@
package test.com.jd.blockchain.intgr.contract;

import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;
import com.jd.blockchain.ledger.ContractBizContent;
import com.jd.blockchain.utils.Bytes;

import java.math.BigDecimal;

/**
* 示例:一个“资产管理”智能合约;
*
* @author zhaogw
*/
@Contract
public interface AssetContract2 {

/**
* 发行资产;
* 新发行的资产数量;
* @param assetHolderAddress
* 新发行的资产的持有账户;
*/
@ContractEvent(name = "issue-asset-0")
void issue(ContractBizContent contractBizContent, String assetHolderAddress);

/**
* 发行资产;
* 新发行的资产数量;
* @param assetHolderAddress
* 新发行的资产的持有账户;
*/
@ContractEvent(name = "issue-asset")
void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber);

@ContractEvent(name = "issue-asset-2")
void issue(Bytes bytes, String assetHolderAddress, long cashNumber);

@ContractEvent(name = "issue-asset-3")
void issue(Byte byteObj, String assetHolderAddress, long cashNumber);

@ContractEvent(name = "issue-asset-4")
void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber);
}

BIN
source/test/test-integration/src/test/resources/contract.jar View File


+ 1
- 1
source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java View File

@@ -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";


Loading…
Cancel
Save