@@ -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; | |||||
} | |||||
} |
@@ -1,47 +1,57 @@ | |||||
package com.jd.blockchain.contract.jvm; | package com.jd.blockchain.contract.jvm; | ||||
import java.lang.reflect.Method; | |||||
import java.util.concurrent.Callable; | import java.util.concurrent.Callable; | ||||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | 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.ContractEventContext; | ||||
import com.jd.blockchain.contract.ContractException; | 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.runtime.Module; | ||||
import com.jd.blockchain.transaction.ContractType; | |||||
import com.jd.blockchain.utils.Bytes; | 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 static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); | ||||
private Module codeModule; | private Module codeModule; | ||||
private Bytes address; | private Bytes address; | ||||
private long version; | private long version; | ||||
private Class<?> contractClass; | |||||
private ContractType contractType; | |||||
public JavaContractCode(Bytes address, long version, Module codeModule) { | public JavaContractCode(Bytes address, long version, Module codeModule) { | ||||
super(address, version, resolveContractDefinition(codeModule)); | |||||
this.address = address; | this.address = address; | ||||
this.version = version; | this.version = version; | ||||
this.codeModule = codeModule; | 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 | @Override | ||||
@@ -56,11 +66,32 @@ public class JavaContractCode implements ContractCode { | |||||
@Override | @Override | ||||
public byte[] processEvent(ContractEventContext eventContext) { | public byte[] processEvent(ContractEventContext eventContext) { | ||||
return codeModule.call(new ContractExecution(eventContext)); | |||||
if (LOGGER.isDebugEnabled()) { | |||||
LOGGER.debug("Start processing event[%s] of contract[%s]...", eventContext.getEvent(), address.toString()); | |||||
} | |||||
try { | |||||
return codeModule.call(new ContractExecution(eventContext)); | |||||
} catch (Exception ex) { | |||||
LOGGER.error(String.format("Error occurred while processing event[%s] of contract[%s]! --%s", | |||||
eventContext.getEvent(), address.toString(), ex.getMessage()), ex); | |||||
throw ex; | |||||
} finally { | |||||
if (LOGGER.isDebugEnabled()) { | |||||
LOGGER.debug("End processing event[%s] of contract[%s]. ", eventContext.getEvent(), address.toString()); | |||||
} | |||||
} | |||||
} | } | ||||
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; | private ContractEventContext eventContext; | ||||
public ContractExecution(ContractEventContext contractEventContext) { | public ContractExecution(ContractEventContext contractEventContext) { | ||||
@@ -69,57 +100,7 @@ public class JavaContractCode implements ContractCode { | |||||
@Override | @Override | ||||
public byte[] call() throws Exception { | 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(eventContext.getArgs()); | |||||
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) { | |||||
return ContractSerializeUtils.serialize(retn); | |||||
} | |||||
private Object[] resolveArgs(byte[] argBytes) { | |||||
return ContractSerializeUtils.resolveArray(argBytes); | |||||
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.ClassOrInterfaceDeclaration; | ||||
import com.github.javaparser.ast.body.MethodDeclaration; | import com.github.javaparser.ast.body.MethodDeclaration; | ||||
import com.github.javaparser.ast.visitor.VoidVisitorAdapter; | 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 com.jd.blockchain.utils.IllegalDataException; | ||||
import org.apache.maven.plugin.AbstractMojo; | import org.apache.maven.plugin.AbstractMojo; | ||||
import org.apache.maven.plugin.MojoFailureException; | import org.apache.maven.plugin.MojoFailureException; | ||||
@@ -4,7 +4,7 @@ import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | import com.jd.blockchain.ledger.KVDataEntry; | ||||
@Contract | @Contract | ||||
public class ReadContractImpl implements EventProcessingAwire, ReadContract { | |||||
public class ReadContractImpl implements EventProcessingAware, ReadContract { | |||||
private ContractEventContext eventContext; | private ContractEventContext eventContext; | ||||
@@ -33,22 +33,22 @@ public interface OperationHandle { | |||||
byte[] process(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, | byte[] process(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, | ||||
LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | ||||
/** | |||||
* 异步解析和执行操作; | |||||
* TODO 未来规划实现 | |||||
* | |||||
* | |||||
* @param op | |||||
* 操作实例; | |||||
* @param newBlockDataset | |||||
* 需要修改的新区块的数据集; | |||||
* @param requestContext | |||||
* 交易请求上下文; | |||||
* @param previousBlockDataset | |||||
* 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||||
* | |||||
* @return 操作执行结果 | |||||
*/ | |||||
AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, | |||||
LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | |||||
// /** | |||||
// * 异步解析和执行操作; | |||||
// * TODO 未来规划实现 | |||||
// * | |||||
// * | |||||
// * @param op | |||||
// * 操作实例; | |||||
// * @param newBlockDataset | |||||
// * 需要修改的新区块的数据集; | |||||
// * @param requestContext | |||||
// * 交易请求上下文; | |||||
// * @param previousBlockDataset | |||||
// * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||||
// * | |||||
// * @return 操作执行结果 | |||||
// */ | |||||
// AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, | |||||
// LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); | |||||
} | } |
@@ -3,16 +3,12 @@ package com.jd.blockchain.ledger.core.impl; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import javax.annotation.PostConstruct; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import com.jd.blockchain.ledger.LedgerException; | 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.OperationHandle; | ||||
import com.jd.blockchain.ledger.core.impl.handles.ContractCodeDeployOperationHandle; | import com.jd.blockchain.ledger.core.impl.handles.ContractCodeDeployOperationHandle; | ||||
import com.jd.blockchain.ledger.core.impl.handles.ContractEventSendOperationHandle; | |||||
import com.jd.blockchain.ledger.core.impl.handles.JVMContractEventSendOperationHandle; | |||||
import com.jd.blockchain.ledger.core.impl.handles.DataAccountKVSetOperationHandle; | import com.jd.blockchain.ledger.core.impl.handles.DataAccountKVSetOperationHandle; | ||||
import com.jd.blockchain.ledger.core.impl.handles.DataAccountRegisterOperationHandle; | import com.jd.blockchain.ledger.core.impl.handles.DataAccountRegisterOperationHandle; | ||||
import com.jd.blockchain.ledger.core.impl.handles.UserRegisterOperationHandle; | import com.jd.blockchain.ledger.core.impl.handles.UserRegisterOperationHandle; | ||||
@@ -34,7 +30,7 @@ public class DefaultOperationHandleRegisteration implements OperationHandleRegis | |||||
opHandles.add(new DataAccountRegisterOperationHandle()); | opHandles.add(new DataAccountRegisterOperationHandle()); | ||||
opHandles.add(new UserRegisterOperationHandle()); | opHandles.add(new UserRegisterOperationHandle()); | ||||
opHandles.add(new ContractCodeDeployOperationHandle()); | opHandles.add(new ContractCodeDeployOperationHandle()); | ||||
opHandles.add(new ContractEventSendOperationHandle()); | |||||
opHandles.add(new JVMContractEventSendOperationHandle()); | |||||
} | } | ||||
/** | /** | ||||
@@ -2,8 +2,6 @@ package com.jd.blockchain.ledger.core.impl.handles; | |||||
import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | ||||
import com.jd.blockchain.utils.concurrent.AsyncFuture; | |||||
import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
import com.jd.blockchain.contract.LocalContractEventContext; | import com.jd.blockchain.contract.LocalContractEventContext; | ||||
@@ -23,13 +21,7 @@ import com.jd.blockchain.ledger.core.impl.LedgerQueryService; | |||||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | ||||
@Service | @Service | ||||
public class ContractEventSendOperationHandle implements OperationHandle { | |||||
private static final ContractEngine JVM_ENGINE; | |||||
static { | |||||
JVM_ENGINE = ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine(); | |||||
} | |||||
public abstract class AbtractContractEventHandle implements OperationHandle { | |||||
@Override | @Override | ||||
public boolean support(Class<?> operationType) { | public boolean support(Class<?> operationType) { | ||||
@@ -65,20 +57,15 @@ public class ContractEventSendOperationHandle implements OperationHandle { | |||||
localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) | localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) | ||||
.setLedgerContext(ledgerContext); | .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 contractCode = loadContractCode(contract); | |||||
// 处理合约事件; | // 处理合约事件; | ||||
return contractCode.processEvent(localContractEventContext); | return contractCode.processEvent(localContractEventContext); | ||||
} | } | ||||
protected abstract ContractCode loadContractCode(ContractAccount contract); | |||||
@Override | |||||
public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
return null; | |||||
} | |||||
} | } |
@@ -32,10 +32,10 @@ public class ContractCodeDeployOperationHandle implements OperationHandle { | |||||
return null; | return null; | ||||
} | } | ||||
@Override | |||||
public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
return null; | |||||
} | |||||
// @Override | |||||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
// return null; | |||||
// } | |||||
@Override | @Override | ||||
public boolean support(Class<?> operationType) { | public boolean support(Class<?> operationType) { | ||||
@@ -36,10 +36,10 @@ public class DataAccountKVSetOperationHandle implements OperationHandle { | |||||
return null; | return null; | ||||
} | } | ||||
@Override | |||||
public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
return null; | |||||
} | |||||
// @Override | |||||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
// return null; | |||||
// } | |||||
@Override | @Override | ||||
public boolean support(Class<?> operationType) { | public boolean support(Class<?> operationType) { | ||||
@@ -29,10 +29,10 @@ public class DataAccountRegisterOperationHandle implements OperationHandle { | |||||
return null; | return null; | ||||
} | } | ||||
@Override | |||||
public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
return null; | |||||
} | |||||
// @Override | |||||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
// return null; | |||||
// } | |||||
@Override | @Override | ||||
public boolean support(Class<?> operationType) { | public boolean support(Class<?> operationType) { | ||||
@@ -0,0 +1,43 @@ | |||||
package com.jd.blockchain.ledger.core.impl.handles; | |||||
import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; | |||||
import com.jd.blockchain.contract.engine.ContractCode; | |||||
import com.jd.blockchain.contract.engine.ContractEngine; | |||||
import com.jd.blockchain.contract.engine.ContractServiceProviders; | |||||
import com.jd.blockchain.ledger.Operation; | |||||
import com.jd.blockchain.ledger.core.ContractAccount; | |||||
import com.jd.blockchain.ledger.core.LedgerDataSet; | |||||
import com.jd.blockchain.ledger.core.LedgerService; | |||||
import com.jd.blockchain.ledger.core.TransactionRequestContext; | |||||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | |||||
import com.jd.blockchain.utils.concurrent.AsyncFuture; | |||||
public class JVMContractEventSendOperationHandle extends AbtractContractEventHandle { | |||||
private static final ContractEngine JVM_ENGINE; | |||||
static { | |||||
JVM_ENGINE = ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine(); | |||||
} | |||||
@Override | |||||
protected ContractCode loadContractCode(ContractAccount contract) { | |||||
ContractCode contractCode = JVM_ENGINE.getContract(contract.getAddress(), contract.getChaincodeVersion()); | |||||
if (contractCode == null) { | |||||
// 装载合约; | |||||
contractCode = JVM_ENGINE.setupContract(contract.getAddress(), contract.getChaincodeVersion(), | |||||
contract.getChainCode()); | |||||
} | |||||
return contractCode; | |||||
} | |||||
// @Override | |||||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, | |||||
// TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, | |||||
// OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
// // TODO Auto-generated method stub | |||||
// return null; | |||||
// } | |||||
} |
@@ -29,10 +29,10 @@ public class UserRegisterOperationHandle implements OperationHandle { | |||||
return userAddress.toBytes(); | return userAddress.toBytes(); | ||||
} | } | ||||
@Override | |||||
public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
return null; | |||||
} | |||||
// @Override | |||||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
// return null; | |||||
// } | |||||
@Override | @Override | ||||
public boolean support(Class<?> operationType) { | public boolean support(Class<?> operationType) { | ||||
@@ -1,82 +1,50 @@ | |||||
//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.ConcurrentHashMap; | |||||
import com.jd.blockchain.contract.ContractType; | |||||
import com.jd.blockchain.contract.engine.ContractCode; | |||||
import com.jd.blockchain.contract.jvm.AbstractContractCode; | |||||
import com.jd.blockchain.contract.jvm.ContractDefinition; | |||||
import com.jd.blockchain.ledger.core.ContractAccount; | |||||
import com.jd.blockchain.ledger.core.impl.handles.AbtractContractEventHandle; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
public class ContractInvokingHandle extends AbtractContractEventHandle { | |||||
private Map<Bytes, ContractCode> contractInstances = new ConcurrentHashMap<Bytes, ContractCode>(); | |||||
@Override | |||||
protected ContractCode loadContractCode(ContractAccount contract) { | |||||
return contractInstances.get(contract.getAddress()); | |||||
} | |||||
public <T> ContractCode setup(Bytes address, Class<T> contractIntf, T instance) { | |||||
ContractCodeInstance<T> contract = new ContractCodeInstance<T>(address, 0, contractIntf, instance); | |||||
contractInstances.put(address, contract); | |||||
return contract; | |||||
} | |||||
private static class ContractCodeInstance<T> extends AbstractContractCode { | |||||
private T instance; | |||||
public ContractCodeInstance(Bytes address, long version, Class<T> delaredInterface, T instance) { | |||||
super(address, version, resolveContractDefinition(delaredInterface, instance.getClass())); | |||||
this.instance = instance; | |||||
} | |||||
private static ContractDefinition resolveContractDefinition(Class<?> declaredIntf, Class<?> implementedClass) { | |||||
ContractType contractType = ContractType.resolve(declaredIntf); | |||||
return new ContractDefinition(contractType, implementedClass); | |||||
} | |||||
@Override | |||||
protected T getContractInstance() { | |||||
return instance; | |||||
} | |||||
} | |||||
} |
@@ -1,21 +1,37 @@ | |||||
package test.com.jd.blockchain.ledger; | package test.com.jd.blockchain.ledger; | ||||
import static org.junit.Assert.*; | |||||
import static org.junit.Assert.assertArrayEquals; | |||||
import static org.junit.Assert.assertEquals; | |||||
import static org.junit.Assert.assertNotNull; | |||||
import static org.junit.Assert.assertNull; | |||||
import static org.mockito.Matchers.anyLong; | |||||
import static org.mockito.Matchers.anyString; | |||||
import static org.mockito.Mockito.times; | |||||
import static org.mockito.Mockito.verify; | |||||
import static org.mockito.Mockito.when; | |||||
import java.util.Random; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.mockito.Mockito; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | import com.jd.blockchain.binaryproto.DataContractRegistry; | ||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | import com.jd.blockchain.ledger.BlockchainKeyGenerator; | ||||
import com.jd.blockchain.ledger.BlockchainKeypair; | import com.jd.blockchain.ledger.BlockchainKeypair; | ||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.BytesValueEntry; | |||||
import com.jd.blockchain.ledger.EndpointRequest; | import com.jd.blockchain.ledger.EndpointRequest; | ||||
import com.jd.blockchain.ledger.LedgerBlock; | import com.jd.blockchain.ledger.LedgerBlock; | ||||
import com.jd.blockchain.ledger.LedgerInitSetting; | import com.jd.blockchain.ledger.LedgerInitSetting; | ||||
import com.jd.blockchain.ledger.LedgerTransaction; | import com.jd.blockchain.ledger.LedgerTransaction; | ||||
import com.jd.blockchain.ledger.NodeRequest; | import com.jd.blockchain.ledger.NodeRequest; | ||||
import com.jd.blockchain.ledger.OperationResult; | |||||
import com.jd.blockchain.ledger.TransactionContent; | import com.jd.blockchain.ledger.TransactionContent; | ||||
import com.jd.blockchain.ledger.TransactionContentBody; | import com.jd.blockchain.ledger.TransactionContentBody; | ||||
import com.jd.blockchain.ledger.TransactionRequest; | import com.jd.blockchain.ledger.TransactionRequest; | ||||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||||
import com.jd.blockchain.ledger.TransactionResponse; | import com.jd.blockchain.ledger.TransactionResponse; | ||||
import com.jd.blockchain.ledger.TransactionState; | import com.jd.blockchain.ledger.TransactionState; | ||||
import com.jd.blockchain.ledger.UserRegisterOperation; | import com.jd.blockchain.ledger.UserRegisterOperation; | ||||
@@ -27,9 +43,11 @@ import com.jd.blockchain.ledger.core.UserAccount; | |||||
import com.jd.blockchain.ledger.core.impl.DefaultOperationHandleRegisteration; | import com.jd.blockchain.ledger.core.impl.DefaultOperationHandleRegisteration; | ||||
import com.jd.blockchain.ledger.core.impl.LedgerManager; | import com.jd.blockchain.ledger.core.impl.LedgerManager; | ||||
import com.jd.blockchain.ledger.core.impl.LedgerTransactionalEditor; | import com.jd.blockchain.ledger.core.impl.LedgerTransactionalEditor; | ||||
import com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration; | |||||
import com.jd.blockchain.ledger.core.impl.TransactionBatchProcessor; | |||||
import com.jd.blockchain.service.TransactionBatchResultHandle; | |||||
import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | import com.jd.blockchain.storage.service.utils.MemoryKVStorage; | ||||
import com.jd.blockchain.transaction.TxBuilder; | import com.jd.blockchain.transaction.TxBuilder; | ||||
import com.jd.blockchain.utils.Bytes; | |||||
public class ContractInvokingTest { | public class ContractInvokingTest { | ||||
static { | static { | ||||
@@ -44,7 +62,6 @@ public class ContractInvokingTest { | |||||
private static final String LEDGER_KEY_PREFIX = "LDG://"; | private static final String LEDGER_KEY_PREFIX = "LDG://"; | ||||
private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate(); | private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate(); | ||||
private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate(); | private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate(); | ||||
private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); | private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); | ||||
@@ -56,18 +73,69 @@ public class ContractInvokingTest { | |||||
@Test | @Test | ||||
public void test() { | public void test() { | ||||
// 初始化账本到指定的存储库; | // 初始化账本到指定的存储库; | ||||
HashDigest ledgerHash = initLedger(storage, parti0, parti1, parti2, parti3); | |||||
HashDigest ledgerHash = initLedger(storage, parti0, parti1, parti2, parti3); | |||||
// 重新加载账本; | // 重新加载账本; | ||||
LedgerManager ledgerManager = new LedgerManager(); | LedgerManager ledgerManager = new LedgerManager(); | ||||
LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage); | LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage); | ||||
OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | |||||
//构建基于接口调用合约的交易请求; | |||||
// 创建合约处理器; | |||||
ContractInvokingHandle contractInvokingHandle = new ContractInvokingHandle(); | |||||
// 创建和加载合约实例; | |||||
BlockchainKeypair contractKey = BlockchainKeyGenerator.getInstance().generate(); | |||||
Bytes contractAddress = contractKey.getAddress(); | |||||
TestContract contractInstance = Mockito.mock(TestContract.class); | |||||
contractInvokingHandle.setup(contractAddress, TestContract.class, contractInstance); | |||||
// 注册合约处理器; | |||||
DefaultOperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); | |||||
opReg.insertAsTopPriority(contractInvokingHandle); | |||||
// 创建新区块的交易处理器; | |||||
LedgerBlock preBlock = ledgerRepo.getLatestBlock(); | |||||
LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); | |||||
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||||
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, | |||||
opReg, ledgerManager); | |||||
// 构建基于接口调用合约的交易请求,用于测试合约调用; | |||||
Random rand = new Random(); | |||||
TxBuilder txBuilder = new TxBuilder(ledgerHash); | TxBuilder txBuilder = new TxBuilder(ledgerHash); | ||||
// txBuilder.contract(address, contractIntf) | |||||
TestContract contractProxy = txBuilder.contract(contractAddress, TestContract.class); | |||||
String asset = "AK"; | |||||
long issueAmount = rand.nextLong(); | |||||
when(contractInstance.issue(anyString(), anyLong())).thenReturn(issueAmount); | |||||
contractProxy.issue(asset, issueAmount); | |||||
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | |||||
txReqBuilder.signAsEndpoint(parti0); | |||||
txReqBuilder.signAsNode(parti0); | |||||
TransactionRequest txReq = txReqBuilder.buildRequest(); | |||||
TransactionResponse resp = txbatchProcessor.schedule(txReq); | |||||
verify(contractInstance, times(1)).issue(asset, issueAmount); | |||||
OperationResult[] opResults = resp.getOperationResults(); | |||||
assertEquals(1, opResults.length); | |||||
assertEquals(0, opResults[0].getIndex()); | |||||
byte[] retnBytes = BinaryProtocol.encode(BytesValueEntry.fromInt64(issueAmount), BytesValue.class); | |||||
assertArrayEquals(retnBytes, opResults[0].getResult()); | |||||
// 提交区块; | |||||
TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare(); | |||||
txResultHandle.commit(); | |||||
LedgerBlock latestBlock = ledgerRepo.getLatestBlock(); | |||||
assertEquals(preBlock.getHeight() + 1, latestBlock.getHeight()); | |||||
assertEquals(resp.getBlockHeight(), latestBlock.getHeight()); | |||||
assertEquals(resp.getBlockHash(), latestBlock.getHash()); | |||||
// 再验证一次结果; | |||||
assertEquals(1, opResults.length); | |||||
assertEquals(0, opResults[0].getIndex()); | |||||
assertArrayEquals(retnBytes, opResults[0].getResult()); | |||||
} | } | ||||
private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) { | private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) { | ||||
@@ -1,5 +1,9 @@ | |||||
package test.com.jd.blockchain.ledger; | package test.com.jd.blockchain.ledger; | ||||
import com.jd.blockchain.contract.Contract; | |||||
import com.jd.blockchain.contract.ContractEvent; | |||||
@Contract | |||||
public interface TestContract { | public interface TestContract { | ||||
/** | /** | ||||
@@ -9,6 +13,7 @@ public interface TestContract { | |||||
* @param amount 本次发行的资产数量; | * @param amount 本次发行的资产数量; | ||||
* @return 资产总量; | * @return 资产总量; | ||||
*/ | */ | ||||
@ContractEvent(name = "issue") | |||||
long issue(String asset, long amount); | long issue(String asset, long amount); | ||||
/** | /** | ||||
@@ -17,6 +22,7 @@ public interface TestContract { | |||||
* @param asset | * @param asset | ||||
* @return | * @return | ||||
*/ | */ | ||||
@ContractEvent(name = "get-amount") | |||||
long getAmount(String asset); | long getAmount(String asset); | ||||
/** | /** | ||||
@@ -26,6 +32,7 @@ public interface TestContract { | |||||
* @param asset | * @param asset | ||||
* @return | * @return | ||||
*/ | */ | ||||
@ContractEvent(name = "get-balance") | |||||
long getBalance(String address, String asset); | long getBalance(String address, String asset); | ||||
/** | /** | ||||
@@ -35,6 +42,7 @@ public interface TestContract { | |||||
* @param asset | * @param asset | ||||
* @param amount | * @param amount | ||||
*/ | */ | ||||
@ContractEvent(name = "assign") | |||||
void assign(String address, String asset, int amount); | void assign(String address, String asset, int amount); | ||||
/** | /** | ||||
@@ -45,5 +53,6 @@ public interface TestContract { | |||||
* @param asset | * @param asset | ||||
* @param amount | * @param amount | ||||
*/ | */ | ||||
@ContractEvent(name = "transfer") | |||||
void transfer(String fromAddress, String toAddress, String asset, long amount); | void transfer(String fromAddress, String toAddress, String asset, long amount); | ||||
} | } |
@@ -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; | 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) { | public ContractException(String message) { | ||||
super(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 | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
public interface ContractAppLifecycleAwire extends ContractRuntimeAwire { | |||||
public interface ContractLifecycleAware extends ContractAware { | |||||
void postConstruct(); | void postConstruct(); | ||||
@@ -1,11 +0,0 @@ | |||||
package com.jd.blockchain.contract; | |||||
/** | |||||
* 合约实现 {@link ContractRuntimeAwire} 的子接口可以监听运行时的生命周期事件; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public interface ContractRuntimeAwire { | |||||
} |
@@ -1,13 +1,10 @@ | |||||
package com.jd.blockchain.transaction; | |||||
package com.jd.blockchain.contract; | |||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | 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.contract.ContractSerializeUtils; | import com.jd.blockchain.contract.ContractSerializeUtils; | ||||
import com.jd.blockchain.utils.IllegalDataException; | import com.jd.blockchain.utils.IllegalDataException; | ||||
@@ -16,7 +13,16 @@ public class ContractType { | |||||
private String name; | private String name; | ||||
private Map<String, Method> events = new HashMap<>(); | private Map<String, Method> events = new HashMap<>(); | ||||
private Map<Method, String> handleMethods = new HashMap<>(); | private Map<Method, String> handleMethods = new HashMap<>(); | ||||
// private Map<Method, List<DataContract>> dataContractMap = new HashMap<>(); | |||||
private Class<?> declaredClass; | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
public Class<?> getDeclaredClass() { | |||||
return declaredClass; | |||||
} | |||||
/** | /** | ||||
* 返回声明的所有事件; | * 返回声明的所有事件; | ||||
@@ -27,10 +33,6 @@ public class ContractType { | |||||
return events.keySet(); | return events.keySet(); | ||||
} | } | ||||
// public Map<Method, List<DataContract>> getDataContractMap() { | |||||
// return dataContractMap; | |||||
// } | |||||
/** | /** | ||||
* 返回指定方法声明的事件;<br> | * 返回指定方法声明的事件;<br> | ||||
* | * | ||||
@@ -58,6 +60,12 @@ public class ContractType { | |||||
private ContractType() { | private ContractType() { | ||||
} | } | ||||
/** | |||||
* 解析合约的声明; | |||||
* | |||||
* @param delaredInterface 声明合约的接口类型; | |||||
* @return | |||||
*/ | |||||
public static ContractType resolve(Class<?> contractIntf) { | public static ContractType resolve(Class<?> contractIntf) { | ||||
// 如果是Class则首先获取其接口 | // 如果是Class则首先获取其接口 |
@@ -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 | * @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 { | public class LocalContractEventContext implements ContractEventContext,Cloneable { | ||||
private HashDigest ledgeHash; | private HashDigest ledgeHash; | ||||
private String event; | private String event; | ||||
private byte[] chainCode; | |||||
private byte[] args; | private byte[] args; | ||||
private TransactionRequest transactionRequest; | private TransactionRequest transactionRequest; | ||||
private Set<BlockchainIdentity> txSigners; | private Set<BlockchainIdentity> txSigners; | ||||
private Set<BlockchainIdentity> contractOwners; | |||||
private LedgerContext ledgerContext; | private LedgerContext ledgerContext; | ||||
public LocalContractEventContext(HashDigest ledgeHash, String event){ | public LocalContractEventContext(HashDigest ledgeHash, String event){ | ||||
this.ledgeHash = ledgeHash; | this.ledgeHash = ledgeHash; | ||||
this.event = event; | this.event = event; | ||||
// this.chainCode = chainCode; | |||||
} | } | ||||
@Override | @Override | ||||
@@ -81,11 +78,6 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable | |||||
return this; | return this; | ||||
} | } | ||||
public LocalContractEventContext setContractOwners(Set<BlockchainIdentity> contractOwners) { | |||||
this.contractOwners = contractOwners; | |||||
return this; | |||||
} | |||||
public LocalContractEventContext setLedgerContext(LedgerContext ledgerContext) { | public LocalContractEventContext setLedgerContext(LedgerContext ledgerContext) { | ||||
this.ledgerContext = ledgerContext; | this.ledgerContext = ledgerContext; | ||||
return this; | return this; | ||||
@@ -4,6 +4,7 @@ import java.lang.reflect.InvocationHandler; | |||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import com.jd.blockchain.contract.ContractSerializeUtils; | import com.jd.blockchain.contract.ContractSerializeUtils; | ||||
import com.jd.blockchain.contract.ContractType; | |||||
import com.jd.blockchain.ledger.ContractEventSendOperation; | import com.jd.blockchain.ledger.ContractEventSendOperation; | ||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.IllegalDataException; | import com.jd.blockchain.utils.IllegalDataException; | ||||
@@ -5,6 +5,7 @@ import java.util.Map; | |||||
import java.util.concurrent.ConcurrentHashMap; | import java.util.concurrent.ConcurrentHashMap; | ||||
import com.jd.blockchain.contract.EventResult; | import com.jd.blockchain.contract.EventResult; | ||||
import com.jd.blockchain.contract.ContractType; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.IllegalDataException; | import com.jd.blockchain.utils.IllegalDataException; | ||||
@@ -0,0 +1,69 @@ | |||||
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.ContractException; | |||||
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")); | |||||
//解析非合约声明接口类型时,应该引发异常 ContractException; | |||||
ContractException ex = null; | |||||
try { | |||||
ContractType.resolve(NormalContractImpl.class); | |||||
} catch (ContractException e) { | |||||
ex = e; | |||||
} | |||||
assertNotNull(ex); | |||||
} | |||||
} |
@@ -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 ClassLoader moduleClassLoader; | ||||
private String MainClass; | |||||
private String mainClass; | |||||
public DefaultModule(String name, ClassLoader cl, String mainClass) { | public DefaultModule(String name, ClassLoader cl, String mainClass) { | ||||
this.name = name; | this.name = name; | ||||
this.moduleClassLoader = cl; | this.moduleClassLoader = cl; | ||||
this.MainClass = mainClass; | |||||
this.mainClass = mainClass; | |||||
} | } | ||||
@Override | @Override | ||||
public String getMainClass() { | 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.ContractEventContext; | ||||
import com.jd.blockchain.contract.ContractException; | 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.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.KVDataEntry; | import com.jd.blockchain.ledger.KVDataEntry; | ||||
@@ -21,7 +21,7 @@ import com.jd.blockchain.ledger.KVDataObject; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
public class AssetContractImpl implements EventProcessingAwire, AssetContract { | |||||
public class AssetContractImpl implements EventProcessingAware, AssetContract { | |||||
// 资产管理账户的地址; | // 资产管理账户的地址; | ||||
private static final String ASSET_ADDRESS = "2njZBNbFQcmKd385DxVejwSjy4driRzf9Pk"; | 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.ContractEventContext; | ||||
import com.jd.blockchain.contract.ContractException; | 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.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.KVDataEntry; | import com.jd.blockchain.ledger.KVDataEntry; | ||||
public class AccountContractImpl implements EventProcessingAwire, AccountContract { | |||||
public class AccountContractImpl implements EventProcessingAware, AccountContract { | |||||
private ContractEventContext eventContext; | private ContractEventContext eventContext; | ||||
@@ -2,9 +2,9 @@ package com.jd.blockchain.mocker.contracts; | |||||
import com.jd.blockchain.contract.ContractEventContext; | import com.jd.blockchain.contract.ContractEventContext; | ||||
import com.jd.blockchain.contract.ContractException; | 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; | private ContractEventContext eventContext; | ||||
@@ -1,22 +1,28 @@ | |||||
package com.jd.blockchain.mocker.handler; | package com.jd.blockchain.mocker.handler; | ||||
import com.jd.blockchain.contract.*; | |||||
import java.util.Map; | |||||
import java.util.Set; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import com.jd.blockchain.contract.ContractEventContext; | |||||
import com.jd.blockchain.contract.ContractException; | |||||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||||
import com.jd.blockchain.contract.EventProcessingAware; | |||||
import com.jd.blockchain.contract.LedgerContext; | |||||
import com.jd.blockchain.crypto.HashDigest; | import com.jd.blockchain.crypto.HashDigest; | ||||
import com.jd.blockchain.ledger.BlockchainIdentity; | import com.jd.blockchain.ledger.BlockchainIdentity; | ||||
import com.jd.blockchain.ledger.ContractEventSendOperation; | import com.jd.blockchain.ledger.ContractEventSendOperation; | ||||
import com.jd.blockchain.ledger.Operation; | import com.jd.blockchain.ledger.Operation; | ||||
import com.jd.blockchain.ledger.TransactionRequest; | import com.jd.blockchain.ledger.TransactionRequest; | ||||
import com.jd.blockchain.ledger.core.*; | |||||
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.LedgerManager; | import com.jd.blockchain.ledger.core.impl.LedgerManager; | ||||
import com.jd.blockchain.ledger.core.impl.LedgerQueryService; | import com.jd.blockchain.ledger.core.impl.LedgerQueryService; | ||||
import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | import com.jd.blockchain.ledger.core.impl.OperationHandleContext; | ||||
import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext; | import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext; | ||||
import com.jd.blockchain.mocker.proxy.ExecutorProxy; | import com.jd.blockchain.mocker.proxy.ExecutorProxy; | ||||
import com.jd.blockchain.utils.concurrent.AsyncFuture; | |||||
import java.util.Map; | |||||
import java.util.Set; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
public class MockerContractExeHandle implements OperationHandle { | public class MockerContractExeHandle implements OperationHandle { | ||||
@@ -44,10 +50,10 @@ public class MockerContractExeHandle implements OperationHandle { | |||||
contractOP.getEvent(), requestContext.getRequest(), ledgerContext); | contractOP.getEvent(), requestContext.getRequest(), ledgerContext); | ||||
Object instance = executorProxy.getInstance(); | Object instance = executorProxy.getInstance(); | ||||
EventProcessingAwire awire = null; | |||||
EventProcessingAware awire = null; | |||||
if (instance instanceof EventProcessingAwire) { | |||||
awire = (EventProcessingAwire) instance; | |||||
if (instance instanceof EventProcessingAware) { | |||||
awire = (EventProcessingAware) instance; | |||||
awire.beforeEvent(contractEventContext); | awire.beforeEvent(contractEventContext); | ||||
} | } | ||||
@@ -70,10 +76,10 @@ public class MockerContractExeHandle implements OperationHandle { | |||||
return ContractSerializeUtils.serialize(result); | return ContractSerializeUtils.serialize(result); | ||||
} | } | ||||
@Override | |||||
public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
return null; | |||||
} | |||||
// @Override | |||||
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { | |||||
// return null; | |||||
// } | |||||
@Override | @Override | ||||
public boolean support(Class<?> operationType) { | public boolean support(Class<?> operationType) { | ||||