@@ -1,11 +1,12 @@ | |||
package com.jd.blockchain.contract.jvm; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.runtime.Module; | |||
import com.jd.blockchain.transaction.ContractType; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||
import com.jd.blockchain.utils.IllegalDataException; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.util.ReflectionUtils; | |||
@@ -73,6 +74,9 @@ public class JavaContractCode implements ContractCode { | |||
// 反序列化参数; | |||
Method handleMethod = ContractType.resolve(myClass).getHandleMethod(contractEventContext.getEvent()); | |||
if (handleMethod == null){ | |||
throw new IllegalDataException("don't get this method by it's @ContractEvent."); | |||
} | |||
Object args = resolveArgs(contractEventContext.getArgs(), handleMethod); | |||
Object[] params = null; | |||
@@ -88,9 +92,9 @@ public class JavaContractCode implements ContractCode { | |||
ReflectionUtils.invokeMethod(mth2, contractMainClassObj); | |||
LOGGER.info("postEvent,耗时:" + (System.currentTimeMillis() - startTime)); | |||
} catch (NoSuchMethodException e) { | |||
e.printStackTrace(); | |||
throw new IllegalArgumentException(e.getMessage()); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
throw new IllegalDataException(e.getMessage()); | |||
} | |||
} | |||
@@ -21,9 +21,10 @@ import java.util.Map; | |||
*/ | |||
public class ContractSerializeUtils { | |||
public static Map<Integer, Class<?>> DATA_CONTRACT_MAP = new HashMap<>(); | |||
public static final Integer[] PRIMITIVE_TYPES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32, | |||
public static final Integer[] PRIMITIVE_DATA_CODES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32, | |||
DataCodes.CONTRACT_INT64, DataCodes.CONTRACT_BIG_INT,DataCodes.CONTRACT_TEXT, DataCodes.CONTRACT_BINARY }; | |||
/** | |||
* valid then parse the Object by Method params; | |||
* @param object | |||
@@ -31,7 +32,6 @@ public class ContractSerializeUtils { | |||
* @return | |||
*/ | |||
public static byte[] serializeMethodParam(Object object,Method method) { | |||
if (object == null) { | |||
return null; | |||
} | |||
@@ -53,15 +53,21 @@ public class ContractSerializeUtils { | |||
if(dataContract == null){ | |||
boolean canPass = false; | |||
//check by annotation; | |||
Annotation[] annotationArr = annotations[i]; | |||
for(Annotation annotation : annotationArr){ | |||
if(annotation instanceof DataContract){ | |||
dataContract = (DataContract) annotation; | |||
objArr[i] = regenObj(dataContract,objArr[i]); | |||
canPass = true; | |||
} | |||
// Annotation[] annotationArr = annotations[i]; | |||
// for(Annotation annotation : annotationArr){ | |||
// if(annotation instanceof DataContract){ | |||
// dataContract = (DataContract) annotation; | |||
// objArr[i] = regenObj(dataContract,objArr[i]); | |||
// canPass = true; | |||
// } | |||
// } | |||
//if parameterAnnotations don't contain @DataContract, is it primitive type? | |||
Class<?> contractType = getContractTypeByPrimitiveType(classType); | |||
dataContract = contractType.getDeclaredAnnotation(DataContract.class); | |||
if(dataContract != null){ | |||
objArr[i] = regenObj(dataContract,objArr[i]); | |||
canPass = true; | |||
} | |||
//if parameterAnnotations don't contain @DataContract, we will say goodbye. | |||
if(!canPass){ | |||
throw new IllegalArgumentException("must set @DataContract for each param of contract."); | |||
} | |||
@@ -131,12 +137,18 @@ public class ContractSerializeUtils { | |||
if(dataContract == null){ | |||
boolean canPass = false; | |||
//check by annotation; | |||
Annotation[] annotationArr = annotations[i]; | |||
for(Annotation annotation : annotationArr){ | |||
if(annotation.annotationType().equals(DataContract.class)){ | |||
dataContract = (DataContract) annotation; | |||
canPass = true; | |||
} | |||
// Annotation[] annotationArr = annotations[i]; | |||
// for(Annotation annotation : annotationArr){ | |||
// if(annotation.annotationType().equals(DataContract.class)){ | |||
// dataContract = (DataContract) annotation; | |||
// canPass = true; | |||
// } | |||
// } | |||
//if parameterAnnotations don't contain @DataContract, is it primitive type? | |||
Class<?> contractType = getContractTypeByPrimitiveType(classType); | |||
dataContract = contractType.getDeclaredAnnotation(DataContract.class); | |||
if(dataContract != null){ | |||
canPass = true; | |||
} | |||
if(!canPass){ | |||
throw new IllegalArgumentException("must set annotation in each param of contract."); | |||
@@ -183,7 +195,7 @@ public class ContractSerializeUtils { | |||
} | |||
public static boolean isPrimitiveType(int dataContractCode){ | |||
return Arrays.asList(PRIMITIVE_TYPES).contains(dataContractCode); | |||
return Arrays.asList(PRIMITIVE_DATA_CODES).contains(dataContractCode); | |||
} | |||
private static Object regenObj(DataContract dataContract, Object object){ | |||
@@ -204,4 +216,28 @@ public class ContractSerializeUtils { | |||
} | |||
return null; | |||
} | |||
/** | |||
* get contractType(contain @DataContract) by primitive class type; | |||
* some class type can be supported default (byte/char/int/long/String/Bytes, and so on). | |||
* in other words, need not contain the @DataContract in its class for contract param's serialization or deserialization. | |||
* @param classType | |||
* @return | |||
*/ | |||
private static Class<?> getContractTypeByPrimitiveType(Class<?> classType) { | |||
if(classType.equals(byte.class) || classType.equals(Byte.class)){ | |||
return CONTRACT_INT8.class; | |||
}else if(classType.equals(char.class) || classType.equals(Character.class)){ | |||
return CONTRACT_INT16.class; | |||
}else if(classType.equals(int.class) || classType.equals(Integer.class)){ | |||
return CONTRACT_INT32.class; | |||
}else if(classType.equals(long.class) || classType.equals(Long.class)){ | |||
return CONTRACT_INT64.class; | |||
}else if(classType.equals(String.class)){ | |||
return CONTRACT_TEXT.class; | |||
}else if(classType.equals(Bytes.class)){ | |||
return CONTRACT_BINARY.class; | |||
} | |||
return null; | |||
} | |||
} |
@@ -4,7 +4,6 @@ import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.contract.Contract; | |||
import com.jd.blockchain.contract.ContractEvent; | |||
import com.jd.blockchain.ledger.CONTRACT_TEXT; | |||
import com.jd.blockchain.ledger.TransactionContentBody; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -37,8 +36,18 @@ public interface AssetContract2 { | |||
@DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, | |||
@DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); | |||
/** | |||
* Bytes can bring the byte[]; | |||
* @param bytes | |||
* @param assetHolderAddress | |||
* @param cashNumber | |||
*/ | |||
@ContractEvent(name = "issue-asset-2") | |||
void issue(@DataContract(code = DataCodes.CONTRACT_BINARY) Bytes bytes, | |||
@DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, | |||
@DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber); | |||
void issue(Bytes bytes,String assetHolderAddress, long cashNumber); | |||
@ContractEvent(name = "issue-asset-3") | |||
void issue(Byte bytes, String assetHolderAddress, long cashNumber); | |||
@ContractEvent(name = "issue-asset-4") | |||
void issue1(byte[] bytes, String assetHolderAddress, long cashNumber); | |||
} |
@@ -1,85 +0,0 @@ | |||
package com.jd.blockchain.contract.samples; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.contract.ContractEvent; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.EventProcessingAwire; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
import com.jd.blockchain.ledger.KVDataObject; | |||
import com.jd.blockchain.ledger.TransactionContentBody; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Set; | |||
/** | |||
* 示例:一个“资产管理”智能合约的实现; | |||
* | |||
* 注: 1、实现 EventProcessingAwire 接口以便合约实例在运行时可以从上下文获得合约生命周期事件的通知; 2、实现 | |||
* AssetContract 接口定义的合约方法; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class AssetContractImpl2 implements EventProcessingAwire, AssetContract2 { | |||
// 合约事件上下文; | |||
private ContractEventContext eventContext; | |||
@Override | |||
public void issue(TransactionContentBody transactionContentBody, String assetHolderAddress) { | |||
System.out.println(transactionContentBody.toString()); | |||
} | |||
@Override | |||
@ContractEvent(name = "issue-asset") | |||
public void issue(@DataContract(code = DataCodes.TX_CONTENT_BODY) TransactionContentBody transactionContentBody, | |||
@DataContract(code = DataCodes.CONTRACT_TEXT) String assetHolderAddress, | |||
@DataContract(code = DataCodes.CONTRACT_INT64) long cashNumber) { | |||
System.out.println(transactionContentBody.toString()+",address="+assetHolderAddress+",cashNumber="+cashNumber); | |||
} | |||
@Override | |||
public void issue(Bytes bytes, String assetHolderAddress, long cashNumber) { | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.jd.blockchain.contract.model.EventProcessingAwire#beforeEvent(com.jd. | |||
* blockchain.contract.model.ContractEventContext) | |||
*/ | |||
@Override | |||
public void beforeEvent(ContractEventContext eventContext) { | |||
this.eventContext = eventContext; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.contract.model.EventProcessingAwire#postEvent(com.jd. | |||
* blockchain.contract.model.ContractEventContext, | |||
* com.jd.blockchain.contract.model.ContractError) | |||
*/ | |||
@Override | |||
public void postEvent(ContractEventContext eventContext, ContractException error) { | |||
this.eventContext = null; | |||
} | |||
@Override | |||
public void postEvent(ContractException error) { | |||
} | |||
@Override | |||
public void postEvent() { | |||
} | |||
} |
@@ -68,7 +68,7 @@ public class SDK_Contract_Test { | |||
public void demoContract1() { | |||
// 发起交易; | |||
TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); | |||
String contractAddress = "LdeNvwqrHKCDtEVv5m3nQSpJ66ahds2E7FtnV"; | |||
String contractAddress = "LdeNmSdtUqVfURfcVxmJda252HC4FYHYfGTQv"; | |||
AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); | |||
TransactionContentBody transactionContentBody = new TransactionContentBody() { | |||
@Override | |||
@@ -83,7 +83,10 @@ public class SDK_Contract_Test { | |||
}; | |||
// assetContract.issue(transactionContentBody,contractAddress); | |||
// assetContract.issue(transactionContentBody,contractAddress,888888); | |||
assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,999999); | |||
// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); | |||
// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); | |||
Byte byteObj = Byte.parseByte("127"); | |||
assetContract.issue(byteObj,contractAddress,321123); | |||
// TX 准备就绪; | |||
PreparedTransaction prepTx = txTemp.prepare(); | |||