@@ -0,0 +1,112 @@ | |||
package com.jd.blockchain.contract.jvm; | |||
import java.lang.reflect.Method; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.util.ReflectionUtils; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public abstract class AbstractContractCode implements ContractCode { | |||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractContractCode.class); | |||
private Bytes address; | |||
private long version; | |||
private ContractDefinition contractDefinition; | |||
public AbstractContractCode(Bytes address, long version, ContractDefinition contractDefinition) { | |||
this.address = address; | |||
this.version = version; | |||
this.contractDefinition = contractDefinition; | |||
} | |||
public ContractDefinition getContractDefinition() { | |||
return contractDefinition; | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
@Override | |||
public long getVersion() { | |||
return version; | |||
} | |||
@Override | |||
public byte[] processEvent(ContractEventContext eventContext) { | |||
EventProcessingAware evtProcAwire = null; | |||
Object retn = null; | |||
Exception error = null; | |||
try { | |||
// 执行预处理; | |||
Object contractInstance = getContractInstance(); | |||
if (contractInstance instanceof EventProcessingAware) { | |||
evtProcAwire = (EventProcessingAware) contractInstance; | |||
} | |||
if (evtProcAwire != null) { | |||
evtProcAwire.beforeEvent(eventContext); | |||
} | |||
// 反序列化参数; | |||
Method handleMethod = contractDefinition.getType().getHandleMethod(eventContext.getEvent()); | |||
if (handleMethod == null) { | |||
throw new ContractException( | |||
String.format("Contract[%s:%s] has no handle method to handle event[%s]!", address.toString(), | |||
contractDefinition.getType().getDeclaredClass().toString(), eventContext.getEvent())); | |||
} | |||
Object[] args = resolveArgs(); | |||
retn = ReflectionUtils.invokeMethod(handleMethod, contractInstance, args); | |||
} catch (Exception e) { | |||
error = e; | |||
} | |||
if (evtProcAwire != null) { | |||
try { | |||
evtProcAwire.postEvent(eventContext, error); | |||
} catch (Exception e) { | |||
String errorMessage = "Error occurred while posting contract event! --" + e.getMessage(); | |||
LOGGER.error(errorMessage, e); | |||
throw new ContractException(errorMessage, e); | |||
} | |||
} | |||
if (error != null) { | |||
// Rethrow error; | |||
throw new ContractException(String.format("Error occurred while processing event[%s] of contract[%s]! --%s", | |||
eventContext.getEvent(), address.toString(), error.getMessage()), error); | |||
} | |||
byte[] retnBytes = resolveResult(retn); | |||
return retnBytes; | |||
} | |||
protected abstract Object getContractInstance(); | |||
private byte[] resolveResult(Object retn) { | |||
if (retn == null) { | |||
return null; | |||
} | |||
// TODO: resolve result in bytes; | |||
throw new IllegalStateException("Not implemented!"); | |||
} | |||
private Object[] resolveArgs() { | |||
// TODO Auto-generated method stub | |||
throw new IllegalStateException("Not implemented!"); | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
package com.jd.blockchain.contract.jvm; | |||
import com.jd.blockchain.contract.ContractType; | |||
public class ContractDefinition { | |||
private ContractType type; | |||
private Class<?> mainClass; | |||
public Class<?> getMainClass() { | |||
return mainClass; | |||
} | |||
public ContractType getType() { | |||
return type; | |||
} | |||
public ContractDefinition(ContractType type, Class<?> mainClass) { | |||
this.type = type; | |||
this.mainClass = mainClass; | |||
} | |||
} |
@@ -2,7 +2,6 @@ package com.jd.blockchain.contract.jvm; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.contract.engine.ContractEngine; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.runtime.Module; | |||
import com.jd.blockchain.runtime.RuntimeContext; | |||
import com.jd.blockchain.utils.Bytes; | |||
@@ -1,46 +1,57 @@ | |||
package com.jd.blockchain.contract.jvm; | |||
import java.lang.reflect.Method; | |||
import java.util.concurrent.Callable; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.util.ReflectionUtils; | |||
import com.jd.blockchain.contract.Contract; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.EventProcessingAwire; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.runtime.Module; | |||
import com.jd.blockchain.transaction.ContractType; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* contract code based jvm | |||
* 基于 java jar 包并且以模块化方式独立加载的合约代码; | |||
* | |||
* @author zhaogw | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class JavaContractCode implements ContractCode { | |||
public class JavaContractCode extends AbstractContractCode { | |||
private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); | |||
private Module codeModule; | |||
private Bytes address; | |||
private long version; | |||
private Class<?> contractClass; | |||
private ContractType contractType; | |||
public JavaContractCode(Bytes address, long version, Module codeModule) { | |||
super(address, version, resolveContractDefinition(codeModule)); | |||
this.address = address; | |||
this.version = version; | |||
this.codeModule = codeModule; | |||
init(); | |||
} | |||
private void init() { | |||
String contractClassName = codeModule.getMainClass(); | |||
this.contractClass = codeModule.loadClass(contractClassName); | |||
this.contractType = ContractType.resolve(contractClass); | |||
protected static ContractDefinition resolveContractDefinition(Module codeModule) { | |||
String mainClassName = codeModule.getMainClass(); | |||
Class<?> mainClass = codeModule.loadClass(mainClassName); | |||
Class<?>[] interfaces = mainClass.getInterfaces(); | |||
Class<?> contractInterface = null; | |||
for (Class<?> itf : interfaces) { | |||
Contract annoContract = itf.getAnnotation(Contract.class); | |||
if (annoContract != null) { | |||
if (contractInterface == null) { | |||
contractInterface = itf; | |||
}else { | |||
throw new ContractException("One contract definition is only allowed to implement one contract type!"); | |||
} | |||
} | |||
} | |||
if (contractInterface == null) { | |||
throw new ContractException("No contract type is implemented!"); | |||
} | |||
ContractType type = ContractType.resolve(contractInterface); | |||
return new ContractDefinition(type, mainClass); | |||
} | |||
@Override | |||
@@ -58,8 +69,16 @@ public class JavaContractCode implements ContractCode { | |||
return codeModule.call(new ContractExecution(eventContext)); | |||
} | |||
private class ContractExecution implements Callable<byte[]> { | |||
protected Object getContractInstance() { | |||
try { | |||
// 每一次调用都通过反射创建合约的实例; | |||
return getContractDefinition().getMainClass().newInstance(); | |||
} catch (InstantiationException | IllegalAccessException e) { | |||
throw new IllegalStateException(e.getMessage(), e); | |||
} | |||
} | |||
private class ContractExecution implements Callable<byte[]> { | |||
private ContractEventContext eventContext; | |||
public ContractExecution(ContractEventContext contractEventContext) { | |||
@@ -68,63 +87,7 @@ public class JavaContractCode implements ContractCode { | |||
@Override | |||
public byte[] call() throws Exception { | |||
EventProcessingAwire evtProcAwire = null; | |||
Object retn = null; | |||
Exception error = null; | |||
try { | |||
// 执行预处理; | |||
Object contractInstance = contractClass.newInstance();// 合约主类生成的类实例; | |||
if (contractInstance instanceof EventProcessingAwire) { | |||
evtProcAwire = (EventProcessingAwire) contractInstance; | |||
} | |||
if (evtProcAwire != null) { | |||
evtProcAwire.beforeEvent(eventContext); | |||
} | |||
// 反序列化参数; | |||
Method handleMethod = contractType.getHandleMethod(eventContext.getEvent()); | |||
if (handleMethod == null) { | |||
throw new ContractException( | |||
String.format("Contract[%s:%s] has no handle method to handle event[%s]!", | |||
address.toString(), contractClass.getName(), eventContext.getEvent())); | |||
} | |||
Object[] args = resolveArgs(); | |||
retn = ReflectionUtils.invokeMethod(handleMethod, contractInstance, args); | |||
} catch (Exception e) { | |||
error = e; | |||
} | |||
if (evtProcAwire != null) { | |||
try { | |||
evtProcAwire.postEvent(eventContext, error); | |||
} catch (Exception e) { | |||
LOGGER.error("Error occurred while posting contract event! --" + e.getMessage(), e); | |||
} | |||
} | |||
if (error != null) { | |||
// Rethrow error; | |||
throw error; | |||
} | |||
byte[] retnBytes = resolveResult(retn); | |||
return retnBytes; | |||
} | |||
private byte[] resolveResult(Object retn) { | |||
if (retn == null) { | |||
return null; | |||
} | |||
// TODO: resolve result in bytes; | |||
return null; | |||
} | |||
private Object[] resolveArgs() { | |||
// TODO Auto-generated method stub | |||
throw new IllegalStateException("Not implemented!"); | |||
return JavaContractCode.super.processEvent(eventContext); | |||
} | |||
} | |||
@@ -8,7 +8,7 @@ import com.github.javaparser.ast.PackageDeclaration; | |||
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; | |||
import com.github.javaparser.ast.body.MethodDeclaration; | |||
import com.github.javaparser.ast.visitor.VoidVisitorAdapter; | |||
import com.jd.blockchain.transaction.ContractType; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.utils.IllegalDataException; | |||
import org.apache.maven.plugin.AbstractMojo; | |||
import org.apache.maven.plugin.MojoFailureException; | |||
@@ -4,7 +4,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
@Contract | |||
public class ReadContractImpl implements EventProcessingAwire, ReadContract { | |||
public class ReadContractImpl implements EventProcessingAware, ReadContract { | |||
private ContractEventContext eventContext; | |||
@@ -3,13 +3,9 @@ package com.jd.blockchain.ledger.core.impl; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import javax.annotation.PostConstruct; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.stereotype.Component; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.impl.handles.ContractCodeDeployOperationHandle; | |||
import com.jd.blockchain.ledger.core.impl.handles.ContractEventSendOperationHandle; | |||
@@ -2,8 +2,6 @@ package com.jd.blockchain.ledger.core.impl.handles; | |||
import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | |||
import java.util.concurrent.CompletableFuture; | |||
import org.springframework.stereotype.Service; | |||
import com.jd.blockchain.contract.LocalContractEventContext; | |||
@@ -1,82 +1,82 @@ | |||
//package test.com.jd.blockchain.ledger; | |||
// | |||
//import java.util.Map; | |||
//import java.util.concurrent.CompletableFuture; | |||
//import java.util.concurrent.ConcurrentHashMap; | |||
// | |||
//import com.jd.blockchain.contract.LocalContractEventContext; | |||
//import com.jd.blockchain.contract.engine.ContractCode; | |||
//import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
//import com.jd.blockchain.ledger.LedgerException; | |||
//import com.jd.blockchain.ledger.Operation; | |||
//import com.jd.blockchain.ledger.core.ContractAccount; | |||
//import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
//import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
//import com.jd.blockchain.ledger.core.LedgerService; | |||
//import com.jd.blockchain.ledger.core.OperationHandle; | |||
//import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
//import com.jd.blockchain.ledger.core.impl.LedgerQueryService; | |||
//import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | |||
//import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext; | |||
//import com.jd.blockchain.utils.Bytes; | |||
// | |||
//public class ContractInvokingHandle implements OperationHandle { | |||
// | |||
// private Map<Bytes, Object> contractInstances = new ConcurrentHashMap<Bytes, Object>(); | |||
// | |||
// @Override | |||
// public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, | |||
// LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | |||
// process(op, dataset, requestContext, previousBlockDataset, opHandleContext, ledgerService, null); | |||
// | |||
// // TODO: return value; | |||
// return null; | |||
// } | |||
// | |||
// @Override | |||
// public boolean support(Class<?> operationType) { | |||
// return ContractEventSendOperation.class.isAssignableFrom(operationType); | |||
// } | |||
// | |||
// public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, | |||
// LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService, | |||
// CompletableFuture<String> contractReturn) { | |||
// | |||
// ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | |||
// // 先从账本校验合约的有效性; | |||
// // 注意:必须在前一个区块的数据集中进行校验,因为那是经过共识的数据;从当前新区块链数据集校验则会带来攻击风险:未经共识的合约得到执行; | |||
// ContractAccountSet contractSet = previousBlockDataset.getContractAccountSet(); | |||
// if (!contractSet.contains(contractOP.getContractAddress())) { | |||
// throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", | |||
// contractOP.getContractAddress())); | |||
// } | |||
// | |||
// // 创建合约的账本上下文实例; | |||
// LedgerQueryService queryService = new LedgerQueryService(ledgerService); | |||
// ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext); | |||
// | |||
// // 先检查合约引擎是否已经加载合约;如果未加载,再从账本中读取合约代码并装载到引擎中执行; | |||
// ContractAccount contract = contractSet.getContract(contractOP.getContractAddress()); | |||
// if (contract == null) { | |||
// throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", | |||
// contractOP.getContractAddress())); | |||
// } | |||
// | |||
// // 创建合约上下文; | |||
// LocalContractEventContext localContractEventContext = new LocalContractEventContext( | |||
// requestContext.getRequest().getTransactionContent().getLedgerHash(), contractOP.getEvent()); | |||
// localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) | |||
// .setLedgerContext(ledgerContext); | |||
// | |||
// ContractCode contractCode = JVM_ENGINE.getContract(contract.getAddress(), contract.getChaincodeVersion()); | |||
// if (contractCode == null) { | |||
// // 装载合约; | |||
// contractCode = JVM_ENGINE.setupContract(contract.getAddress(), contract.getChaincodeVersion(), | |||
// contract.getChainCode()); | |||
// } | |||
// | |||
// // 处理合约事件; | |||
// contractCode.processEvent(localContractEventContext, contractReturn); | |||
// } | |||
// | |||
//} | |||
package test.com.jd.blockchain.ledger; | |||
import java.util.Map; | |||
import java.util.concurrent.CompletableFuture; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import com.jd.blockchain.contract.LocalContractEventContext; | |||
import com.jd.blockchain.contract.engine.ContractCode; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.core.ContractAccount; | |||
import com.jd.blockchain.ledger.core.ContractAccountSet; | |||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
import com.jd.blockchain.ledger.core.LedgerService; | |||
import com.jd.blockchain.ledger.core.OperationHandle; | |||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||
import com.jd.blockchain.ledger.core.impl.LedgerQueryService; | |||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | |||
import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractInvokingHandle implements OperationHandle { | |||
private Map<Bytes, Object> contractInstances = new ConcurrentHashMap<Bytes, Object>(); | |||
@Override | |||
public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, | |||
LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { | |||
process(op, dataset, requestContext, previousBlockDataset, opHandleContext, ledgerService, null); | |||
// TODO: return value; | |||
return null; | |||
} | |||
@Override | |||
public boolean support(Class<?> operationType) { | |||
return ContractEventSendOperation.class.isAssignableFrom(operationType); | |||
} | |||
public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, | |||
LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService, | |||
CompletableFuture<String> contractReturn) { | |||
ContractEventSendOperation contractOP = (ContractEventSendOperation) op; | |||
// 先从账本校验合约的有效性; | |||
// 注意:必须在前一个区块的数据集中进行校验,因为那是经过共识的数据;从当前新区块链数据集校验则会带来攻击风险:未经共识的合约得到执行; | |||
ContractAccountSet contractSet = previousBlockDataset.getContractAccountSet(); | |||
if (!contractSet.contains(contractOP.getContractAddress())) { | |||
throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", | |||
contractOP.getContractAddress())); | |||
} | |||
// 创建合约的账本上下文实例; | |||
LedgerQueryService queryService = new LedgerQueryService(ledgerService); | |||
ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext); | |||
// 先检查合约引擎是否已经加载合约;如果未加载,再从账本中读取合约代码并装载到引擎中执行; | |||
ContractAccount contract = contractSet.getContract(contractOP.getContractAddress()); | |||
if (contract == null) { | |||
throw new LedgerException(String.format("Contract was not registered! --[ContractAddress=%s]", | |||
contractOP.getContractAddress())); | |||
} | |||
// 创建合约上下文; | |||
LocalContractEventContext localContractEventContext = new LocalContractEventContext( | |||
requestContext.getRequest().getTransactionContent().getLedgerHash(), contractOP.getEvent()); | |||
localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) | |||
.setLedgerContext(ledgerContext); | |||
ContractCode contractCode = JVM_ENGINE.getContract(contract.getAddress(), contract.getChaincodeVersion()); | |||
if (contractCode == null) { | |||
// 装载合约; | |||
contractCode = JVM_ENGINE.setupContract(contract.getAddress(), contract.getChaincodeVersion(), | |||
contract.getChainCode()); | |||
} | |||
// 处理合约事件; | |||
contractCode.processEvent(localContractEventContext, contractReturn); | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
package test.com.jd.blockchain.ledger; | |||
public interface TestContractImpl { | |||
/** | |||
* 发行资产; | |||
* | |||
* @param asset 资产代码; | |||
* @param amount 本次发行的资产数量; | |||
* @return 资产总量; | |||
*/ | |||
long issue(String asset, long amount); | |||
/** | |||
* 获取资产总量; | |||
* | |||
* @param asset | |||
* @return | |||
*/ | |||
long getAmount(String asset); | |||
/** | |||
* 获取资产余额; | |||
* | |||
* @param address | |||
* @param asset | |||
* @return | |||
*/ | |||
long getBalance(String address, String asset); | |||
/** | |||
* 向账户分配资产; | |||
* | |||
* @param address | |||
* @param asset | |||
* @param amount | |||
*/ | |||
void assign(String address, String asset, int amount); | |||
/** | |||
* 转移资产; | |||
* | |||
* @param fromAddress | |||
* @param toAddress | |||
* @param asset | |||
* @param amount | |||
*/ | |||
void transfer(String fromAddress, String toAddress, String asset, long amount); | |||
} |
@@ -0,0 +1,11 @@ | |||
package com.jd.blockchain.contract; | |||
/** | |||
* 合约实现 {@link ContractAware} 的子接口可以监听运行时的生命周期事件; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface ContractAware { | |||
} |
@@ -1,18 +1,17 @@ | |||
package com.jd.blockchain.contract; | |||
public class ContractException extends RuntimeException { | |||
private static final long serialVersionUID = 4338023105616639257L; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
public class ContractException extends LedgerException { | |||
private static final long serialVersionUID = -4643365435848655115L; | |||
public ContractException(String message) { | |||
super(message); | |||
} | |||
public ContractException(String message,ErrorCodeEnum errorCodeEnum) { | |||
super(message+","+errorCodeEnum.toString()); | |||
public ContractException(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
public ContractException(ErrorCodeEnum errorCodeEnum) { | |||
super(errorCodeEnum.toString()); | |||
} | |||
} |
@@ -7,7 +7,7 @@ package com.jd.blockchain.contract; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface ContractAppLifecycleAwire extends ContractRuntimeAwire { | |||
public interface ContractLifecycleAware extends ContractAware { | |||
void postConstruct(); | |||
@@ -1,11 +0,0 @@ | |||
package com.jd.blockchain.contract; | |||
/** | |||
* 合约实现 {@link ContractRuntimeAwire} 的子接口可以监听运行时的生命周期事件; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface ContractRuntimeAwire { | |||
} |
@@ -1,4 +1,4 @@ | |||
package com.jd.blockchain.transaction; | |||
package com.jd.blockchain.contract; | |||
import java.lang.annotation.Annotation; | |||
import java.lang.reflect.Method; | |||
@@ -8,9 +8,6 @@ import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import com.jd.blockchain.contract.Contract; | |||
import com.jd.blockchain.contract.ContractEvent; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.utils.IllegalDataException; | |||
public class ContractType { | |||
@@ -18,7 +15,16 @@ public class ContractType { | |||
private String name; | |||
private Map<String, Method> events = new HashMap<>(); | |||
private Map<Method, String> handleMethods = new HashMap<>(); | |||
// private Map<Method, List<DataContract>> dataContractMap = new HashMap<>(); | |||
private Class<?> declaredClass; | |||
public String getName() { | |||
return name; | |||
} | |||
public Class<?> getDeclaredClass() { | |||
return declaredClass; | |||
} | |||
/** | |||
* 返回声明的所有事件; | |||
@@ -29,10 +35,6 @@ public class ContractType { | |||
return events.keySet(); | |||
} | |||
// public Map<Method, List<DataContract>> getDataContractMap() { | |||
// return dataContractMap; | |||
// } | |||
/** | |||
* 返回指定方法声明的事件;<br> | |||
* | |||
@@ -60,32 +62,39 @@ public class ContractType { | |||
private ContractType() { | |||
} | |||
public static ContractType resolve(Class<?> contractIntf){ | |||
/** | |||
* 解析合约的声明; | |||
* | |||
* @param contractDelaredInterface 声明合约的接口类型; | |||
* @return | |||
*/ | |||
public static ContractType resolve(Class<?> contractDelaredInterface) { | |||
ContractType contractType = new ContractType(); | |||
Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class); | |||
Annotation annotation = contractDelaredInterface.getDeclaredAnnotation(Contract.class); | |||
//contains: @Contract? | |||
// contains: @Contract? | |||
boolean isContractType = annotation != null ? true : false; | |||
if(!isContractType){ | |||
if (!isContractType) { | |||
throw new IllegalDataException("is not Contract Type, becaust there is not @Contract."); | |||
} | |||
//contractIntf contains @Contract and @ContractEvent; | |||
Method[] classMethods = contractIntf.getDeclaredMethods(); | |||
// contractIntf contains @Contract and @ContractEvent; | |||
Method[] classMethods = contractDelaredInterface.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_)){ | |||
// 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. | |||
// check param's type is fit for need. | |||
Class<?>[] paramTypes = method.getParameterTypes(); | |||
List dataContractList = new ArrayList(); | |||
for(Class<?> curParamType : paramTypes){ | |||
for (Class<?> curParamType : paramTypes) { | |||
throw new IllegalStateException("Not implemented!"); | |||
// DataContract dataContract = ContractSerializeUtils.parseDataContract(curParamType); | |||
// dataContractList.add(dataContract); | |||
@@ -95,18 +104,9 @@ public class ContractType { | |||
// } | |||
contractType.events.put(eventName_, method); | |||
contractType.handleMethods.put(method,eventName_); | |||
contractType.handleMethods.put(method, eventName_); | |||
} | |||
} | |||
return contractType; | |||
} | |||
@Override | |||
public String toString() { | |||
return "ContractType{" + | |||
"name='" + name + '\'' + | |||
", events=" + events + | |||
", handleMethods=" + handleMethods + | |||
'}'; | |||
} | |||
} |
@@ -1,52 +0,0 @@ | |||
package com.jd.blockchain.contract; | |||
/** | |||
* 给每个错误编码,编译快速定位; | |||
* @Author zhaogw | |||
* @Date 2018/11/8 15:32 | |||
*/ | |||
public enum ErrorCodeEnum { | |||
//<100为致命错误; | |||
GATEWAY_CONNECT_ERROR(1,ErrorType.ERROR,"GatewayServiceFactory connect error.!"), | |||
CONTRACT_CLASSPATH_NOT_SET(2,ErrorType.ERROR,"in private contract classLoader,no jar in the contract folder!"), | |||
//其它错误从101开始计数; | |||
AMOUNT_NEGATIVE(101,ErrorType.ALARM,"The amount is negative!"); | |||
private int code; | |||
private int type; | |||
private String message; | |||
ErrorCodeEnum(int code, int type, String message) { | |||
this.code = code; | |||
this.type = type; | |||
this.message = message; | |||
} | |||
public int getCode() { | |||
return code; | |||
} | |||
public int getType() { | |||
return type; | |||
} | |||
public String getMessage() { | |||
return message; | |||
} | |||
@Override | |||
public String toString(){ | |||
return "code:"+code+", type:"+type+", message:"+message; | |||
} | |||
} | |||
/** | |||
* 给错误分个类,便于汇总; | |||
*/ | |||
class ErrorType { | |||
public static final int ALARM = 0; | |||
public static final int ERROR = 1; | |||
public static final int CONTRACT_EXE = 2; | |||
public static final int CONTRACT_COMPILE = 3; | |||
} | |||
@@ -4,7 +4,7 @@ package com.jd.blockchain.contract; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface EventProcessingAwire extends ContractRuntimeAwire { | |||
public interface EventProcessingAware extends ContractAware { | |||
/** | |||
* 在事件处理方法执行之前调用; |
@@ -13,17 +13,14 @@ import com.jd.blockchain.ledger.TransactionRequest; | |||
public class LocalContractEventContext implements ContractEventContext,Cloneable { | |||
private HashDigest ledgeHash; | |||
private String event; | |||
private byte[] chainCode; | |||
private byte[] args; | |||
private TransactionRequest transactionRequest; | |||
private Set<BlockchainIdentity> txSigners; | |||
private Set<BlockchainIdentity> contractOwners; | |||
private LedgerContext ledgerContext; | |||
public LocalContractEventContext(HashDigest ledgeHash, String event){ | |||
this.ledgeHash = ledgeHash; | |||
this.event = event; | |||
// this.chainCode = chainCode; | |||
} | |||
@Override | |||
@@ -81,11 +78,6 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable | |||
return this; | |||
} | |||
public LocalContractEventContext setContractOwners(Set<BlockchainIdentity> contractOwners) { | |||
this.contractOwners = contractOwners; | |||
return this; | |||
} | |||
public LocalContractEventContext setLedgerContext(LedgerContext ledgerContext) { | |||
this.ledgerContext = ledgerContext; | |||
return this; | |||
@@ -3,6 +3,7 @@ package com.jd.blockchain.transaction; | |||
import java.lang.reflect.InvocationHandler; | |||
import java.lang.reflect.Method; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.IllegalDataException; | |||
@@ -6,6 +6,7 @@ import java.util.Map; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import com.jd.blockchain.contract.Contract; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractInvocationProxyBuilder { | |||
@@ -0,0 +1,59 @@ | |||
package test.com.jd.blockchain.ledger.data; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertTrue; | |||
import java.lang.reflect.Method; | |||
import java.util.Set; | |||
import org.junit.Test; | |||
import com.jd.blockchain.contract.ContractType; | |||
public class ContractTypeTest { | |||
/** | |||
* 正常测试; | |||
* @throws SecurityException | |||
* @throws NoSuchMethodException | |||
*/ | |||
@Test | |||
public void normalTest() throws NoSuchMethodException, SecurityException { | |||
ContractType contractType = ContractType.resolve(NormalContract.class); | |||
assertEquals(NormalContract.class, contractType.getDeclaredClass()); | |||
assertEquals("NORMAL-CONTRACT", contractType.getName()); | |||
Set<String> events = contractType.getEvents(); | |||
assertEquals(5, events.size()); | |||
assertTrue(events.contains("issue")); | |||
assertTrue(events.contains("get_amount")); | |||
assertTrue(events.contains("get_balance")); | |||
assertTrue(events.contains("assign")); | |||
assertTrue(events.contains("transfer")); | |||
Method issueMethod = contractType.getHandleMethod("issue"); | |||
assertNotNull(issueMethod); | |||
Method getAmountMethod = contractType.getHandleMethod("get_amount"); | |||
assertNotNull(getAmountMethod); | |||
Method getBalanceMethod = contractType.getHandleMethod("get_balance"); | |||
assertNotNull(getBalanceMethod); | |||
Method assignMethod = contractType.getHandleMethod("assign"); | |||
assertNotNull(assignMethod); | |||
Method transferMethod = contractType.getHandleMethod("transfer"); | |||
assertNotNull(transferMethod); | |||
assertEquals("issue", contractType.getEvent(issueMethod)); | |||
assertEquals("get_amount", contractType.getEvent(getAmountMethod)); | |||
assertEquals("get_balance", contractType.getEvent(getBalanceMethod)); | |||
assertEquals("assign", contractType.getEvent(assignMethod)); | |||
assertEquals("transfer", contractType.getEvent(transferMethod)); | |||
Method toStringMethod = NormalContractImpl.class.getMethod("toString"); | |||
assertNull(contractType.getEvent(toStringMethod)); | |||
assertNull(contractType.getHandleMethod("NotExist")); | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
package test.com.jd.blockchain.ledger.data; | |||
import com.jd.blockchain.contract.Contract; | |||
import com.jd.blockchain.contract.ContractEvent; | |||
@Contract(name="NORMAL-CONTRACT") | |||
public interface NormalContract { | |||
/** | |||
* 发行资产; | |||
* | |||
* @param asset 资产代码; | |||
* @param amount 本次发行的资产数量; | |||
* @return 资产总量; | |||
*/ | |||
@ContractEvent(name="issue") | |||
long issue(String asset, long amount); | |||
/** | |||
* 获取资产总量; | |||
* | |||
* @param asset | |||
* @return | |||
*/ | |||
@ContractEvent(name="get_amount") | |||
long getAmount(String asset); | |||
/** | |||
* 获取资产余额; | |||
* | |||
* @param address | |||
* @param asset | |||
* @return | |||
*/ | |||
@ContractEvent(name="get_balance") | |||
long getBalance(String address, String asset); | |||
/** | |||
* 向账户分配资产; | |||
* | |||
* @param address | |||
* @param asset | |||
* @param amount | |||
*/ | |||
@ContractEvent(name="assign") | |||
void assign(String address, String asset, int amount); | |||
/** | |||
* 转移资产; | |||
* | |||
* @param fromAddress | |||
* @param toAddress | |||
* @param asset | |||
* @param amount | |||
*/ | |||
@ContractEvent(name="transfer") | |||
void transfer(String fromAddress, String toAddress, String asset, long amount); | |||
} |
@@ -0,0 +1,35 @@ | |||
package test.com.jd.blockchain.ledger.data; | |||
public class NormalContractImpl implements NormalContract{ | |||
@Override | |||
public long issue(String asset, long amount) { | |||
// TODO Auto-generated method stub | |||
return 0; | |||
} | |||
@Override | |||
public long getAmount(String asset) { | |||
// TODO Auto-generated method stub | |||
return 0; | |||
} | |||
@Override | |||
public long getBalance(String address, String asset) { | |||
// TODO Auto-generated method stub | |||
return 0; | |||
} | |||
@Override | |||
public void assign(String address, String asset, int amount) { | |||
// TODO Auto-generated method stub | |||
} | |||
@Override | |||
public void transfer(String fromAddress, String toAddress, String asset, long amount) { | |||
// TODO Auto-generated method stub | |||
} | |||
} |
@@ -131,17 +131,17 @@ public abstract class RuntimeContext { | |||
private ClassLoader moduleClassLoader; | |||
private String MainClass; | |||
private String mainClass; | |||
public DefaultModule(String name, ClassLoader cl, String mainClass) { | |||
this.name = name; | |||
this.moduleClassLoader = cl; | |||
this.MainClass = mainClass; | |||
this.mainClass = mainClass; | |||
} | |||
@Override | |||
public String getMainClass() { | |||
return MainClass; | |||
return mainClass; | |||
} | |||
@@ -6,7 +6,7 @@ import java.util.Set; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.EventProcessingAwire; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
@@ -21,7 +21,7 @@ import com.jd.blockchain.ledger.KVDataObject; | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class AssetContractImpl implements EventProcessingAwire, AssetContract { | |||
public class AssetContractImpl implements EventProcessingAware, AssetContract { | |||
// 资产管理账户的地址; | |||
private static final String ASSET_ADDRESS = "2njZBNbFQcmKd385DxVejwSjy4driRzf9Pk"; | |||
// 保存资产总数的键; | |||
@@ -2,11 +2,11 @@ package com.jd.blockchain.mocker.contracts; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.EventProcessingAwire; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.KVDataEntry; | |||
public class AccountContractImpl implements EventProcessingAwire, AccountContract { | |||
public class AccountContractImpl implements EventProcessingAware, AccountContract { | |||
private ContractEventContext eventContext; | |||
@@ -2,9 +2,9 @@ package com.jd.blockchain.mocker.contracts; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.EventProcessingAwire; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
public class WriteContractImpl implements EventProcessingAwire, WriteContract { | |||
public class WriteContractImpl implements EventProcessingAware, WriteContract { | |||
private ContractEventContext eventContext; | |||
@@ -2,7 +2,7 @@ package com.jd.blockchain.mocker.handler; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.ContractException; | |||
import com.jd.blockchain.contract.EventProcessingAwire; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import com.jd.blockchain.contract.LedgerContext; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
@@ -44,7 +44,7 @@ public class MockerContractExeHandle implements OperationHandle { | |||
MockerContractEventContext contractEventContext = new MockerContractEventContext(ledgerHash, | |||
contractOP.getEvent(), requestContext.getRequest(), ledgerContext); | |||
EventProcessingAwire eventProcessingAwire = (EventProcessingAwire) executorProxy.getInstance(); | |||
EventProcessingAware eventProcessingAwire = (EventProcessingAware) executorProxy.getInstance(); | |||
try { | |||
// | |||
// Before处理过程 | |||