diff --git a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java index 48cffbc7..e2f8d65b 100644 --- a/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java +++ b/source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java @@ -9,6 +9,8 @@ package com.jd.blockchain.consts; public interface DataCodes { public static final int BYTES_VALUE = 0x80; + + public static final int BYTES_VALUE_LIST = 0x81; public static final int BLOCK_CHAIN_IDENTITY = 0x90; @@ -16,8 +18,6 @@ public interface DataCodes { public static final int BLOCK_BODY = 0x110; - // public static final int BLOCK_LEDGER = 0x110; - public static final int BLOCK_GENESIS = 0x120; public static final int DATA_SNAPSHOT = 0x130; @@ -30,6 +30,8 @@ public interface DataCodes { public static final int TX_CONTENT_BODY = 0x220; + public static final int TX_RETURN_MESSAGE = 0x230; + public static final int TX_OP = 0x300; public static final int TX_OP_LEDGER_INIT = 0x301; @@ -49,6 +51,8 @@ public interface DataCodes { public static final int TX_RESPONSE = 0x350; + public static final int TX_OP_RESULT = 0x360; + public static final int METADATA = 0x600; public static final int METADATA_INIT_SETTING = 0x610; @@ -81,17 +85,9 @@ public interface DataCodes { //contract related; public static final int CONTRACT = 0xA00; - public static final int CONTRACT_INT8 = 0xA01; - public static final int CONTRACT_INT16 = 0xA02; - public static final int CONTRACT_INT32 = 0xA03; - public static final int CONTRACT_INT64 = 0xA04; - public static final int CONTRACT_TEXT = 0xA05; - public static final int CONTRACT_BINARY = 0xA06; - public static final int CONTRACT_BIG_INT = 0xA07; - //...0xA19 - public static final int CONTRACT_BIZ_CONTENT = 0xA20; - public static final int CONTRACT_ARGS = 0xA21; + + //...0xA19 public static final int HASH = 0xB00; public static final int HASH_OBJECT = 0xB10; diff --git a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BaseType.java b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BaseType.java new file mode 100644 index 00000000..f649171e --- /dev/null +++ b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BaseType.java @@ -0,0 +1,63 @@ +package com.jd.blockchain.binaryproto; + +/** + * 基础类型标志; + * + * @author huanghaiquan + * + */ +public interface BaseType { + + /** + * 空值; + */ + public static final byte NIL = (byte) 0x00; + + /** + * 布尔; + */ + public static final byte BOOLEAN = (byte) 0x01; + + /** + * 整数; + */ + public static final byte INTEGER = (byte) 0x10; + + /** + * 8位整数; + */ + public static final byte INT8 = (byte) (INTEGER | 0x01); + + /** + * 16位整数; + */ + public static final byte INT16 = (byte) (INTEGER | 0x02); + + /** + * 32位整数; + */ + public static final byte INT32 = (byte) (INTEGER | 0x03); + + /** + * 64位整数; + */ + public static final byte INT64 = (byte) (INTEGER | 0x04); + + /** + * 文本 + */ + public static final byte TEXT = (byte) 0x20; + + /** + * 字节序列; + */ + public static final byte BYTES = (byte) 0x40; + + /** + * 扩展类型;
+ * + * 最高位为1,用作保留字段; + */ + public static final byte EXT = (byte) 0x80; + +} diff --git a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java index e0b17277..ddf8e012 100644 --- a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java +++ b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java @@ -57,5 +57,7 @@ public class BinaryProtocol { } + + } diff --git a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java deleted file mode 100644 index 9df9f7bd..00000000 --- a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.jd.blockchain.binaryproto; - -public interface DataType { - - /** - * 空值; - */ - public static final byte NIL = (byte) 0x00; - - /** - * 布尔; - */ - public static final byte BOOLEAN = (byte) 0x01; - - /** - * 数值; - */ - public static final byte NUMERIC = (byte) 0x10; - - public static final byte TEXT = (byte) 0x20; - - public static final byte BINARY = (byte) 0x40; - -} diff --git a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/PrimitiveType.java b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/PrimitiveType.java index c183d8df..b43f743e 100644 --- a/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/PrimitiveType.java +++ b/source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/PrimitiveType.java @@ -11,68 +11,42 @@ public enum PrimitiveType { /** * 空; */ - NIL(DataType.NIL), + NIL(BaseType.NIL), /** * 布尔型; */ - BOOLEAN(DataType.BOOLEAN), + BOOLEAN(BaseType.BOOLEAN), /** - * 数值型: + * 8位的整数: */ - INT8((byte) (DataType.NUMERIC | 0x01)), - - INT16((byte) (DataType.NUMERIC | 0x02)), - - INT32((byte) (DataType.NUMERIC | 0x03)), - - INT64((byte) (DataType.NUMERIC | 0x04)), + INT8(BaseType.INT8), /** - * 时间戳; + * 16位整数; */ - TIMESTAMP((byte) (DataType.NUMERIC | 0x08)), + INT16(BaseType.INT16), /** - * 文本数据; + * 32位整数; */ - TEXT(DataType.TEXT), + INT32(BaseType.INT32), /** - * 文本数据; + * 64位整数; */ - JSON((byte) (DataType.TEXT | 0x01)), + INT64(BaseType.INT64), /** - * 文本数据; + * 文本; */ - XML((byte) (DataType.TEXT | 0x02)), + TEXT(BaseType.TEXT), /** * 二进制数据; */ - BYTES(DataType.BINARY), - - /** - * 大整数; - */ - BIG_INT((byte) (DataType.BINARY | 0x01)), - - /** - * 图片; - */ - IMG((byte) (DataType.BINARY | 0x02)), - - /** - * 视频; - */ - VIDEO((byte) (DataType.BINARY | 0x03)), - - /** - * 位置坐标; - */ - LOCATION((byte) (DataType.BINARY | 0x04)); + BYTES(BaseType.BYTES); public final byte CODE; diff --git a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java index 94ded100..2f363a55 100644 --- a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java +++ b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java @@ -1,16 +1,14 @@ package com.jd.blockchain.contract.engine; import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.utils.Bytes; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; - public interface ContractCode { Bytes getAddress(); long getVersion(); - void processEvent(ContractEventContext eventContext, CompletableFuture execReturn); + BytesValue processEvent(ContractEventContext eventContext); } diff --git a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java index 2e81c7f8..8567c13e 100644 --- a/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java +++ b/source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java @@ -1,6 +1,5 @@ package com.jd.blockchain.contract.engine; -import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.utils.Bytes; /** @@ -27,9 +26,9 @@ public interface ContractEngine { * 如果已经存在,则直接返回已有实例; * * @param address - * @param code + * @param codeBytes * @return */ - ContractCode setupContract(Bytes address, long version, byte[] code); + ContractCode setupContract(Bytes address, long version, byte[] codeBytes); } diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java new file mode 100644 index 00000000..2aee31f8 --- /dev/null +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java @@ -0,0 +1,105 @@ +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.ledger.BytesValue; +import com.jd.blockchain.ledger.BytesValueEncoding; +import com.jd.blockchain.ledger.BytesValueList; +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 BytesValue processEvent(ContractEventContext eventContext) { + EventProcessingAware evtProcAwire = null; + Object retn = null; + Method handleMethod = null; + Exception error = null; + try { + // 执行预处理; + Object contractInstance = getContractInstance(); + if (contractInstance instanceof EventProcessingAware) { + evtProcAwire = (EventProcessingAware) contractInstance; + } + + if (evtProcAwire != null) { + evtProcAwire.beforeEvent(eventContext); + } + + // 反序列化参数; + 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().getName(), eventContext.getEvent())); + } + + BytesValueList bytesValues = eventContext.getArgs(); + Object[] args = BytesValueEncoding.decode(bytesValues, handleMethod.getParameterTypes()); + + 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); + } + + BytesValue retnBytes = BytesValueEncoding.encodeSingle(retn, handleMethod.getReturnType()); + return retnBytes; + } + + protected abstract Object getContractInstance(); + +} diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/ContractDefinition.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/ContractDefinition.java new file mode 100644 index 00000000..d61e037a --- /dev/null +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/ContractDefinition.java @@ -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; + } + +} diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java index 0a8b0018..ea1ee9fa 100644 --- a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java @@ -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; diff --git a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java index 4dcab78f..c6b7c5b9 100644 --- a/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java +++ b/source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java @@ -1,42 +1,60 @@ package com.jd.blockchain.contract.jvm; -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.contract.ContractEventContext; -import com.jd.blockchain.contract.ContractSerializeUtils; -import com.jd.blockchain.contract.engine.ContractCode; -import com.jd.blockchain.runtime.Module; -import com.jd.blockchain.transaction.ContractType; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.IllegalDataException; +import java.util.concurrent.Callable; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Method; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEventContext; +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.contract.ContractType; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.runtime.Module; +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 ContractEventContext contractEventContext; - - 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; } + 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 public Bytes getAddress() { return address; @@ -48,87 +66,42 @@ public class JavaContractCode implements ContractCode { } @Override - public void processEvent(ContractEventContext eventContext, CompletableFuture execReturn) { - this.contractEventContext = eventContext; - codeModule.execute(new ContractExecution(execReturn)); + public BytesValue processEvent(ContractEventContext 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 Object resolveArgs(byte[] args, List dataContractList) { - if(args == null || args.length == 0){ - return null; + protected Object getContractInstance() { + try { + // 每一次调用都通过反射创建合约的实例; + return getContractDefinition().getMainClass().newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException(e.getMessage(), e); } - return ContractSerializeUtils.deserializeMethodParam(args,dataContractList); } - class ContractExecution implements Runnable { - - private CompletableFuture contractReturn; + private class ContractExecution implements Callable { + private ContractEventContext eventContext; - public ContractExecution(CompletableFuture contractReturn) { - this.contractReturn = contractReturn; + public ContractExecution(ContractEventContext contractEventContext) { + this.eventContext = contractEventContext; } - public void run() { - LOGGER.info("ContractThread execute()."); - try { - // 执行预处理; - long startTime = System.currentTimeMillis(); - - String contractClassName = codeModule.getMainClass(); - - Class myClass = codeModule.loadClass(contractClassName); - - Object contractMainClassObj = myClass.newInstance();// 合约主类生成的类实例; - - Method beforeMth_ = myClass.getMethod("beforeEvent", - codeModule.loadClass(ContractEventContext.class.getName())); - - ReflectionUtils.invokeMethod(beforeMth_, contractMainClassObj, contractEventContext); - - LOGGER.info("beforeEvent,耗时:" + (System.currentTimeMillis() - startTime)); - -// Method eventMethod = this.getMethodByAnno(contractMainClassObj, contractEventContext.getEvent()); - startTime = System.currentTimeMillis(); - - // 反序列化参数; - contractType = ContractType.resolve(myClass); - - Method handleMethod = contractType.getHandleMethod(contractEventContext.getEvent()); - - if (handleMethod == null){ - throw new IllegalDataException("don't get this method by it's @ContractEvent."); - } - - Object args = resolveArgs(contractEventContext.getArgs(), - contractType.getDataContractMap().get(handleMethod)); - - Object[] params = null; - - if(args.getClass().isArray()){ - params = (Object[])args; - } - - String contractReturn = ReflectionUtils.invokeMethod(handleMethod, contractMainClassObj, params).toString(); - - LOGGER.info("合约执行,耗时:" + (System.currentTimeMillis() - startTime)); - - Method mth2 = myClass.getMethod("postEvent"); - - startTime = System.currentTimeMillis(); - - ReflectionUtils.invokeMethod(mth2, contractMainClassObj); - - LOGGER.info("postEvent,耗时:" + (System.currentTimeMillis() - startTime)); - - // 填充return结果 - if (this.contractReturn != null) { - this.contractReturn.complete(contractReturn); - } - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException(e.getMessage()); - } catch (Exception e) { - throw new IllegalDataException(e.getMessage()); - } + @Override + public BytesValue call() throws Exception { + return JavaContractCode.super.processEvent(eventContext); } } diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java index 64a12e20..461917a4 100644 --- a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java +++ b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java @@ -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; diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java index b597558e..19822d00 100644 --- a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java +++ b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java @@ -1,6 +1,5 @@ package com.jd.blockchain.contract; -import com.jd.blockchain.ledger.ContractBizContent; import com.jd.blockchain.utils.Bytes; /** diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java index 06af2632..9f5588bb 100644 --- a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java +++ b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java @@ -1,6 +1,5 @@ package com.jd.blockchain.contract; -import com.jd.blockchain.ledger.ContractBizContent; import com.jd.blockchain.ledger.KVDataEntry; import com.jd.blockchain.ledger.KVDataObject; import com.jd.blockchain.utils.Bytes; diff --git a/source/contract/contract-samples/pom.xml b/source/contract/contract-samples/pom.xml index b229b7bc..5842f8c7 100644 --- a/source/contract/contract-samples/pom.xml +++ b/source/contract/contract-samples/pom.xml @@ -34,11 +34,11 @@ maven-assembly-plugin - contract + transfer false - com.jd.blockchain.contract.ReadContractImpl + com.jd.blockchain.contract.TransferContractImpl diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java index 1f82491f..25bc9aca 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java @@ -6,5 +6,10 @@ public interface ReadContract { @ContractEvent(name = "read-key") String read(String address, String key); + + @ContractEvent(name = "version-key") + Long readVersion(String address, String key); + + int test(); } diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java index 65310b6e..e3d720a5 100644 --- a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java @@ -4,35 +4,26 @@ 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; + private HashDigest ledgerHash; + @Override public void beforeEvent(ContractEventContext eventContext) { this.eventContext = eventContext; + this.ledgerHash = eventContext.getCurrentLedgerHash(); } @Override - public void postEvent(ContractEventContext eventContext, ContractException error) { - - } - - @Override - public void postEvent(ContractException error) { - - } - - @Override - public void postEvent() { + public void postEvent(ContractEventContext eventContext, Exception error) { } @Override @ContractEvent(name = "read-key") public String read(String address, String key) { - HashDigest ledgerHash = eventContext.getCurrentLedgerHash(); - KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); if (kvDataEntries != null && kvDataEntries.length == 1) { @@ -40,4 +31,20 @@ public class ReadContractImpl implements EventProcessingAwire, ReadContract { } return null; } + + @Override + @ContractEvent(name = "version-key") + public Long readVersion(String address, String key) { + KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, key); + + if (kvDataEntries != null && kvDataEntries.length == 1) { + return kvDataEntries[0].getVersion(); + } + return -1L; + } + + @Override + public int test() { + return 0; + } } diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java new file mode 100644 index 00000000..321101a3 --- /dev/null +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java @@ -0,0 +1,17 @@ +package com.jd.blockchain.contract; + +@Contract +public interface TransferContract { + + @ContractEvent(name = "create") + String create(String address, String account, long money); + + @ContractEvent(name = "transfer") + String transfer(String address, String from, String to, long money); + + @ContractEvent(name = "read") + long read(String address, String account); + + @ContractEvent(name = "readAll") + String readAll(String address, String account); +} diff --git a/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java new file mode 100644 index 00000000..c312dd4f --- /dev/null +++ b/source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java @@ -0,0 +1,109 @@ +package com.jd.blockchain.contract; + +import com.alibaba.fastjson.JSON; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.KVDataVO; +import com.jd.blockchain.ledger.KVInfoVO; + +public class TransferContractImpl implements EventProcessingAware, TransferContract { + + private ContractEventContext eventContext; + + private HashDigest ledgerHash; + + @Override + public String create(String address, String account, long money) { + KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + // 肯定有返回值,但若不存在则返回version=-1 + if (kvDataEntries != null && kvDataEntries.length > 0) { + long currVersion = kvDataEntries[0].getVersion(); + if (currVersion > -1) { + throw new IllegalStateException(String.format("%s -> %s already have created !!!", address, account)); + } + eventContext.getLedger().dataAccount(address).setInt64(account, money, -1L); + } else { + throw new IllegalStateException(String.format("Ledger[%s] inner Error !!!", ledgerHash.toBase58())); + } + return String.format("DataAccountAddress[%s] -> Create(By Contract Operation) Account = %s and Money = %s Success!!! \r\n", + address, account, money); + } + + @Override + public String transfer(String address, String from, String to, long money) { + // 首先查询余额 + KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); + if (kvDataEntries == null || kvDataEntries.length != 2) { + throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); + } else { + // 判断from账号中钱数量是否足够 + long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; + for (KVDataEntry kvDataEntry : kvDataEntries) { + if (kvDataEntry.getKey().equals(from)) { + fromMoney = (long) kvDataEntry.getValue(); + fromVersion = kvDataEntry.getVersion(); + } else { + toMoney = (long) kvDataEntry.getValue(); + toVersion = kvDataEntry.getVersion(); + } + } + if (fromMoney < money) { + throw new IllegalStateException(String.format("%s -> %s not have enough money !!!", address, from)); + } + long fromNewMoney = fromMoney - money; + long toNewMoney = toMoney + money; + // 重新设置 + eventContext.getLedger().dataAccount(address).setInt64(from, fromNewMoney, fromVersion); + eventContext.getLedger().dataAccount(address).setInt64(to, toNewMoney, toVersion); + } + + return String.format("DataAccountAddress[%s] transfer from [%s] to [%s] and [money = %s] Success !!!", address, from, to, money); + } + + @Override + public long read(String address, String account) { + KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + if (kvDataEntries == null || kvDataEntries.length == 0) { + return -1; + } + return (long)kvDataEntries[0].getValue(); + } + + @Override + public String readAll(String address, String account) { + KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); + // 获取最新的版本号 + if (kvDataEntries == null || kvDataEntries.length == 0) { + return ""; + } + long newestVersion = kvDataEntries[0].getVersion(); + if (newestVersion == -1) { + return ""; + } + KVDataVO[] kvDataVOS = new KVDataVO[1]; + long[] versions = new long[(int)newestVersion + 1]; + for (int i = 0; i < versions.length; i++) { + versions[i] = i; + } + KVDataVO kvDataVO = new KVDataVO(account, versions); + + kvDataVOS[0] = kvDataVO; + + KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); + + KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); + + return JSON.toJSONString(allEntries); + } + + @Override + public void beforeEvent(ContractEventContext eventContext) { + this.eventContext = eventContext; + this.ledgerHash = eventContext.getCurrentLedgerHash(); + } + + @Override + public void postEvent(ContractEventContext eventContext, Exception error) { + + } +} diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java index fdd040fb..ac3c94f4 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java @@ -7,15 +7,21 @@ public final class ClassicAlgorithm { public static final CryptoAlgorithm ED25519 = CryptoAlgorithmDefinition.defineSignature("ED25519", false, (byte) 21); - public static final CryptoAlgorithm ECDSA = CryptoAlgorithmDefinition.defineSignature("ECDSA", false, (byte) 22); - public static final CryptoAlgorithm RSA = CryptoAlgorithmDefinition.defineSignature("RSA", true, (byte) 23); + public static final CryptoAlgorithm ECDSA = CryptoAlgorithmDefinition.defineSignature("ECDSA", false, + (byte) 22); - public static final CryptoAlgorithm SHA256 = CryptoAlgorithmDefinition.defineHash("SHA256", (byte) 24); + public static final CryptoAlgorithm RSA = CryptoAlgorithmDefinition.defineSignature("RSA", true, + (byte) 23); - public static final CryptoAlgorithm RIPEMD160 = CryptoAlgorithmDefinition.defineHash("RIPEMD160", (byte) 25); + public static final CryptoAlgorithm SHA256 = CryptoAlgorithmDefinition.defineHash("SHA256", + (byte) 24); - public static final CryptoAlgorithm AES = CryptoAlgorithmDefinition.defineSymmetricEncryption("AES", (byte) 26); + public static final CryptoAlgorithm RIPEMD160 = CryptoAlgorithmDefinition.defineHash("RIPEMD160", + (byte) 25); + + public static final CryptoAlgorithm AES = CryptoAlgorithmDefinition.defineSymmetricEncryption("AES", + (byte) 26); public static final CryptoAlgorithm JVM_SECURE_RANDOM = CryptoAlgorithmDefinition.defineRandom("JVM-SECURE-RANDOM", (byte) 27); diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java new file mode 100644 index 00000000..a0eebbc4 --- /dev/null +++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java @@ -0,0 +1,18 @@ +package test.com.jd.blockchain.crypto.service.classic; + +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.codec.HexUtils; +import org.junit.Assert; +import org.junit.Test; + +public class EncodeTest { + + @Test + public void test() { + String pubKey = "7VeRLdGtSz1Y91gjLTqEdnkotzUfaAqdap3xw6fQ1yKHkvVq"; + Bytes bytes = Bytes.fromBase58(pubKey); + String hexString = HexUtils.encode(bytes.toBytes()); + String code = hexString.substring(2, 4); + Assert.assertEquals(code, "15"); // 15为十六进制,对应十进制为21(ED25519) + } +} diff --git a/source/gateway/pom.xml b/source/gateway/pom.xml index 3150363e..9cb95d06 100644 --- a/source/gateway/pom.xml +++ b/source/gateway/pom.xml @@ -45,7 +45,7 @@ com.jd.blockchain - browser + explorer @@ -78,6 +78,23 @@ ${commons-io.version} + + org.bitbucket.mstrobel + procyon-core + + + org.bitbucket.mstrobel + procyon-expressions + + + org.bitbucket.mstrobel + procyon-reflection + + + org.bitbucket.mstrobel + procyon-compilertools + + org.springframework.boot spring-boot-starter-web diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java new file mode 100644 index 00000000..8caf66f0 --- /dev/null +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java @@ -0,0 +1,249 @@ +package com.jd.blockchain.gateway.decompiler.loads; + +import com.strobel.assembler.ir.ConstantPool; +import com.strobel.assembler.metadata.Buffer; +import com.strobel.assembler.metadata.ClasspathTypeLoader; +import com.strobel.assembler.metadata.ITypeLoader; +import com.strobel.core.StringUtilities; +import com.strobel.core.VerifyArgument; + +import java.io.ByteArrayInputStream; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class BytesTypeLoader implements ITypeLoader { + + private final static Logger LOG = Logger.getLogger(BytesTypeLoader.class.getSimpleName()); + + private final ITypeLoader defaultTypeLoader; + private final Map> packageLocations; + private final Map knownBytes; + + private String name; + + public BytesTypeLoader(byte[] bytes) { + this(new ClasspathTypeLoader(), bytes); + } + + public BytesTypeLoader(final ITypeLoader defaultTypeLoader, byte[] bytes) { + this.defaultTypeLoader = VerifyArgument.notNull(defaultTypeLoader, "defaultTypeLoader"); + this.packageLocations = new LinkedHashMap<>(); + this.knownBytes = new LinkedHashMap<>(); + Buffer innerNameBuffer = new Buffer(); + if (tryLoadTypeFromBytes(bytes, innerNameBuffer)) { + this.name = getInternalNameFromClassFile(innerNameBuffer); + this.knownBytes.put(this.name, bytes); + } else { + throw new IllegalStateException("Input Class Bytes Exception !!!"); + } + } + + @Override + public boolean tryLoadType(final String typeNameOrPath, final Buffer buffer) { + VerifyArgument.notNull(typeNameOrPath, "typeNameOrPath"); + VerifyArgument.notNull(buffer, "buffer"); + + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Attempting to load type: " + typeNameOrPath + "..."); + } + + final boolean hasExtension = StringUtilities.endsWithIgnoreCase(typeNameOrPath, ".class"); + + if (hasExtension) { + return false; + } + + String internalName = typeNameOrPath; + + if (tryLoadTypeFromName(internalName, buffer)) { + return true; + } + + for (int lastDelimiter = internalName.lastIndexOf('/'); + lastDelimiter != -1; + lastDelimiter = internalName.lastIndexOf('/')) { + + internalName = internalName.substring(0, lastDelimiter) + "$" + + internalName.substring(lastDelimiter + 1); + + if (tryLoadTypeFromName(internalName, buffer)) { + return true; + } + } + + if (LOG.isLoggable(Level.FINER)) { + LOG.finer("Failed to load type: " + typeNameOrPath + "."); + } + + return false; + } + + private boolean tryLoadTypeFromName(final String internalName, final Buffer buffer) { + if (tryLoadFromKnownLocation(internalName, buffer)) { + return true; + } + + if (defaultTypeLoader.tryLoadType(internalName, buffer)) { + return true; + } + + return false; + } + + private boolean tryLoadFromKnownLocation(final String internalName, final Buffer buffer) { + final byte[] knownFile = knownBytes.get(internalName); + + if (tryLoadBytes(knownFile, buffer)) { + return true; + } + + final int packageEnd = internalName.lastIndexOf('/'); + + String head; + String tail; + + if (packageEnd < 0 || packageEnd >= internalName.length()) { + head = StringUtilities.EMPTY; + tail = internalName; + } + else { + head = internalName.substring(0, packageEnd); + tail = internalName.substring(packageEnd + 1); + } + + while (true) { + final LinkedHashSet directories = packageLocations.get(head); + + if (directories != null) { + for (final byte[] directory : directories) { + if (tryLoadBytes(internalName, directory, buffer, true)) { + return true; + } + } + } + + final int split = head.lastIndexOf('/'); + + if (split <= 0) { + break; + } + + tail = head.substring(split + 1) + '/' + tail; + head = head.substring(0, split); + } + + return false; + } + + private boolean tryLoadBytes(final byte[] bytes, final Buffer buffer) { + + if (bytes == null || bytes.length == 0) { + return false; + } + + int length = bytes.length; + buffer.position(0); + buffer.reset(length); + new ByteArrayInputStream(bytes).read(buffer.array(), 0, length); + buffer.position(0); + + return true; + } + + private boolean tryLoadBytes(final String internalName, final byte[] bytes, final Buffer buffer, final boolean trustName) { + if (!tryLoadBytes(bytes, buffer)) { + return false; + } + + final String actualName = getInternalNameFromClassFile(buffer); + + final String name = trustName ? (internalName != null ? internalName : actualName) + : actualName; + + if (name == null) { + return false; + } + + final boolean nameMatches = StringUtilities.equals(actualName, internalName); + + final boolean result = internalName == null || nameMatches; + + if (result) { + final int packageEnd = name.lastIndexOf('/'); + final String packageName; + + if (packageEnd < 0 || packageEnd >= name.length()) { + packageName = StringUtilities.EMPTY; + } + else { + packageName = name.substring(0, packageEnd); + } + + registerKnownPath(packageName, bytes); + + knownBytes.put(actualName, bytes); + + } + else { + buffer.reset(0); + } + + return result; + } + + private void registerKnownPath(final String packageName, final byte[] directory) { + if (directory == null || directory.length == 0) { + return; + } + + LinkedHashSet directories = packageLocations.get(packageName); + + if (directories == null) { + packageLocations.put(packageName, directories = new LinkedHashSet<>()); + } + + if (!directories.add(directory)) { + return; + } + } + + private static String getInternalNameFromClassFile(final Buffer b) { + final long magic = b.readInt() & 0xFFFFFFFFL; + + if (magic != 0xCAFEBABEL) { + return null; + } + + b.readUnsignedShort(); // minor version + b.readUnsignedShort(); // major version + + final ConstantPool constantPool = ConstantPool.read(b); + + b.readUnsignedShort(); // access flags + + final ConstantPool.TypeInfoEntry thisClass = constantPool.getEntry(b.readUnsignedShort()); + + b.position(0); + + return thisClass.getName(); + } + + public String getName() { + return name; + } + + private boolean tryLoadTypeFromBytes(byte[] bytes, Buffer buffer) { + if (bytes == null || bytes.length == 0 || buffer == null) { + return false; + } + int length = bytes.length; + buffer.position(0); + buffer.reset(length); + new ByteArrayInputStream(bytes).read(buffer.array(), 0, length); + buffer.position(0); + return true; + } +} diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java new file mode 100644 index 00000000..0a66da9f --- /dev/null +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java @@ -0,0 +1,218 @@ +package com.jd.blockchain.gateway.decompiler.utils; + +import com.jd.blockchain.gateway.decompiler.loads.BytesTypeLoader; +import com.strobel.assembler.metadata.JarTypeLoader; +import com.strobel.decompiler.Decompiler; +import com.strobel.decompiler.DecompilerSettings; +import com.strobel.decompiler.PlainTextOutput; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import java.util.jar.JarFile; + +public class DecompilerUtils { + + public static final AtomicLong SAVE_INDEX = new AtomicLong(); + + public static final String MANIFEST_MF = "/META-INF/MANIFEST.MF"; + + public static final String MAIN_CLASS = "Main-Class"; + + public static String SAVE_DIR = null; + + static { + init(); + } + + private static void init() { + try { + URL url = DecompilerUtils.class + .getProtectionDomain() + .getCodeSource() + .getLocation(); + String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); + if (currPath.contains("!/")) { + currPath = currPath.substring(5, currPath.indexOf("!/")); + } + if (currPath.endsWith(".jar")) { + currPath = currPath.substring(0, currPath.lastIndexOf("/") + 1); + } + File file = new File(currPath); + String homeDir = file.getParent(); + SAVE_DIR = homeDir + File.separator + "temp"; + File dir = new File(SAVE_DIR); + if (!dir.exists()) { + dir.mkdir(); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + + } + + public static String decompile(String classPath) { + + String decompileJava; + + try (StringWriter stringWriter = new StringWriter()) { + + final DecompilerSettings settings = DecompilerSettings.javaDefaults(); + + Decompiler.decompile( + classPath, + new PlainTextOutput(stringWriter), + settings + ); + decompileJava = stringWriter.toString(); + } catch (final Exception e) { + throw new IllegalStateException(e); + } + return decompileJava; + } + + public static List readManifest2Array(final String jarFilePath, final String charSet) { + String manifest = readManifest(jarFilePath, charSet); + String[] manifests = manifest.split("\r\n"); + return Arrays.asList(manifests); + } + + public static String readManifest(final String jarFilePath, final String charSet) { + return decompileJarFile(jarFilePath, MANIFEST_MF, false, charSet); + } + + public static String decompileMainClassFromBytes(byte[] bytes) { + try { + String jarFile = writeBytes(bytes, SAVE_DIR, "jar"); + String decompileJava = decompileMainClassFromJarFile(jarFile); + // 然后删除jarFile文件 + FileUtils.forceDelete(new File(jarFile)); + return decompileJava; + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + public static String decompileMainClassFromJarFile(final String jarFilePath) { + // 首先获取Main-Class + List manifests = readManifest2Array(jarFilePath, null); + if (manifests == null || manifests.size() == 0) { + throw new IllegalStateException("MANIFEST.MF not Exist or is Empty !!!"); + } else { + String mainClass = null; + for (String s : manifests) { + String inner = s.trim().replaceAll(" ", ""); + if (inner.startsWith(MAIN_CLASS)) { + mainClass = inner.split(":")[1]; + break; + } + } + if (mainClass == null || mainClass.length() == 0) { + throw new IllegalStateException("MANIFEST.MF has not Main-Class !!!"); + } + + // 然后读取MainClass中的内容并进行反编译 + String classPath = mainClass.replaceAll("\\.", "/"); + return decompileJarFile(jarFilePath, classPath, true, null); + } + } + + public static String decompileJarFile(final String jarFilePath, final String source, final boolean isClass, final String charSet) { + + // 对于Class文件和非Class文件处理方式不同 + if (!isClass) { + // 非Class文件不需要编译,直接从文件中读取即可 + String innerSource = source; + if (!innerSource.startsWith("/")) { + innerSource = "/" + innerSource; + } + try { + URL jarUrl = new URL("jar:file:" + jarFilePath + "!" + innerSource); + InputStream inputStream = jarUrl.openStream(); + byte[] bytes = IOUtils.toByteArray(inputStream); + if (charSet == null) { + return new String(bytes); + } + return new String(bytes, charSet); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } else { + + String decompileJava; + + try (StringWriter stringWriter = new StringWriter()) { + + JarFile jarFile = new JarFile(jarFilePath); + + JarTypeLoader jarTypeLoader = new JarTypeLoader(jarFile); + + final DecompilerSettings settings = DecompilerSettings.javaDefaults(); + + settings.setTypeLoader(jarTypeLoader); + + Decompiler.decompile( + source, + new PlainTextOutput(stringWriter), + settings + ); + decompileJava = stringWriter.toString(); + } catch (final Exception e) { + throw new IllegalStateException(e); + } + return decompileJava; + } + } + + public static String decompile(byte[] classBytes) { + + String decompileJava; + + try (StringWriter stringWriter = new StringWriter()) { + + BytesTypeLoader bytesTypeLoader = new BytesTypeLoader(classBytes); + + String name = bytesTypeLoader.getName(); + + final DecompilerSettings settings = DecompilerSettings.javaDefaults(); + + settings.setTypeLoader(bytesTypeLoader); + + Decompiler.decompile( + name, + new PlainTextOutput(stringWriter), + settings + ); + decompileJava = stringWriter.toString(); + } catch (final Exception e) { + throw new IllegalStateException(e); + } + return decompileJava; + } + + public static String decompile(InputStream in) { + try { + return decompile(IOUtils.toByteArray(in)); + } catch (final Exception e) { + throw new IllegalStateException(e); + } + } + + public static byte[] read2Bytes(String filePath) throws IOException { + return FileUtils.readFileToByteArray(new File(filePath)); + } + + public static String writeBytes(byte[] bytes, String directory, String suffix) throws IOException { + String saveFileName = System.currentTimeMillis() + "-" + SAVE_INDEX.incrementAndGet() + "." + suffix; + File saveFile = new File(directory + File.separator + saveFileName); + FileUtils.writeByteArrayToFile(saveFile, bytes); + return saveFile.getPath(); + } +} diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java index 6cd1828c..340527c7 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java @@ -2,7 +2,9 @@ package com.jd.blockchain.gateway.service; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.sdk.ContractSettings; import com.jd.blockchain.sdk.LedgerInitSettings; +import com.jd.blockchain.utils.Bytes; /** * queryService only for gateway; @@ -34,4 +36,15 @@ public interface GatewayQueryService { * @return */ LedgerInitSettings getLedgerInitSettings(HashDigest ledgerHash); + + /** + * 获取账本指定合约信息 + * + * @param ledgerHash + * 账本Hash + * @param address + * 合约地址 + * @return + */ + ContractSettings getContractSettings(HashDigest ledgerHash, String address); } diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java index 1a6c0267..4421dde1 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java @@ -7,8 +7,11 @@ import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.gateway.PeerService; +import com.jd.blockchain.gateway.decompiler.utils.DecompilerUtils; +import com.jd.blockchain.ledger.ContractInfo; import com.jd.blockchain.ledger.LedgerMetadata; import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.sdk.ContractSettings; import com.jd.blockchain.sdk.LedgerInitSettings; import com.jd.blockchain.utils.QueryUtil; import com.jd.blockchain.utils.codec.HexUtils; @@ -53,6 +56,21 @@ public class GatewayQueryServiceHandler implements GatewayQueryService { return initLedgerInitSettings(participantNodes, ledgerMetadata); } + @Override + public ContractSettings getContractSettings(HashDigest ledgerHash, String address) { + ContractInfo contractInfo = peerService.getQueryService().getContract(ledgerHash, address); + return contractSettings(contractInfo); + } + + private ContractSettings contractSettings(ContractInfo contractInfo) { + ContractSettings contractSettings = new ContractSettings(contractInfo.getAddress(), contractInfo.getPubKey(), contractInfo.getRootHash()); + byte[] chainCodeBytes = contractInfo.getChainCode(); + // 将反编译chainCode + String mainClassJava = DecompilerUtils.decompileMainClassFromBytes(chainCodeBytes); + contractSettings.setChainCode(mainClassJava); + return contractSettings; + } + /** * 初始化账本配置 * diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java index 66f94b97..91c498aa 100644 --- a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java +++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java @@ -8,6 +8,7 @@ import com.jd.blockchain.gateway.service.DataRetrievalService; import com.jd.blockchain.gateway.service.GatewayQueryService; import com.jd.blockchain.ledger.*; import com.jd.blockchain.sdk.BlockchainExtendQueryService; +import com.jd.blockchain.sdk.ContractSettings; import com.jd.blockchain.sdk.LedgerInitSettings; import com.jd.blockchain.tools.keygen.KeyGenCommand; import com.jd.blockchain.utils.BaseConstant; @@ -23,6 +24,7 @@ import java.util.List; @RestController @RequestMapping(path = "/") public class BlockBrowserController implements BlockchainExtendQueryService { + private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(BlockBrowserController.class); @Autowired @@ -55,7 +57,7 @@ public class BlockBrowserController implements BlockchainExtendQueryService { // @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/participants") @Override - public ParticipantNode[] getConsensusParticipants(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { + public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { return peerService.getQueryService().getConsensusParticipants(ledgerHash); } @@ -263,10 +265,15 @@ public class BlockBrowserController implements BlockchainExtendQueryService { } @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") + public ContractSettings getContractSettings(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "address") String address) { + return gatewayQueryService.getContractSettings(ledgerHash, address); + } + +// @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") @Override - public AccountHeader getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address) { - return peerService.getQueryService().getContract(ledgerHash, address); + public ContractInfo getContract(HashDigest ledgerHash, String address) { + return peerService.getQueryService().getContract(ledgerHash, address); } @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/latest") @@ -450,7 +457,8 @@ public class BlockBrowserController implements BlockchainExtendQueryService { } @RequestMapping(method = RequestMethod.GET, value = "ledgers/{ledgerHash}/**/search") - public Object dataRetrieval(@PathVariable(name = "ledgerHash") HashDigest ledgerHash,HttpServletRequest request) { + public Object dataRetrieval(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + HttpServletRequest request) { String result; if (dataRetrievalUrl == null || dataRetrievalUrl.length() <= 0) { result = "{'message':'OK','data':'" + "data.retrieval.url is empty" + "'}"; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java index 01ed4d2f..a28a5fb5 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java @@ -162,8 +162,10 @@ public class AccountSet implements Transactional, MerkleProvable { * * 只有最新版本的账户才能可写的,其它都是只读; * - * @param address 账户地址; - * @param version 账户版本;如果指定为 -1,则返回最新版本; + * @param address + * 账户地址; + * @param version + * 账户版本;如果指定为 -1,则返回最新版本; * @return */ public BaseAccount getAccount(Bytes address, long version) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java index 5a302ca8..c4a94ee6 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java @@ -4,10 +4,11 @@ import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.ledger.AccountHeader; import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesValueEntry; +import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.ContractInfo; import com.jd.blockchain.utils.Bytes; -public class ContractAccount implements AccountHeader { +public class ContractAccount implements ContractInfo { private static final Bytes CONTRACT_INFO_PREFIX = Bytes.fromString("INFO" + LedgerConsts.KEY_SEPERATOR); @@ -43,7 +44,7 @@ public class ContractAccount implements AccountHeader { } public long setChaincode(byte[] chaincode, long version) { - BytesValue bytesValue = BytesValueEntry.fromBytes(chaincode); + BytesValue bytesValue = BytesData.fromBytes(chaincode); return accBase.setBytes(CHAIN_CODE_KEY, bytesValue, version); } @@ -60,18 +61,18 @@ public class ContractAccount implements AccountHeader { } public long setProperty(Bytes key, String value, long version) { - BytesValue bytesValue = BytesValueEntry.fromText(value); + BytesValue bytesValue = BytesData.fromText(value); return accBase.setBytes(encodePropertyKey(key), bytesValue, version); } public String getProperty(Bytes key) { BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key)); - return BytesValueEntry.toText(bytesValue); + return BytesData.toText(bytesValue); } public String getProperty(Bytes key, long version) { BytesValue bytesValue = accBase.getBytes(encodePropertyKey(key), version); - return BytesValueEntry.toText(bytesValue); + return BytesData.toText(bytesValue); } private Bytes encodePropertyKey(Bytes key) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java index 4d23ec27..792ca704 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java @@ -6,7 +6,7 @@ import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.ledger.AccountHeader; import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesValueEntry; +import com.jd.blockchain.ledger.BytesData; import com.jd.blockchain.ledger.KVDataEntry; import com.jd.blockchain.ledger.KVDataObject; import com.jd.blockchain.utils.Bytes; @@ -49,15 +49,15 @@ public class DataAccount implements AccountHeader, MerkleProvable { public long setBytes(Bytes key, String value, long version) { - BytesValue bytesValue = BytesValueEntry.fromText(value); + BytesValue bytesValue = BytesData.fromText(value); return baseAccount.setBytes(key, bytesValue, version); } public long setBytes(Bytes key, byte[] value, long version) { - BytesValue bytesValue = BytesValueEntry.fromBytes(value); + BytesValue bytesValue = BytesData.fromBytes(value); return baseAccount.setBytes(key, bytesValue, version); } - + /** * Return the latest version entry associated the specified key; If the key * doesn't exist, then return -1; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java index 9b653ce8..33f589c5 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java @@ -1,8 +1,8 @@ package com.jd.blockchain.ledger.core; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.ledger.*; + +import java.util.List; /** * 事务上下文; @@ -28,22 +28,43 @@ public interface LedgerTransactionContext { /** * 提交对账本数据的修改,以指定的交易状态提交交易; - * + * * @param txResult + * * @return */ LedgerTransaction commit(TransactionState txResult); /** - * 抛弃对账本数据的修改,以指定的交易状态提交交易;
+ * 提交对账本数据的修改,以指定的交易状态提交交易; * + * @param txResult + * @param operationResults + * + * @return + */ + LedgerTransaction commit(TransactionState txResult, List operationResults); + + /** + * 抛弃对账本数据的修改,以指定的交易状态提交交易;
+ * * 通常来说,当在开启事务之后,修改账本或者尝试提交交易({@link #commit(TransactionState)})时发生错误,都应该抛弃数据,通过此方法记录一个表示错误状态的交易; - * + * * @param txResult * @return */ LedgerTransaction discardAndCommit(TransactionState txResult); + /** + * 抛弃对账本数据的修改,以指定的交易状态提交交易;
+ * + * 通常来说,当在开启事务之后,修改账本或者尝试提交交易({@link #commit(TransactionState, List)})时发生错误,都应该抛弃数据,通过此方法记录一个表示错误状态的交易; + * + * @param txResult + * @return + */ + LedgerTransaction discardAndCommit(TransactionState txResult, List operationResults); + /** * 回滚事务,抛弃本次事务的所有数据更新; */ diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java index da4e8f43..e1a0f567 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java @@ -1,8 +1,10 @@ package com.jd.blockchain.ledger.core; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; + public interface OperationHandle { /** @@ -14,8 +16,9 @@ public interface OperationHandle { boolean support(Class operationType); /** - * 解析和执行操作; - * + * 同步解析和执行操作; + * + * * @param op * 操作实例; * @param newBlockDataset @@ -24,8 +27,28 @@ public interface OperationHandle { * 交易请求上下文; * @param previousBlockDataset * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; + * + * @return 操作执行结果 */ - void process(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, + BytesValue process(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); +// /** +// * 异步解析和执行操作; +// * TODO 未来规划实现 +// * +// * +// * @param op +// * 操作实例; +// * @param newBlockDataset +// * 需要修改的新区块的数据集; +// * @param requestContext +// * 交易请求上下文; +// * @param previousBlockDataset +// * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; +// * +// * @return 操作执行结果 +// */ +// AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, +// LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java index f6faa1e0..b9cc88fd 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java @@ -3,7 +3,7 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesValueEntry; +import com.jd.blockchain.ledger.BytesData; import com.jd.blockchain.ledger.UserInfo; import com.jd.blockchain.utils.Bytes; @@ -50,12 +50,12 @@ public class UserAccount implements UserInfo { public long setDataPubKey(PubKey pubKey) { byte[] pkBytes = pubKey.toBytes(); - return baseAccount.setBytes(DATA_PUB_KEY, BytesValueEntry.fromBytes(pkBytes), -1); + return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), -1); } public long setDataPubKey(PubKey pubKey, long version) { byte[] pkBytes = pubKey.toBytes(); - return baseAccount.setBytes(DATA_PUB_KEY, BytesValueEntry.fromBytes(pkBytes), version); + return baseAccount.setBytes(DATA_PUB_KEY, BytesData.fromBytes(pkBytes), version); } public long setProperty(String key, String value, long version) { @@ -63,7 +63,7 @@ public class UserAccount implements UserInfo { } public long setProperty(Bytes key, String value, long version) { - return baseAccount.setBytes(encodePropertyKey(key), BytesValueEntry.fromText(value), version); + return baseAccount.setBytes(encodePropertyKey(key), BytesData.fromText(value), version); } public String getProperty(Bytes key) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/DefaultOperationHandleRegisteration.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/DefaultOperationHandleRegisteration.java index ec0504e4..1966c716 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/DefaultOperationHandleRegisteration.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/DefaultOperationHandleRegisteration.java @@ -3,16 +3,12 @@ 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; +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.DataAccountRegisterOperationHandle; import com.jd.blockchain.ledger.core.impl.handles.UserRegisterOperationHandle; @@ -21,18 +17,7 @@ import com.jd.blockchain.ledger.core.impl.handles.UserRegisterOperationHandle; public class DefaultOperationHandleRegisteration implements OperationHandleRegisteration { private List opHandles = new ArrayList<>(); - - -// private UserRegisterOperationHandle userRegHandle; -// -// private DataAccountRegisterOperationHandle dataAccRegHandle; -// -// private DataAccountKVSetOperationHandle dataAccKVSetHandle; -// -// private ContractCodeDeployOperationHandle contractDplHandle; -// -// private ContractEventSendOperationHandle contractEvtSendHandle; - + public DefaultOperationHandleRegisteration() { initDefaultHandles(); } @@ -40,25 +25,30 @@ public class DefaultOperationHandleRegisteration implements OperationHandleRegis /** * 针对不采用bean依赖注入的方式来处理; */ - private void initDefaultHandles(){ + private void initDefaultHandles() { opHandles.add(new DataAccountKVSetOperationHandle()); opHandles.add(new DataAccountRegisterOperationHandle()); opHandles.add(new UserRegisterOperationHandle()); opHandles.add(new ContractCodeDeployOperationHandle()); - opHandles.add(new ContractEventSendOperationHandle()); + opHandles.add(new JVMContractEventSendOperationHandle()); } - -// @PostConstruct -// private void init() { -// opHandles.add(dataAccKVSetHandle); -// opHandles.add(dataAccRegHandle); -// opHandles.add(userRegHandle); -// opHandles.add(contractDplHandle); -// opHandles.add(contractEvtSendHandle); -// } - /* (non-Javadoc) - * @see com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration#getHandle(java.lang.Class) + /** + * 以最高优先级插入一个操作处理器; + * + * @param handle + */ + public void insertAsTopPriority(OperationHandle handle) { + opHandles.remove(handle); + opHandles.add(0, handle); + } + + /* + * (non-Javadoc) + * + * @see + * com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration#getHandle( + * java.lang.Class) */ @Override public OperationHandle getHandle(Class operationType) { @@ -69,6 +59,5 @@ public class DefaultOperationHandleRegisteration implements OperationHandleRegis } throw new LedgerException("Unsupported operation type[" + operationType.getName() + "]!"); } - - + } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerInitializer.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerInitializer.java deleted file mode 100644 index 78fec379..00000000 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerInitializer.java +++ /dev/null @@ -1,85 +0,0 @@ -//package com.jd.blockchain.ledger.core.impl; -// -//import com.jd.blockchain.crypto.hash.HashDigest; -//import com.jd.blockchain.ledger.TransactionState; -//import com.jd.blockchain.ledger.LedgerBlock; -//import com.jd.blockchain.ledger.LedgerTransaction; -//import com.jd.blockchain.ledger.TransactionRequest; -//import com.jd.blockchain.ledger.core.LedgerDataSet; -//import com.jd.blockchain.ledger.core.LedgerEditor; -//import com.jd.blockchain.ledger.core.LedgerManage; -//import com.jd.blockchain.ledger.core.LedgerTransactionContext; -//import com.jd.blockchain.ledger.core.PrefixAppender; -//import com.jd.blockchain.storage.service.ExPolicyKVStorage; -//import com.jd.blockchain.storage.service.KVStorageService; -//import com.jd.blockchain.storage.service.VersioningKVStorage; -//import com.jd.blockchain.storage.service.utils.BufferedKVStorage; -// -///** -// * 账本初始化;
-// * -// * 初始生成账本时,所有的KV数据先缓冲写入到内存中,待计算得到账本 hash 之后,再重写入到与账本hash相关的持久化存储; -// * -// * @author huanghaiquan -// * -// */ -//class LedgerInitializer implements LedgerEditor { -// -// private KVStorageService baseStorage; -// -// private GenesisLedgerStorageProxy ledgerStorageProxy; -// -// private BufferedKVStorage genesisBufferedStorage; -// -// private LedgerEditor genesisBlockEditor; -// -// private LedgerBlock genesisBlock; -// -// private LedgerManage ledgerManager; -// -// LedgerInitializer(LedgerEditor genesisBlockEditor, BufferedKVStorage bufferedStorage, -// GenesisLedgerStorageProxy ledgerStorageProxy, KVStorageService kvStorage, LedgerManage ledgerManager) { -// this.genesisBlockEditor = genesisBlockEditor; -// this.genesisBufferedStorage = bufferedStorage; -// this.ledgerStorageProxy = ledgerStorageProxy; -// this.baseStorage = kvStorage; -// -// this.ledgerManager = ledgerManager; -// } -// -// @Override -// public LedgerTransactionContext newTransaction(TransactionRequest txRequest) { -// return genesisBlockEditor.newTransaction(txRequest); -// } -// -// @Override -// public LedgerBlock prepare() { -// // create genesis block; -// genesisBlock = genesisBlockEditor.prepare(); -// -// return genesisBlock; -// } -// -// @Override -// public void commit() { -// // commit data of editor; it will flush data to genesisBufferedStorage; -// genesisBlockEditor.commit(); -// -// // redirect persistence to storage which created for this new ledger with ledger hash; -// HashDigest ledgerHash = genesisBlock.getHash(); -// String ledgerPrefix =LedgerManager.getLedgerStoragePrefix(ledgerHash); -// ExPolicyKVStorage ledgerExStorage = PrefixAppender.prefix(ledgerPrefix, baseStorage.getExPolicyKVStorage()); -// VersioningKVStorage ledgerVerStorage = PrefixAppender.prefix(ledgerPrefix, baseStorage.getVersioningKVStorage()); -// -// // ready to persistent; -// ledgerStorageProxy.setPersistentStorage(ledgerExStorage, ledgerVerStorage); -// -// // flush output; -// genesisBufferedStorage.flush(); -// } -// -// @Override -// public void cancel() { -// genesisBlockEditor.cancel(); -// } -//} \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java index 66fbda39..13625600 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java @@ -5,19 +5,7 @@ import java.util.List; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.AccountHeader; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; -import com.jd.blockchain.ledger.KVDataVO; -import com.jd.blockchain.ledger.KVInfoVO; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInfo; -import com.jd.blockchain.ledger.LedgerMetadata; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.UserInfo; +import com.jd.blockchain.ledger.*; import com.jd.blockchain.ledger.core.ContractAccountSet; import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.DataAccountSet; @@ -276,15 +264,15 @@ public class LedgerQueryService implements BlockchainQueryService { KVDataEntry[] entries = new KVDataEntry[keys.length]; long ver; for (int i = 0; i < entries.length; i++) { - ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); + final String currKey = keys[i]; - dataAccount.getBytes(Bytes.fromString(keys[i]), 1); + ver = dataAccount.getDataVersion(Bytes.fromString(currKey)); if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); + entries[i] = new KVDataObject(currKey, -1, null); } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); - entries[i] = new KVDataObject(keys[i], ver, value); + BytesValue value = dataAccount.getBytes(Bytes.fromString(currKey), ver); + entries[i] = new KVDataObject(currKey, ver, value); } } @@ -367,7 +355,7 @@ public class LedgerQueryService implements BlockchainQueryService { } @Override - public AccountHeader getContract(HashDigest ledgerHash, String address) { + public ContractInfo getContract(HashDigest ledgerHash, String address) { LedgerRepository ledger = ledgerService.getLedger(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java index 349e3040..6e231b44 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java @@ -1,8 +1,12 @@ package com.jd.blockchain.ledger.core.impl; +import java.util.Arrays; +import java.util.Comparator; + import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.DigitalSignature; import com.jd.blockchain.ledger.LedgerTransaction; +import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionState; @@ -23,6 +27,8 @@ public class LedgerTransactionData implements LedgerTransaction { private long blockHeight; + private OperationResult[] operationResults; + // private HashDigest adminAccountHash; // // private HashDigest userAccountSetHash; @@ -49,7 +55,7 @@ public class LedgerTransactionData implements LedgerTransaction { * 交易级的系统快照; */ public LedgerTransactionData(long blockHeight, TransactionRequest txReq, TransactionState execState, - TransactionStagedSnapshot txSnapshot) { + TransactionStagedSnapshot txSnapshot, OperationResult... opResults) { this.blockHeight = blockHeight; // this.txSnapshot = txSnapshot == null ? new TransactionStagedSnapshot() : txSnapshot; this.txSnapshot = txSnapshot; @@ -57,6 +63,15 @@ public class LedgerTransactionData implements LedgerTransaction { this.endpointSignatures = txReq.getEndpointSignatures(); this.nodeSignatures = txReq.getNodeSignatures(); this.executionState = execState; + if (opResults != null) { + Arrays.sort(opResults, new Comparator() { + @Override + public int compare(OperationResult o1, OperationResult o2) { + return o1.getIndex() - o2.getIndex(); + } + }); + } + this.operationResults = opResults; } @Override @@ -74,6 +89,11 @@ public class LedgerTransactionData implements LedgerTransaction { return executionState; } + @Override + public OperationResult[] getOperationResults() { + return operationResults; + } + @Override public TransactionContent getTransactionContent() { return this.transactionContent; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java index 5bb29512..af9294bf 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java @@ -1,5 +1,6 @@ package com.jd.blockchain.ledger.core.impl; +import java.util.List; import java.util.Stack; import com.jd.blockchain.binaryproto.BinaryProtocol; @@ -351,6 +352,11 @@ public class LedgerTransactionalEditor implements LedgerEditor { @Override public LedgerTransaction commit(TransactionState txResult) { + return commit(txResult, null); + } + + @Override + public LedgerTransaction commit(TransactionState txResult, List operationResults) { checkTxState(); // capture snapshot @@ -359,7 +365,8 @@ public class LedgerTransactionalEditor implements LedgerEditor { // LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, // txResult, txDataSnapshot); - LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null); + + LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null, operationResultArray(operationResults)); this.txset.add(tx); // this.txset.commit(); @@ -377,6 +384,11 @@ public class LedgerTransactionalEditor implements LedgerEditor { @Override public LedgerTransaction discardAndCommit(TransactionState txResult) { + return discardAndCommit(txResult, null); + } + + @Override + public LedgerTransaction discardAndCommit(TransactionState txResult, List operationResults) { checkTxState(); // 未处理 @@ -385,7 +397,7 @@ public class LedgerTransactionalEditor implements LedgerEditor { // TransactionStagedSnapshot txDataSnapshot = takeSnapshot(); // LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, // txResult, txDataSnapshot); - LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null); + LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null, operationResultArray(operationResults)); this.txset.add(tx); // this.txset.commit(); @@ -410,6 +422,15 @@ public class LedgerTransactionalEditor implements LedgerEditor { return txDataSnapshot; } + private OperationResult[] operationResultArray(List operationResults) { + OperationResult[] operationResultArray = null; + if (operationResults != null && !operationResults.isEmpty()) { + operationResultArray = new OperationResult[operationResults.size()]; + operationResults.toArray(operationResultArray); + } + return operationResultArray; + } + @Override public void rollback() { if (this.rollbacked) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java index dc2cb787..b4795c01 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java @@ -3,16 +3,17 @@ package com.jd.blockchain.ledger.core.impl; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.concurrent.CompletableFuture; -import com.jd.blockchain.ledger.core.impl.handles.ContractEventSendOperationHandle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.OperationResult; +import com.jd.blockchain.ledger.OperationResultData; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -30,7 +31,7 @@ import com.jd.blockchain.utils.Bytes; public class TransactionBatchProcessor implements TransactionBatchProcess { private static final Logger LOGGER = LoggerFactory.getLogger(TransactionBatchProcessor.class); - + private LedgerService ledgerService; private LedgerEditor newBlockEditor; @@ -76,8 +77,11 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { // 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上; LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); TransactionState result; - List> contractReturn = new ArrayList<>(); + + List operationResults = new ArrayList<>(); + try { + LedgerDataSet dataset = txCtx.getDataSet(); TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request); // TODO: 验证签名者的有效性; @@ -103,46 +107,37 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { } }; OperationHandle opHandle; + int opIndex = 0; for (Operation op : ops) { opHandle = opHandles.getHandle(op.getClass()); - // 合约执行需要填充执行结果 - if (opHandle instanceof ContractEventSendOperationHandle) { - CompletableFuture currContractReturn = new CompletableFuture<>(); - contractReturn.add(currContractReturn); - ((ContractEventSendOperationHandle) opHandle).process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService, currContractReturn); - } else { - opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService); + BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService); + if (opResult != null) { + operationResults.add(new OperationResultData(opIndex, opResult)); } + opIndex++; } // 提交交易(事务); result = TransactionState.SUCCESS; - txCtx.commit(result); + + txCtx.commit(result, operationResults); } catch (LedgerException e) { // TODO: 识别更详细的异常类型以及执行对应的处理; result = TransactionState.LEDGER_ERROR; - txCtx.discardAndCommit(TransactionState.LEDGER_ERROR); + txCtx.discardAndCommit(TransactionState.LEDGER_ERROR, operationResults); LOGGER.warn(String.format("Transaction rollback caused by the ledger exception! --[TxHash=%s] --%s", request.getHash().toBase58(), e.getMessage()), e); } catch (Exception e) { result = TransactionState.SYSTEM_ERROR; - txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR); + txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); LOGGER.warn(String.format("Transaction rollback caused by the system exception! --[TxHash=%s] --%s", request.getHash().toBase58(), e.getMessage()), e); } TxResponseHandle resp = new TxResponseHandle(request, result); - if (!contractReturn.isEmpty()) { - // 获取结果中的字符串 - String[] returnValue = new String[contractReturn.size()]; - try { - for (int i = 0; i < contractReturn.size(); i++) { - returnValue[i] = contractReturn.get(i).get(); - } - resp.setContractReturn(returnValue); - } catch (Exception e) { - throw new IllegalStateException(e); - } + if (!operationResults.isEmpty()) { + OperationResult[] operationResultArray = new OperationResult[operationResults.size()]; + resp.setOperationResults(operationResults.toArray(operationResultArray)); } responseList.add(resp); @@ -224,7 +219,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { private TransactionState result; - private String[] contractReturn; + private OperationResult[] operationResults; public TxResponseHandle(TransactionRequest request, TransactionState result) { this.request = request; @@ -257,12 +252,12 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { } @Override - public String[] getContractReturn() { - return contractReturn; + public OperationResult[] getOperationResults() { + return operationResults; } - public void setContractReturn(String[] contractReturn) { - this.contractReturn = contractReturn; + public void setOperationResults(OperationResult[] operationResults) { + this.operationResults = operationResults; } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractEventSendOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java similarity index 66% rename from source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractEventSendOperationHandle.java rename to source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java index a8882d5d..40f6e2c2 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractEventSendOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java @@ -1,13 +1,10 @@ package com.jd.blockchain.ledger.core.impl.handles; -import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; - import org.springframework.stereotype.Service; import com.jd.blockchain.contract.LocalContractEventContext; 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.BytesValue; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.Operation; @@ -20,33 +17,17 @@ import com.jd.blockchain.ledger.core.TransactionRequestContext; import com.jd.blockchain.ledger.core.impl.LedgerQueryService; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; - @Service -public class ContractEventSendOperationHandle implements OperationHandle { - - private static final ContractEngine JVM_ENGINE; - - static { - JVM_ENGINE = ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine(); - } - - @Override - public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, - LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { - process(op, dataset, requestContext, previousBlockDataset, opHandleContext, ledgerService, null); - } +public abstract class AbtractContractEventHandle implements OperationHandle { @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 contractReturn) { - + @Override + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { ContractEventSendOperation contractOP = (ContractEventSendOperation) op; // 先从账本校验合约的有效性; // 注意:必须在前一个区块的数据集中进行校验,因为那是经过共识的数据;从当前新区块链数据集校验则会带来攻击风险:未经共识的合约得到执行; @@ -73,16 +54,15 @@ public class ContractEventSendOperationHandle implements OperationHandle { 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 contractCode = loadContractCode(contract); // 处理合约事件; - contractCode.processEvent(localContractEventContext, contractReturn); + return contractCode.processEvent(localContractEventContext); } + + protected abstract ContractCode loadContractCode(ContractAccount contract); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java index fc84830f..e18c9304 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java @@ -1,5 +1,8 @@ package com.jd.blockchain.ledger.core.impl.handles; +import org.springframework.stereotype.Service; + +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.LedgerDataSet; @@ -8,22 +11,28 @@ import com.jd.blockchain.ledger.core.OperationHandle; import com.jd.blockchain.ledger.core.TransactionRequestContext; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; -import org.springframework.stereotype.Service; - @Service public class ContractCodeDeployOperationHandle implements OperationHandle { @Override - public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { ContractCodeDeployOperation contractOP = (ContractCodeDeployOperation) op; // TODO: 校验合约代码的正确性; // TODO: 请求者应该提供合约账户的公钥签名,已确定注册的地址的唯一性; + dataset.getContractAccountSet().deploy(contractOP.getContractID().getAddress(), contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode()); + + return null; } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { +// return null; +// } + @Override public boolean support(Class operationType) { return ContractCodeDeployOperation.class.isAssignableFrom(operationType); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java index 162f3408..5a673722 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java @@ -5,23 +5,7 @@ import java.util.List; import com.jd.blockchain.contract.LedgerContext; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.AccountHeader; -import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesValueEntry; -import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.DataAccountRegisterOperation; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVInfoVO; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInfo; -import com.jd.blockchain.ledger.LedgerMetadata; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.Operation; -import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.UserInfo; -import com.jd.blockchain.ledger.UserRegisterOperation; +import com.jd.blockchain.ledger.*; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; import com.jd.blockchain.transaction.BlockchainQueryService; import com.jd.blockchain.transaction.DataAccountKVSetOperationBuilder; @@ -186,7 +170,7 @@ public class ContractLedgerContext implements LedgerContext { } @Override - public AccountHeader getContract(HashDigest ledgerHash, String address) { + public ContractInfo getContract(HashDigest ledgerHash, String address) { return innerQueryService.getContract(ledgerHash, address); } @@ -279,7 +263,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromText(value); + BytesValue bytesValue = BytesData.fromText(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -287,7 +271,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromBytes(value); + BytesValue bytesValue = BytesData.fromBytes(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -295,7 +279,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromInt64(value); + BytesValue bytesValue = BytesData.fromInt64(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -312,7 +296,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromJSON(value); + BytesValue bytesValue = BytesData.fromJSON(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -320,7 +304,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromXML(value); + BytesValue bytesValue = BytesData.fromXML(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -328,7 +312,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromBytes(value); + BytesValue bytesValue = BytesData.fromBytes(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -336,7 +320,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromImage(value); + BytesValue bytesValue = BytesData.fromImage(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; @@ -344,7 +328,7 @@ public class ContractLedgerContext implements LedgerContext { @Override public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromTimestamp(value); + BytesValue bytesValue = BytesData.fromTimestamp(value); this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion); handle(op); return this; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java index 4331c29c..c07dd628 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java @@ -1,33 +1,44 @@ package com.jd.blockchain.ledger.core.impl.handles; -import com.jd.blockchain.binaryproto.BinaryProtocol; +import org.springframework.stereotype.Service; + import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.DataAccountKVSetOperation.KVWriteEntry; import com.jd.blockchain.ledger.Operation; -import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.ledger.core.DataAccount; +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.OperationHandleContext; import com.jd.blockchain.utils.Bytes; -import org.springframework.stereotype.Service; @Service -public class DataAccountKVSetOperationHandle implements OperationHandle{ +public class DataAccountKVSetOperationHandle implements OperationHandle { static { DataContractRegistry.register(BytesValue.class); } @Override - public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { DataAccountKVSetOperation kvWriteOp = (DataAccountKVSetOperation) op; DataAccount account = dataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); - KVWriteEntry[] writeset = kvWriteOp.getWriteSet(); - for (KVWriteEntry kvw : writeset) { + KVWriteEntry[] writeSet = kvWriteOp.getWriteSet(); + for (KVWriteEntry kvw : writeSet) { +// byte[] value = BinaryProtocol.encode(kvw.getValue(), BytesValue.class); account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); } + return null; } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { +// return null; +// } + @Override public boolean support(Class operationType) { return DataAccountKVSetOperation.class.isAssignableFrom(operationType); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java index c4d3fd61..69337dfa 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java @@ -1,6 +1,9 @@ package com.jd.blockchain.ledger.core.impl.handles; +import org.springframework.stereotype.Service; + import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataAccountRegisterOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.LedgerDataSet; @@ -9,23 +12,28 @@ import com.jd.blockchain.ledger.core.OperationHandle; import com.jd.blockchain.ledger.core.TransactionRequestContext; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; -import org.springframework.stereotype.Service; - @Service -public class DataAccountRegisterOperationHandle implements OperationHandle{ +public class DataAccountRegisterOperationHandle implements OperationHandle { @Override - public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op; BlockchainIdentity bid = dataAccountRegOp.getAccountID(); - + //TODO: 校验用户身份; - + //TODO: 请求者应该提供数据账户的公钥签名,已确定注册的地址的唯一性; dataset.getDataAccountSet().register(bid.getAddress(), bid.getPubKey(), null); + + return null; } +// @Override +// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { +// return null; +// } + @Override public boolean support(Class operationType) { return DataAccountRegisterOperation.class.isAssignableFrom(operationType); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java new file mode 100644 index 00000000..a5b592ab --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java @@ -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 asyncProcess(Operation op, LedgerDataSet newBlockDataset, +// TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, +// OperationHandleContext handleContext, LedgerService ledgerService) { +// // TODO Auto-generated method stub +// return null; +// } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java index aef14906..f583e8cd 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java @@ -1,6 +1,7 @@ package com.jd.blockchain.ledger.core.impl.handles; import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.UserRegisterOperation; import com.jd.blockchain.ledger.core.LedgerDataSet; @@ -8,15 +9,24 @@ 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.OperationHandleContext; +import com.jd.blockchain.utils.Bytes; -public class UserRegisterOperationHandle implements OperationHandle{ + +public class UserRegisterOperationHandle implements OperationHandle { @Override - public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { + + UserRegisterOperation userRegOp = (UserRegisterOperation) op; BlockchainIdentity bid = userRegOp.getUserID(); - dataset.getUserAccountSet().register(bid.getAddress(), bid.getPubKey()); + + Bytes userAddress = bid.getAddress(); + + dataset.getUserAccountSet().register(userAddress, bid.getPubKey()); + + return null; } @Override diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/BaseAccountTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/BaseAccountTest.java index ac9f50b1..4a641b7d 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/BaseAccountTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/BaseAccountTest.java @@ -12,7 +12,7 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.BytesValueEntry; +import com.jd.blockchain.ledger.BytesData; import com.jd.blockchain.ledger.core.BaseAccount; import com.jd.blockchain.ledger.core.CryptoConfig; import com.jd.blockchain.storage.service.utils.MemoryKVStorage; @@ -53,33 +53,33 @@ public class BaseAccountTest { assertFalse(baseAccount.isReadonly()); // 在空白状态下写入数据; - long v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), 0); + long v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 0); // 预期失败; assertEquals(-1, v); - v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), 1); + v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), 1); // 预期失败; assertEquals(-1, v); - v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A"), -1); + v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A"), -1); // 预期成功; assertEquals(0, v); - v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A-1"), -1); + v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A-1"), -1); // 已经存在版本,指定版本号-1,预期导致失败; assertEquals(-1, v); baseAccount.commit(); v = 0; for (int i = 0; i < 10; i++) { - long s = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A_" + i), v); + long s = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + i), v); baseAccount.commit(); // 预期成功; assertEquals(v + 1, s); v++; } - v = baseAccount.setBytes(Bytes.fromString("A"), BytesValueEntry.fromText("VALUE_A_" + v), v + 1); + v = baseAccount.setBytes(Bytes.fromString("A"), BytesData.fromText("VALUE_A_" + v), v + 1); // 预期成功; assertEquals(-1, v); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingHandle.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingHandle.java new file mode 100644 index 00000000..c0a31321 --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingHandle.java @@ -0,0 +1,50 @@ +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 contractInstances = new ConcurrentHashMap(); + + @Override + protected ContractCode loadContractCode(ContractAccount contract) { + return contractInstances.get(contract.getAddress()); + } + + public ContractCode setup(Bytes address, Class contractIntf, T instance) { + ContractCodeInstance contract = new ContractCodeInstance(address, 0, contractIntf, instance); + contractInstances.put(address, contract); + return contract; + } + + private static class ContractCodeInstance extends AbstractContractCode { + + private T instance; + + public ContractCodeInstance(Bytes address, long version, Class 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; + } + + } + +} diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java new file mode 100644 index 00000000..eab81350 --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java @@ -0,0 +1,223 @@ +package test.com.jd.blockchain.ledger; + +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.mockito.Mockito; + +import com.jd.blockchain.binaryproto.BinaryProtocol; +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.EndpointRequest; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInitSetting; +import com.jd.blockchain.ledger.LedgerTransaction; +import com.jd.blockchain.ledger.NodeRequest; +import com.jd.blockchain.ledger.OperationResult; +import com.jd.blockchain.ledger.TransactionContent; +import com.jd.blockchain.ledger.TransactionContentBody; +import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.ledger.TransactionRequestBuilder; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.UserRegisterOperation; +import com.jd.blockchain.ledger.core.LedgerDataSet; +import com.jd.blockchain.ledger.core.LedgerEditor; +import com.jd.blockchain.ledger.core.LedgerRepository; +import com.jd.blockchain.ledger.core.LedgerTransactionContext; +import com.jd.blockchain.ledger.core.UserAccount; +import com.jd.blockchain.ledger.core.impl.DefaultOperationHandleRegisteration; +import com.jd.blockchain.ledger.core.impl.LedgerManager; +import com.jd.blockchain.ledger.core.impl.LedgerTransactionalEditor; +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.transaction.TxBuilder; +import com.jd.blockchain.utils.Bytes; + +public class ContractInvokingTest { + static { + DataContractRegistry.register(TransactionContent.class); + DataContractRegistry.register(TransactionContentBody.class); + DataContractRegistry.register(TransactionRequest.class); + DataContractRegistry.register(NodeRequest.class); + DataContractRegistry.register(EndpointRequest.class); + DataContractRegistry.register(TransactionResponse.class); + DataContractRegistry.register(UserRegisterOperation.class); + } + + private static final String LEDGER_KEY_PREFIX = "LDG://"; + + private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate(); + + // 采用基于内存的 Storage; + private MemoryKVStorage storage = new MemoryKVStorage(); + + @Test + public void test() { + // 初始化账本到指定的存储库; + HashDigest ledgerHash = initLedger(storage, parti0, parti1, parti2, parti3); + + // 重新加载账本; + LedgerManager ledgerManager = new LedgerManager(); + LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage); + + // 创建合约处理器; + 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); + + // 发布指定地址合约 + deploy(ledgerRepo, ledgerManager, opReg, ledgerHash, contractKey); + + + // 创建新区块的交易处理器; + LedgerBlock preBlock = ledgerRepo.getLatestBlock(); + LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(preBlock); + + // 加载合约 + LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, + opReg, ledgerManager); + + // 构建基于接口调用合约的交易请求,用于测试合约调用; + TxBuilder txBuilder = new TxBuilder(ledgerHash); + TestContract contractProxy = txBuilder.contract(contractAddress, TestContract.class); + TestContract contractProxy1 = txBuilder.contract(contractAddress, TestContract.class); + + String asset = "AK"; + long issueAmount = new Random().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[] expectedRetnBytes = BinaryProtocol.encode(BytesData.fromInt64(issueAmount), BytesValue.class); + byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); + assertArrayEquals(expectedRetnBytes, reallyRetnBytes); + + // 提交区块; + 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()); + + reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class); + assertArrayEquals(expectedRetnBytes, reallyRetnBytes); + + } + + private void deploy(LedgerRepository ledgerRepo, LedgerManager ledgerManager, + DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, + BlockchainKeypair contractKey) { + // 创建新区块的交易处理器; + LedgerBlock preBlock = ledgerRepo.getLatestBlock(); + LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(preBlock); + + // 加载合约 + LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, + opReg, ledgerManager); + + // 构建基于接口调用合约的交易请求,用于测试合约调用; + TxBuilder txBuilder = new TxBuilder(ledgerHash); + txBuilder.contracts().deploy(contractKey.getIdentity(), chainCode()); + TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); + txReqBuilder.signAsEndpoint(parti0); + txReqBuilder.signAsNode(parti0); + TransactionRequest txReq = txReqBuilder.buildRequest(); + + TransactionResponse resp = txbatchProcessor.schedule(txReq); + OperationResult[] opResults = resp.getOperationResults(); + assertNull(opResults); + + // 提交区块; + TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare(); + txResultHandle.commit(); + } + + private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) { + // 创建初始化配置; + LedgerInitSetting initSetting = LedgerTestUtils.createLedgerInitSetting(partiKeys); + + // 创建账本; + LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); + + TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null); + LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq); + LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); + + for (int i = 0; i < partiKeys.length; i++) { + UserAccount userAccount = ldgDS.getUserAccountSet().register(partiKeys[i].getAddress(), + partiKeys[i].getPubKey()); + userAccount.setProperty("Name", "参与方-" + i, -1); + userAccount.setProperty("Share", "" + (10 + i), -1); + } + + LedgerTransaction tx = genisisTxCtx.commit(TransactionState.SUCCESS); + + assertEquals(genesisTxReq.getTransactionContent().getHash(), tx.getTransactionContent().getHash()); + assertEquals(0, tx.getBlockHeight()); + + LedgerBlock block = ldgEdt.prepare(); + + assertEquals(0, block.getHeight()); + assertNotNull(block.getHash()); + assertNull(block.getPreviousHash()); + + assertEquals(block.getHash(), block.getLedgerHash()); + + // 提交数据,写入存储; + ldgEdt.commit(); + + HashDigest ledgerHash = block.getHash(); + return ledgerHash; + } + + private byte[] chainCode() { + byte[] chainCode = new byte[1024]; + new Random().nextBytes(chainCode); + return chainCode; + } +} diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java index 5018ede7..c7f3d6e6 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java @@ -18,7 +18,7 @@ import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesValueType; +import com.jd.blockchain.ledger.DataType; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInitSetting; import com.jd.blockchain.ledger.LedgerTransaction; @@ -68,17 +68,17 @@ public class LedgerEditerTest { MemoryKVStorage storage = new MemoryKVStorage(); // 创建初始化配置; - LedgerInitSetting initSetting = createLedgerInitSetting(); + LedgerInitSetting initSetting = LedgerTestUtils.createLedgerInitSetting(); // 创建账本; return LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); } private LedgerTransactionContext createGenisisTx(LedgerEditor ldgEdt) { - TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest(null, signatureFunction); + TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null); LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq); - + return txCtx; } @@ -88,8 +88,7 @@ public class LedgerEditerTest { LedgerEditor ldgEdt = createLedgerInitEditor(); LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt); LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); - - + AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); BlockchainKeypair dataKP = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); @@ -109,7 +108,7 @@ public class LedgerEditerTest { // 验证数据读写的一致性; BytesValue bytes = dataAccount.getBytes("A"); - assertEquals(BytesValueType.TEXT, bytes.getType()); + assertEquals(DataType.TEXT, bytes.getType()); String textValue = bytes.getValue().toUTF8String(); assertEquals("abc", textValue); } @@ -147,42 +146,5 @@ public class LedgerEditerTest { ldgEdt.commit(); } - - private LedgerInitSetting createLedgerInitSetting() { - SignatureFunction signFunc = Crypto.getSignatureFunction("ED25519"); - - CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; - for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { - supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); - } - - CryptoConfig defCryptoSetting = new CryptoConfig(); - defCryptoSetting.setSupportedProviders(supportedProviders); - defCryptoSetting.setAutoVerifyHash(true); - defCryptoSetting.setHashAlgorithm(ClassicAlgorithm.SHA256); - - LedgerInitSettingData initSetting = new LedgerInitSettingData(); - - initSetting.setLedgerSeed(BytesUtils.toBytes("A Test Ledger seed!", "UTF-8")); - initSetting.setCryptoSetting(defCryptoSetting); - ConsensusParticipantData[] parties = new ConsensusParticipantData[2]; - parties[0] = new ConsensusParticipantData(); - parties[0].setId(0); - parties[0].setName("John"); - AsymmetricKeypair kp0 = signFunc.generateKeypair(); - parties[0].setPubKey(kp0.getPubKey()); - parties[0].setAddress(AddressEncoding.generateAddress(kp0.getPubKey()).toBase58()); - parties[0].setHostAddress(new NetworkAddress("192.168.1.6", 9000)); - - parties[1] = new ConsensusParticipantData(); - parties[1].setId(1); - parties[1].setName("John"); - AsymmetricKeypair kp1 = signFunc.generateKeypair(); - parties[1].setPubKey(kp1.getPubKey()); - parties[1].setAddress(AddressEncoding.generateAddress(kp1.getPubKey()).toBase58()); - parties[1].setHostAddress(new NetworkAddress("192.168.1.7", 9000)); - initSetting.setConsensusParticipants(parties); - - return initSetting; - } + } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java index cdbece82..9639602c 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java @@ -83,13 +83,13 @@ public class LedgerManagerTest { LedgerEditor ldgEdt = ledgerManager.newLedger(initSetting, storage); // 创建一个模拟的创世交易; - TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest(null, signatureFunction); + TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null); // 记录交易,注册用户; LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq); LedgerDataSet ldgDS = txCtx.getDataSet(); BlockchainKeypair userKP = BlockchainKeyGenerator.getInstance().generate(); - ; + UserAccount userAccount = ldgDS.getUserAccountSet().register(userKP.getAddress(), userKP.getPubKey()); userAccount.setProperty("Name", "孙悟空", -1); userAccount.setProperty("Age", "10000", -1); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java index 52f050c4..3a631ad3 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java @@ -2,69 +2,103 @@ package test.com.jd.blockchain.ledger; import java.util.Random; -import com.jd.blockchain.crypto.AsymmetricKeypair; +import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.CryptoAlgorithm; import com.jd.blockchain.crypto.CryptoProvider; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; -import com.jd.blockchain.ledger.BlockchainIdentityData; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.CryptoSetting; -import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.LedgerInitSetting; import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.ledger.TransactionRequestBuilder; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.core.CryptoConfig; import com.jd.blockchain.ledger.core.impl.TransactionStagedSnapshot; +import com.jd.blockchain.transaction.ConsensusParticipantData; +import com.jd.blockchain.transaction.LedgerInitSettingData; import com.jd.blockchain.transaction.TransactionService; -import com.jd.blockchain.transaction.TxTemplate; +import com.jd.blockchain.transaction.TxBuilder; +import com.jd.blockchain.utils.io.BytesUtils; +import com.jd.blockchain.utils.net.NetworkAddress; public class LedgerTestUtils { - // private static ThreadLocalRandom rand = ThreadLocalRandom.current(); + public static final SignatureFunction ED25519_SIGN_FUNC = Crypto.getSignatureFunction("ED25519"); + + public static final CryptoAlgorithm ED25519 = ED25519_SIGN_FUNC.getAlgorithm(); private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), SMCryptoService.class.getName() }; private static Random rand = new Random(); - public static TransactionRequest createTxRequest(HashDigest ledgerHash) { - SignatureFunction signFunc = Crypto.getSignatureFunction("ED25519"); - return createTxRequest(ledgerHash, signFunc); + public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash) { + BlockchainKeypair key = BlockchainKeyGenerator.getInstance().generate(ED25519); + return createTxRequest_UserReg(ledgerHash, key); + } + + public static LedgerInitSetting createLedgerInitSetting() { + BlockchainKeypair[] partiKeys = new BlockchainKeypair[2]; + partiKeys[0] = BlockchainKeyGenerator.getInstance().generate(); + partiKeys[1] = BlockchainKeyGenerator.getInstance().generate(); + return createLedgerInitSetting(partiKeys); } - public static TransactionRequest createTxRequest(HashDigest ledgerHash, SignatureFunction signatureFunction) { - TxHandle txHandle = new TxHandle(); + public static LedgerInitSetting createLedgerInitSetting(BlockchainKeypair[] partiKeys) { + CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; + for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { + supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); + } + + CryptoConfig defCryptoSetting = new CryptoConfig(); + defCryptoSetting.setSupportedProviders(supportedProviders); + defCryptoSetting.setAutoVerifyHash(true); + defCryptoSetting.setHashAlgorithm(ClassicAlgorithm.SHA256); + + LedgerInitSettingData initSetting = new LedgerInitSettingData(); - TxTemplate txTemp = new TxTemplate(ledgerHash, txHandle); + initSetting.setLedgerSeed(BytesUtils.toBytes("A Test Ledger seed!", "UTF-8")); + initSetting.setCryptoSetting(defCryptoSetting); + ConsensusParticipantData[] parties = new ConsensusParticipantData[partiKeys.length]; + for (int i = 0; i < parties.length; i++) { + parties[i] = new ConsensusParticipantData(); + parties[i].setId(0); + parties[i].setName("Parti-" + i); + parties[i].setPubKey(partiKeys[i].getPubKey()); + parties[i].setAddress(AddressEncoding.generateAddress(partiKeys[i].getPubKey()).toBase58()); + parties[i].setHostAddress(new NetworkAddress("192.168.1." + (10 + i), 9000)); - AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); - PubKey pubKey = cryptoKeyPair.getPubKey(); - txTemp.users().register(new BlockchainIdentityData(pubKey)); - PreparedTransaction ptx = txTemp.prepare(); - ptx.sign(cryptoKeyPair); - ptx.commit(); - return txHandle.txRequest; + } + + initSetting.setConsensusParticipants(parties); + + return initSetting; + } + + public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash, BlockchainKeypair userKeypair) { + return createTxRequest_UserReg(ledgerHash, userKeypair, null); } -// public static TransactionRequest createContractEventTxRequest(HashDigest ledgerHash, -// SignatureFunction signatureFunction, String contractAddress, String event, byte[] args) { -// TxHandle txHandle = new TxHandle(); -// -// TxTemplate txTemp = new TxTemplate(ledgerHash, txHandle); -// -// txTemp.contractEvents().send(contractAddress, event, args); -// -// AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); -// PubKey pubKey = cryptoKeyPair.getPubKey(); -// txTemp.users().register(new BlockchainIdentityData(pubKey)); -// PreparedTransaction ptx = txTemp.prepare(); -// ptx.sign(cryptoKeyPair); -// ptx.commit(); -// return txHandle.txRequest; -// } + public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash, BlockchainKeypair userKeypair, + BlockchainKeypair gatewayKeypair) { + TxBuilder txBuilder = new TxBuilder(ledgerHash); + + txBuilder.users().register(userKeypair.getIdentity()); + + TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); + txReqBuilder.signAsEndpoint(userKeypair); + if (gatewayKeypair != null) { + txReqBuilder.signAsNode(gatewayKeypair); + } + + return txReqBuilder.buildRequest(); + } public static TransactionStagedSnapshot generateRandomSnapshot() { TransactionStagedSnapshot txDataSnapshot = new TransactionStagedSnapshot(); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTransactionDataTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTransactionDataTest.java index d99ed706..9e53ae24 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTransactionDataTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTransactionDataTest.java @@ -68,7 +68,7 @@ public class LedgerTransactionDataTest { long blockHeight = 9986L; data = new LedgerTransactionData(blockHeight, txRequestMessage, TransactionState.SUCCESS, - initTransactionStagedSnapshot()); + initTransactionStagedSnapshot(), null); HashDigest hash = new HashDigest(ClassicAlgorithm.SHA256, "zhangsan".getBytes()); HashDigest adminAccountHash = new HashDigest(ClassicAlgorithm.SHA256, "lisi".getBytes()); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContract.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContract.java new file mode 100644 index 00000000..4d9a5ccd --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContract.java @@ -0,0 +1,58 @@ +package test.com.jd.blockchain.ledger; + +import com.jd.blockchain.contract.Contract; +import com.jd.blockchain.contract.ContractEvent; + +@Contract +public interface TestContract { + + /** + * 发行资产; + * + * @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); +} diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContractImpl.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContractImpl.java new file mode 100644 index 00000000..3375f7f3 --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContractImpl.java @@ -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); +} diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java index 7b28c41e..72c8a848 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java @@ -1,392 +1,140 @@ -//package test.com.jd.blockchain.ledger; -// -//import static org.junit.Assert.assertArrayEquals; -//import static org.junit.Assert.assertEquals; -//import static org.junit.Assert.assertNotNull; -//import static org.junit.Assert.assertTrue; -// -//import java.io.File; -//import java.io.FileInputStream; -//import java.io.IOException; -//import java.io.InputStream; -//import java.net.URISyntaxException; -//import java.net.URL; -//import java.nio.file.Paths; -// -//import org.junit.Before; -//import org.junit.Test; -// -//import com.jd.blockchain.binaryproto.DataContractRegistry; -//import com.jd.blockchain.contract.model.ContractPath; -//import com.jd.blockchain.crypto.CryptoAlgorithm; -//import com.jd.blockchain.crypto.CryptoUtils; -//import com.jd.blockchain.crypto.asymmetric.CryptoKeyPair; -//import com.jd.blockchain.crypto.asymmetric.PubKey; -//import com.jd.blockchain.crypto.hash.HashDigest; -//import com.jd.blockchain.ledger.BlockchainKeyGenerator; -//import com.jd.blockchain.ledger.BlockchainKeyPair; -//import com.jd.blockchain.ledger.ContractCodeDeployOperation; -//import com.jd.blockchain.ledger.ContractEventSendOperation; -//import com.jd.blockchain.ledger.DataAccountKVSetOperation; -//import com.jd.blockchain.ledger.DataAccountRegisterOperation; -//import com.jd.blockchain.ledger.EndpointRequest; -//import com.jd.blockchain.ledger.LedgerBlock; -//import com.jd.blockchain.ledger.LedgerInitSetting; -//import com.jd.blockchain.ledger.LedgerTransaction; -//import com.jd.blockchain.ledger.NodeRequest; -//import com.jd.blockchain.ledger.TransactionBuilder; -//import com.jd.blockchain.ledger.TransactionContent; -//import com.jd.blockchain.ledger.TransactionContentBody; -//import com.jd.blockchain.ledger.TransactionRequest; -//import com.jd.blockchain.ledger.TransactionRequestBuilder; -//import com.jd.blockchain.ledger.TransactionResponse; -//import com.jd.blockchain.ledger.TransactionState; -//import com.jd.blockchain.ledger.UserRegisterOperation; -//import com.jd.blockchain.ledger.core.CryptoConfig; -//import com.jd.blockchain.ledger.core.DataAccountSet; -//import com.jd.blockchain.ledger.core.LedgerDataSet; -//import com.jd.blockchain.ledger.core.LedgerEditor; -//import com.jd.blockchain.ledger.core.LedgerRepository; -//import com.jd.blockchain.ledger.core.LedgerTransactionContext; -//import com.jd.blockchain.ledger.core.TransactionSet; -//import com.jd.blockchain.ledger.core.UserAccount; -//import com.jd.blockchain.ledger.core.impl.DefaultOperationHandleRegisteration; -//import com.jd.blockchain.ledger.core.impl.LedgerManager; -//import com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration; -//import com.jd.blockchain.ledger.core.impl.TransactionBatchProcessor; -//import com.jd.blockchain.ledger.data.AddressEncoding; -//import com.jd.blockchain.ledger.data.ConsensusParticipantData; -//import com.jd.blockchain.ledger.data.LedgerInitSettingData; -//import com.jd.blockchain.ledger.data.TxBuilder; -//import com.jd.blockchain.storage.service.utils.MemoryKVStorage; -// -//import my.utils.Bytes; -//import my.utils.io.BytesUtils; -//import my.utils.net.NetworkAddress; -// -//public class TransactionBatchProcessorTest { -// private HashDigest ledgerHash = null; -// BlockchainKeyPair userKey = BlockchainKeyGenerator.getInstance().generate(); -// BlockchainKeyPair dataKey = BlockchainKeyGenerator.getInstance().generate(); -// BlockchainKeyPair sponsorKey = BlockchainKeyGenerator.getInstance().generate(); -// BlockchainKeyPair gatewayKey = BlockchainKeyGenerator.getInstance().generate(); -// BlockchainKeyPair contractKey = BlockchainKeyGenerator.getInstance().generate(); -// TransactionRequest transactionRequest; -// String pubKeyVal = "jd.com"+Thread.currentThread(); -//// String userPubKeyVal = "this is user's pubKey"; -// byte[] chainCode; -// // 保存资产总数的键; -// private static final String KEY_TOTAL = "TOTAL"; -// //第二个参数; -// private static final String KEY_ABC = "abc"; -// // 采用基于内存的 Storage; -// MemoryKVStorage storage = new MemoryKVStorage(); -// -// @Before -// public void setUp(){ -// DataContractRegistry.register(TransactionContent.class); -// DataContractRegistry.register(TransactionContentBody.class); -// DataContractRegistry.register(TransactionRequest.class); -// DataContractRegistry.register(NodeRequest.class); -// DataContractRegistry.register(EndpointRequest.class); -// DataContractRegistry.register(TransactionResponse.class); -// DataContractRegistry.register(UserRegisterOperation.class); -// } -// -//// @After -// public void after() { -// //清理所有使用的临时文件; -// String outputPath = null; -// try { -// outputPath = ContractPath.getOutputPath(); -// }finally { -// deleteDir(new File(outputPath)); -// } -// } -// -// /** -// * 递归删除目录下的所有文件及子目录下所有文件 -// * @param dir 将要删除的文件目录 -// * @return boolean Returns "true" if all deletions were successful. -// * If a deletion fails, the method stops attempting to -// * delete and returns "false". -// */ -// private static boolean deleteDir(File dir) { -// if (dir.isDirectory()) { -// String[] children = dir.list(); -// //递归删除目录中的子目录下 -// for (int i=0; i${project.version} test
- \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractAware.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractAware.java new file mode 100644 index 00000000..87c51fec --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractAware.java @@ -0,0 +1,11 @@ +package com.jd.blockchain.contract; + +/** + * 合约实现 {@link ContractAware} 的子接口可以监听运行时的生命周期事件; + * + * @author huanghaiquan + * + */ +public interface ContractAware { + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractEventContext.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractEventContext.java index a24ba26d..e80a34b5 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractEventContext.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractEventContext.java @@ -1,11 +1,12 @@ package com.jd.blockchain.contract; +import java.util.Set; + import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValueList; import com.jd.blockchain.ledger.TransactionRequest; -import java.util.Set; - public interface ContractEventContext { @@ -42,7 +43,7 @@ public interface ContractEventContext { * * @return */ - byte[] getArgs(); + BytesValueList getArgs(); /** * 账本操作上下文; diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractException.java index 61ba347a..c5382d8e 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractException.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractException.java @@ -1,16 +1,17 @@ package com.jd.blockchain.contract; -public class ContractException extends RuntimeException { - +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()); - } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractAppLifecycleAwire.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractLifecycleAware.java similarity index 73% rename from source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractAppLifecycleAwire.java rename to source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractLifecycleAware.java index c8f4f8a9..881de255 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractAppLifecycleAwire.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractLifecycleAware.java @@ -7,7 +7,7 @@ package com.jd.blockchain.contract; * @author huanghaiquan * */ -public interface ContractAppLifecycleAwire extends ContractRuntimeAwire { +public interface ContractLifecycleAware extends ContractAware { void postConstruct(); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractRuntimeAwire.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractRuntimeAwire.java deleted file mode 100644 index eab96a41..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractRuntimeAwire.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.jd.blockchain.contract; - -/** - * 合约实现 {@link ContractRuntimeAwire} 的子接口可以监听运行时的生命周期事件; - * - * @author huanghaiquan - * - */ -public interface ContractRuntimeAwire { - -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java index da3297bf..e7cc92ef 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java @@ -1,196 +1,165 @@ -package com.jd.blockchain.contract; - -import com.jd.blockchain.binaryproto.BinaryProtocol; -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.consts.DataCodes; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.IllegalDataException; -import org.springframework.util.ReflectionUtils; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author zhaogw - * date 2019/5/16 18:05 - */ -public class ContractSerializeUtils { - public static Map> DATA_CONTRACT_MAP = new HashMap<>(); - public static final Integer[] PRIMITIVE_DATA_CODES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32, - DataCodes.CONTRACT_INT64, DataCodes.CONTRACT_BIG_INT,DataCodes.CONTRACT_TEXT, DataCodes.CONTRACT_BINARY }; - - /** - * serialize the Object[] by List list; - * @param objArr - * @param dataContractList - * @return - */ - public static byte[] serializeMethodParam(Object[] objArr,List dataContractList) { - byte[][] result = new byte[objArr.length][]; - //将method中形参转换为实体对象,每个形参都必须为@DataContract类型;每个形参使用系统的BinaryProtocol来进行序列化,如果有5个参数,则使用5次序列化; - int sum = 0; - - for(int i=0;i dataContractList) { - Object result[] = new Object[dataContractList.size()]; - ByteBuffer byteBuffer = ByteBuffer.allocate(params.length); - byteBuffer.put(params); - int paramNums = byteBuffer.getInt(0); - - if(paramNums != dataContractList.size()){ - throw new IllegalArgumentException("deserialize Method param. params'length in byte[] != method's param length"); - } - - int offsetPosition = (1 + dataContractList.size())*4; //start position of real data; - for(int i=0; i classObj = getDataIntf().get(dataContract.code()); - try { - result[i] = ReflectionUtils.invokeMethod(classObj.getMethod("getValue"),object); - } catch (NoSuchMethodException e) { - throw new IllegalStateException("no getValue(). detail="+e.getMessage()); - } - }else { - result[i] = object; - } - byteBuffer1.clear(); - } - - return result; - } - - - /** - * the param types that we can support; - * @param - * @return - */ - public static Map > getDataIntf(){ - DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT8, CONTRACT_INT8.class); - DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT16, CONTRACT_INT16.class); - DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT32, CONTRACT_INT32.class); - DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT64, CONTRACT_INT64.class); - DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class); - DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class); - DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIG_INT, CONTRACT_BIG_INT.class); - DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIZ_CONTENT, ContractBizContent.class); - return DATA_CONTRACT_MAP; - } - - public static boolean isPrimitiveType(int dataContractCode){ - return Arrays.asList(PRIMITIVE_DATA_CODES).contains(dataContractCode); - } - - private static Object regenObj(DataContract dataContract, Object object){ - if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT8.class)){ - - return (CONTRACT_INT8) () -> Byte.parseByte(object.toString()); - }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT16.class)){ - return (CONTRACT_INT16) () -> Short.parseShort(object.toString()); - }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT32.class)){ - return (CONTRACT_INT32) () -> Integer.parseInt(object.toString()); - }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT64.class)){ - return (CONTRACT_INT64) () -> Long.parseLong(object.toString()); - }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_TEXT.class)){ - return (CONTRACT_TEXT) () -> object.toString(); - }else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BINARY.class)){ - return (CONTRACT_BINARY) () -> (Bytes) object; - }else if(getDataIntf().get(dataContract.code()).equals(ContractBizContent.class)){ - ContractBizContent contractBizContent = (ContractBizContent)object; - return contractBizContent; - }else { - throw new IllegalDataException("cann't get new Object by dataContract and object."); - } - } - - /** - * get contractType(contain @DataContract) by primitive class type; - * some class type can be supported default (byte/char/int/long/String/Bytes, and so on). - * in other words, need not contain the @DataContract in its class for contract param's serialization or deserialization. - * @param classType - * @return - */ - private static Class getContractTypeByPrimitiveType(Class classType) { - if(classType.equals(byte.class) || classType.equals(Byte.class)){ - return CONTRACT_INT8.class; - }else if(classType.equals(char.class) || classType.equals(Character.class)){ - return CONTRACT_INT16.class; - }else if(classType.equals(int.class) || classType.equals(Integer.class)){ - return CONTRACT_INT32.class; - }else if(classType.equals(long.class) || classType.equals(Long.class)){ - return CONTRACT_INT64.class; - }else if(classType.equals(String.class)){ - return CONTRACT_TEXT.class; - }else if(classType.equals(Bytes.class)){ - return CONTRACT_BINARY.class; - }else { - throw new IllegalDataException(String.format("no support the classType=%s, please check @DataContract.",classType.toString())); - } - } - - public static DataContract parseDataContract(Class classType){ - DataContract dataContract = classType.getAnnotation(DataContract.class); - //if the param's class Type don't contain @DataContract, then check parameterAnnotations of this method. - if(dataContract == null){ - boolean canPass = false; - //if parameterAnnotations don't contain @DataContract, is it primitive type? - Class contractType = getContractTypeByPrimitiveType(classType); - dataContract = contractType.getAnnotation(DataContract.class); - } - if(!getDataIntf().containsKey(dataContract.code())){ - throw new IllegalArgumentException(String.format( - "for now, this @dataContract(code=%s) is forbidden in the param list.",dataContract.code())); - } - return dataContract; - } -} +//package com.jd.blockchain.contract; +// +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +// +//import com.jd.blockchain.binaryproto.BinaryProtocol; +//import com.jd.blockchain.binaryproto.DataContract; +//import com.jd.blockchain.binaryproto.DataContractRegistry; +//import com.jd.blockchain.contract.param.WRAP_BYTES; +//import com.jd.blockchain.contract.param.WRAP_INT; +//import com.jd.blockchain.contract.param.WRAP_LONG; +//import com.jd.blockchain.contract.param.WRAP_SHORT; +//import com.jd.blockchain.contract.param.WRAP_STRING; +//import com.jd.blockchain.ledger.BytesValue; +//import com.jd.blockchain.ledger.BytesValueList; +//import com.jd.blockchain.utils.io.BytesUtils; +// +//public class ContractSerializeUtils { +// +// final static int INT_LENGTH = 4; +// +// static Map, Class> MAP = new HashMap<>(); +// +// static { +// MAP.put(byte[].class, WRAP_BYTES.class); +// MAP.put(Short.class, WRAP_SHORT.class); +// MAP.put(short.class, WRAP_SHORT.class); +// MAP.put(Integer.class, WRAP_INT.class); +// MAP.put(int.class, WRAP_INT.class); +// MAP.put(Long.class, WRAP_LONG.class); +// MAP.put(long.class, WRAP_LONG.class); +// MAP.put(String.class, WRAP_STRING.class); +// +// DataContractRegistry.register(WRAP_BYTES.class); +// DataContractRegistry.register(WRAP_SHORT.class); +// DataContractRegistry.register(WRAP_INT.class); +// DataContractRegistry.register(WRAP_LONG.class); +// DataContractRegistry.register(WRAP_STRING.class); +// } +// +// public static boolean support(Class clazz) { +// if (clazz.isAnnotationPresent(DataContract.class) || MAP.containsKey(clazz)) { +// return true; +// } +// return false; +// } +// +// public static BytesValue serialize(Object data) { +// +// if (data == null) { +// return null; +// } +// +// Class clazz = data.getClass(); +// Class serialClass; +// Object wrapData = data; +// if (clazz.isAnnotationPresent(DataContract.class)) { +// serialClass = clazz; +// } else { +// // 判断类型是否可以序列化 +// Class wrapClass = MAP.get(clazz); +// if (wrapClass == null) { +// throw new IllegalArgumentException("There are Un-Support Type !!!"); +// } +// serialClass = wrapClass; +// +// if (wrapClass.equals(WRAP_BYTES.class)) { +// wrapData = (WRAP_BYTES) () -> (byte[]) data; +// } else if (wrapClass.equals(WRAP_INT.class)) { +// wrapData = (WRAP_INT) () -> (int) data; +// } else if (wrapClass.equals(WRAP_LONG.class)) { +// wrapData = (WRAP_LONG) () -> (long) data; +// } else if (wrapClass.equals(WRAP_SHORT.class)) { +// wrapData = (WRAP_SHORT) () -> (short) data; +// } else if (wrapClass.equals(WRAP_STRING.class)) { +// wrapData = (WRAP_STRING) () -> (String) data; +// } +// } +// // 按照对应接口进行序列化 +// // 生成该接口对应的对象 +// return BinaryProtocol.encode(wrapData, serialClass); +// } +// +// public static BytesValueList serializeArray(Object[] datas) { +// if (datas == null || datas.length == 0) { +// return null; +// } +// int contentBytesSize = 0; +// byte[] header = new byte[(datas.length + 1) * 4]; +// System.arraycopy(BytesUtils.toBytes(datas.length), 0, header, 0, INT_LENGTH); +// int offset = INT_LENGTH; +// +// List serialBytesList = new ArrayList<>(); +// for (Object data : datas) { +// // 按照对应接口进行序列化 +// byte[] currBytes = serialize(data); +// // 长度写入 +// System.arraycopy(BytesUtils.toBytes(currBytes.length), 0, header, offset, INT_LENGTH); +// serialBytesList.add(currBytes); +// contentBytesSize += currBytes.length; +// offset += INT_LENGTH; +// } +// +// // 填充content +// byte[] content = new byte[contentBytesSize]; +// offset = 0; +// for (byte[] bytes : serialBytesList) { +// System.arraycopy(bytes, 0, content, offset, bytes.length); +// offset += bytes.length; +// } +// // 将header和content组装 +// return BytesUtils.concat(header, content); +// } +// +// public static Object[] resolveArray(byte[] bytes) { +// if (bytes == null || bytes.length == 0) { +// return null; +// } +// byte[] lengthBytes = new byte[INT_LENGTH]; +// System.arraycopy(bytes, 0, lengthBytes, 0, INT_LENGTH); +// int length = BytesUtils.toInt(lengthBytes); +// Object[] datas = new Object[length]; +// +// int headerOffset = INT_LENGTH; +// int contentStart = (length + 1) * INT_LENGTH; +// +// for (int i = 0; i < length; i++) { +// byte[] currDataLengthBytes = new byte[INT_LENGTH]; +// System.arraycopy(bytes, headerOffset, currDataLengthBytes, 0, INT_LENGTH); +// int currDataLength = BytesUtils.toInt(currDataLengthBytes); +// // 读取 +// byte[] dataBytes = new byte[currDataLength]; +// System.arraycopy(bytes, contentStart, dataBytes, 0, currDataLength); +// +// datas[i] = resolve(dataBytes); +// +// contentStart += currDataLength; +// headerOffset += INT_LENGTH; +// } +// +// return datas; +// } +// +// public static Object resolve(BytesValue bytes) { +// // 反序列化该接口 +// Object currData = BinaryProtocol.decode(bytes); +// +// // 代理对象类型不能使用class判断,只能使用instanceof +// if (currData instanceof WRAP_STRING) { +// return ((WRAP_STRING) currData).getValue(); +// } else if (currData instanceof WRAP_INT) { +// return ((WRAP_INT) currData).getValue(); +// } else if (currData instanceof WRAP_LONG) { +// return ((WRAP_LONG) currData).getValue(); +// } else if (currData instanceof WRAP_BYTES) { +// return ((WRAP_BYTES) currData).getValue(); +// } else if (currData instanceof WRAP_SHORT) { +// return ((WRAP_SHORT) currData).getValue(); +// } else { +// return currData; +// } +// } +//} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java new file mode 100644 index 00000000..c8daa7e7 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java @@ -0,0 +1,147 @@ +package com.jd.blockchain.contract; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.jd.blockchain.ledger.BytesValueEncoding; +import com.jd.blockchain.utils.IllegalDataException; + +public class ContractType { + + private String name; + + private Map events = new HashMap<>(); + + private Map handleMethods = new HashMap<>(); + + public String getName() { + return name; + } + + /** + * 返回声明的所有事件; + * + * @return + */ + public Set getEvents() { + return events.keySet(); + } + + /** + * 返回指定方法声明的事件;
+ * + * 如果不存在,则返回 null; + * + * @param method + * @return + */ + public String getEvent(Method method) { + return handleMethods.get(method); + } + + /** + * 返回事件的处理方法;
+ * + * 如果不存在,则返回 null; + * + * @param event + * @return + */ + public Method getHandleMethod(String event) { + return events.get(event); + } + + private ContractType() { + } + + /** + * 解析合约的声明; + * + * @param contractIntf 合约的声明接口,必须是 interface ; + * @return + */ + public static ContractType resolve(Class contractIntf) { + // TODO:方法会检查合约方法声明的类型和返回值类型; + // 如果是Class则首先获取其接口 + if (!contractIntf.isInterface()) { + Class realIntf = null; + Class[] interfaces = contractIntf.getInterfaces(); + for (Class intf : interfaces) { + if (intf.isAnnotationPresent(Contract.class)) { + realIntf = intf; + break; + } + } + if (realIntf == null) { + throw new IllegalDataException(String + .format("%s is not a Contract Type, because there is not @Contract !", contractIntf.getName())); + } + contractIntf = realIntf; + } + + // 接口上必须有注解 + Contract contract = contractIntf.getAnnotation(Contract.class); + if (contract == null) { + throw new IllegalDataException("It is not a Contract Type, because there is not @Contract !"); + } + + Method[] classMethods = contractIntf.getDeclaredMethods(); + + if (classMethods.length == 0) { + throw new IllegalDataException("This interface have not any methods !"); + } + + ContractType contractType = new ContractType(); + + // 设置合约显示名字为 + contractType.name = contract.name(); + + for (Method method : classMethods) { + + // if current method contains @ContractEvent,then put it in this map; + ContractEvent contractEvent = method.getAnnotation(ContractEvent.class); + + if (contractEvent != null) { + String eventName = contractEvent.name(); + // if annoMethodMap has contained the eventName, too many same eventNames exists + // probably, say NO! + if (contractType.events.containsKey(eventName)) { + throw new ContractException("there is repeat definition of contractEvent to @ContractEvent."); + } + // check param's type is fit for need. + Class[] paramTypes = method.getParameterTypes(); + for (Class currParamType : paramTypes) { + if (!BytesValueEncoding.supportType(currParamType)) { + throw new IllegalStateException( + String.format("Param Type = %s can not support !!!", currParamType.getName())); + } + } + + // 判断返回值是否可序列化 + Class returnType = method.getReturnType(); + if (!BytesValueEncoding.supportType(returnType)) { + throw new IllegalStateException( + String.format("Return Type = %s can not support !!!", returnType.getName())); + } + + contractType.events.put(eventName, method); + contractType.handleMethods.put(method, eventName); + } + } + // 最起码有一个ContractEvent + if (contractType.events.isEmpty()) { + throw new IllegalStateException( + String.format("Contract Interface[%s] have none method for annotation[@ContractEvent] !", contractIntf.getName())); + } + + return contractType; + } + + @Override + public String toString() { + return "ContractType{" + "name='" + name + '\'' + ", events=" + events + ", handleMethods=" + handleMethods + + '}'; + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ErrorCodeEnum.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ErrorCodeEnum.java deleted file mode 100644 index f978cb2f..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ErrorCodeEnum.java +++ /dev/null @@ -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; -} - - diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAwire.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAware.java similarity index 50% rename from source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAwire.java rename to source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAware.java index 36080be1..0e309dbd 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAwire.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAware.java @@ -4,7 +4,7 @@ package com.jd.blockchain.contract; * @author huanghaiquan * */ -public interface EventProcessingAwire extends ContractRuntimeAwire { +public interface EventProcessingAware extends ContractAware { /** * 在事件处理方法执行之前调用; @@ -21,19 +21,6 @@ public interface EventProcessingAwire extends ContractRuntimeAwire { * @param error * 错误;如果事件处理正常结束,则此参数为 null;如果事件处理发生了错误,此参数非空; */ - void postEvent(ContractEventContext eventContext, ContractException error); + void postEvent(ContractEventContext eventContext, Exception error); - - /** - * 在事件处理方法成功执行之后调用; - * - * @param error - * 错误;如果事件处理正常结束,则此参数为 null;如果事件处理发生了错误,此参数非空; - */ - void postEvent(ContractException error); - - /** - * 在事件处理方法成功执行之后调用; - */ - void postEvent(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java new file mode 100644 index 00000000..928d5979 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java @@ -0,0 +1,39 @@ +package com.jd.blockchain.contract; + +import com.jd.blockchain.utils.IllegalDataException; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +public class EventResult { + + private static final long MAX_SECONDS = 30; + + private CompletableFuture data = new CompletableFuture<>(); + + private int opIndex; + + public EventResult() { + } + + public EventResult(int opIndex) { + this.opIndex = opIndex; + } + + public void done(T value) { + data.complete(value); + } + + public int opIndex() { + return this.opIndex; + } + + public T get() { + try { + // 防止长时间阻塞 + return data.get(MAX_SECONDS, TimeUnit.SECONDS); + } catch (Exception e) { + throw new IllegalDataException(e.getMessage()); + } + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java index e18d7714..03263a1c 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java @@ -4,6 +4,7 @@ import java.util.Set; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValueList; import com.jd.blockchain.ledger.TransactionRequest; /** @@ -13,17 +14,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 BytesValueList args; private TransactionRequest transactionRequest; private Set txSigners; - private Set contractOwners; private LedgerContext ledgerContext; public LocalContractEventContext(HashDigest ledgeHash, String event){ this.ledgeHash = ledgeHash; this.event = event; -// this.chainCode = chainCode; } @Override @@ -47,7 +45,7 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable } @Override - public byte[] getArgs() { + public BytesValueList getArgs() { return args; } @@ -81,11 +79,6 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable return this; } - public LocalContractEventContext setContractOwners(Set contractOwners) { - this.contractOwners = contractOwners; - return this; - } - public LocalContractEventContext setLedgerContext(LedgerContext ledgerContext) { this.ledgerContext = ledgerContext; return this; @@ -100,7 +93,7 @@ public class LocalContractEventContext implements ContractEventContext,Cloneable // return this; // } - public LocalContractEventContext setArgs(byte[] args) { + public LocalContractEventContext setArgs(BytesValueList args) { this.args = args; return this; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEntry.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java similarity index 53% rename from source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEntry.java rename to source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java index 2189d2b1..ca4e9cb0 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEntry.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java @@ -8,38 +8,38 @@ import com.jd.blockchain.utils.io.BytesUtils; * @author huanghaiquan * */ -public class BytesValueEntry implements BytesValue { - BytesValueType type; +public class BytesData implements BytesValue { + DataType type; Bytes value; - private BytesValueEntry(BytesValueType type, byte[] bytes) { + private BytesData(DataType type, byte[] bytes) { this.type = type; this.value = new Bytes(bytes); } - private BytesValueEntry(BytesValueType type, Bytes bytes) { + private BytesData(DataType type, Bytes bytes) { this.type = type; this.value = bytes; } - public static BytesValue fromType(BytesValueType type, byte[] value) { - return new BytesValueEntry(type, value); + public static BytesValue fromType(DataType type, byte[] value) { + return new BytesData(type, value); } public static BytesValue fromBytes(byte[] value) { - return new BytesValueEntry(BytesValueType.BYTES, value); + return new BytesData(DataType.BYTES, value); } public static BytesValue fromBytes(Bytes value) { - return new BytesValueEntry(BytesValueType.BYTES, value); + return new BytesData(DataType.BYTES, value); } public static BytesValue fromImage(byte[] value) { - return new BytesValueEntry(BytesValueType.IMG, value); + return new BytesData(DataType.IMG, value); } public static BytesValue fromImage(Bytes value) { - return new BytesValueEntry(BytesValueType.IMG, value); + return new BytesData(DataType.IMG, value); } /** @@ -49,7 +49,7 @@ public class BytesValueEntry implements BytesValue { * @return */ public static BytesValue fromText(String value) { - return new BytesValueEntry(BytesValueType.TEXT, BytesUtils.toBytes(value)); + return new BytesData(DataType.TEXT, BytesUtils.toBytes(value)); } /** @@ -62,51 +62,51 @@ public class BytesValueEntry implements BytesValue { if (bytesValue == null) { return null; } - if (bytesValue.getType() != BytesValueType.TEXT) { - throw new ValueTypeCastException("The expected value type is " + BytesValueType.TEXT.toString() + if (bytesValue.getType() != DataType.TEXT) { + throw new ValueTypeCastException("The expected value type is " + DataType.TEXT.toString() + ", but it is actually " + bytesValue.getType().toString() + "!"); } return bytesValue.getValue().toUTF8String(); } public static BytesValue fromJSON(String value) { - return new BytesValueEntry(BytesValueType.JSON, BytesUtils.toBytes(value)); + return new BytesData(DataType.JSON, BytesUtils.toBytes(value)); } public static BytesValue fromXML(String value) { - return new BytesValueEntry(BytesValueType.XML, BytesUtils.toBytes(value)); + return new BytesData(DataType.XML, BytesUtils.toBytes(value)); } public static BytesValue fromInt32(int value) { - return new BytesValueEntry(BytesValueType.INT32, BytesUtils.toBytes(value)); + return new BytesData(DataType.INT32, BytesUtils.toBytes(value)); } public static BytesValue fromInt64(long value) { - return new BytesValueEntry(BytesValueType.INT64, BytesUtils.toBytes(value)); + return new BytesData(DataType.INT64, BytesUtils.toBytes(value)); } public static BytesValue fromInt16(short value) { - return new BytesValueEntry(BytesValueType.INT16, BytesUtils.toBytes(value)); + return new BytesData(DataType.INT16, BytesUtils.toBytes(value)); } public static BytesValue fromInt8(byte value) { - return new BytesValueEntry(BytesValueType.INT8, BytesUtils.toBytes(value)); + return new BytesData(DataType.INT8, BytesUtils.toBytes(value)); } public static BytesValue fromTimestamp(long value) { - return new BytesValueEntry(BytesValueType.TIMESTAMP, BytesUtils.toBytes(value)); + return new BytesData(DataType.TIMESTAMP, BytesUtils.toBytes(value)); } public static BytesValue fromBoolean(boolean value) { - return new BytesValueEntry(BytesValueType.BOOLEAN, BytesUtils.toBytes(value)); + return new BytesData(DataType.BOOLEAN, BytesUtils.toBytes(value)); } @Override - public BytesValueType getType() { + public DataType getType() { return this.type; } - public void setType(BytesValueType type) { + public void setType(DataType type) { this.type = type; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java new file mode 100644 index 00000000..f7aef959 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java @@ -0,0 +1,31 @@ +package com.jd.blockchain.ledger; + +public class BytesDataList implements BytesValueList { + + private BytesValue[] bytesValues; + + public BytesDataList(BytesValue... bytesValues) { + this.bytesValues = bytesValues; + } + + @Override + public BytesValue[] getValues() { + return bytesValues; + } + + public static BytesValueList singleText(String value) { + return new BytesDataList(BytesData.fromText(value)); + } + + public static BytesValueList singleLong(long value) { + return new BytesDataList(BytesData.fromInt64(value)); + } + + public static BytesValueList singleInt(int value) { + return new BytesDataList(BytesData.fromInt32(value)); + } + + public static BytesValueList singleBoolean(boolean value) { + return new BytesDataList(BytesData.fromBoolean(value)); + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java index ae340106..6e7b9b46 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java @@ -21,7 +21,7 @@ public interface BytesValue { * @return */ @DataField(order = 0, refEnum = true) - BytesValueType getType(); + DataType getType(); /** * 数据值的二进制序列; diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java new file mode 100644 index 00000000..af67719e --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java @@ -0,0 +1,199 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.BinaryProtocol; +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.ledger.resolver.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class BytesValueEncoding { + + private static final Map, BytesValueResolver> CLASS_RESOLVER_MAP = new ConcurrentHashMap<>(); + + private static final Map DATA_TYPE_RESOLVER_MAP = new ConcurrentHashMap<>(); + + static { + init(); + } + + private static void init() { + BytesValueResolver[] resolvers = new BytesValueResolver[]{ + new BytesToBytesValueResolver(), + new IntegerToBytesValueResolver(), + new LongToBytesValueResolver(), + new ShortToBytesValueResolver(), + new StringToBytesValueResolver() + }; + + for (BytesValueResolver currResolver : resolvers) { + // 填充classMAP + Class[] supportClasses = currResolver.supportClasses(); + if (supportClasses != null && supportClasses.length > 0) { + for (Class clazz : supportClasses) { + CLASS_RESOLVER_MAP.put(clazz, currResolver); + } + } + + // 填充dataTypeMap + DataType[] supportDataTypes = currResolver.supportDataTypes(); + if (supportDataTypes != null && supportDataTypes.length > 0) { + for (DataType dataType : supportDataTypes) { + DATA_TYPE_RESOLVER_MAP.put(dataType, currResolver); + } + } + } + } + + + public static BytesValue encodeSingle(Object value, Class type) { + if (value == null) { + return null; + } + if (type == null) { + type = value.getClass(); + } else if (type.equals(void.class) || type.equals(Void.class)) { + return null; + } + if (type.isInterface()) { + // 判断是否含有DataContract注解 + if (!type.isAnnotationPresent(DataContract.class)) { + throw new IllegalStateException(String.format("Interface[%s] can not be serialize !!!", type.getName())); + } + // 将对象序列化 + byte[] serialBytes = BinaryProtocol.encode(value, type); + return BytesData.fromType(DataType.DATA_CONTRACT, serialBytes); + } + BytesValueResolver bytesValueResolver = CLASS_RESOLVER_MAP.get(type); + if (bytesValueResolver == null) { + throw new IllegalStateException(String.format("Class[%s] can not find encoder !!!", type.getName())); + } + return bytesValueResolver.encode(value, type); + } + + public static BytesValueList encodeArray(Object[] values, Class[] types) { + if (values == null || values.length == 0) { + return null; + } + if (types != null && types.length != values.length) { + throw new IllegalStateException("Types can be null, or types's length must be equal BytesValue[]'s !!!"); + } + + BytesValueListData bytesValueListData = new BytesValueListData(); + for (int i = 0; i < values.length; i++) { + BytesValue bytesValue = encodeSingle(values[i], types == null ? null : types[i]); + bytesValueListData.add(bytesValue); + } + return bytesValueListData; + } + + public static Object decode(BytesValue value) { + return decode(value, null); + } + + public static Object decode(BytesValue value, Class type) { + DataType dataType = value.getType(); + BytesValueResolver valueResolver = DATA_TYPE_RESOLVER_MAP.get(dataType); + if (valueResolver == null) { + throw new IllegalStateException(String.format("DataType[%s] can not find encoder !!!", dataType.name())); + } + return type == null ? valueResolver.decode(value) : valueResolver.decode(value, type); + } + + public static Object[] decode(BytesValueList values, Class[] types) { + BytesValue[] bytesValues = values.getValues(); + if (bytesValues == null || bytesValues.length == 0) { + return null; + } + // 允许types为null,此时每个BytesValue按照当前的对象来处理 + // 若types不为null,则types's长度必须和bytesValues一致 + if (types != null && types.length != bytesValues.length) { + throw new IllegalStateException("Types can be null, or types's length must be equal BytesValue[]'s !!!"); + } + Object[] resolveObjs = new Object[bytesValues.length]; + if (types == null) { + // 按照默认方式解析 + for (int i = 0; i < bytesValues.length; i++) { + BytesValue bytesValue = bytesValues[i]; + DataType dataType = bytesValue.getType(); + BytesValueResolver valueResolver = DATA_TYPE_RESOLVER_MAP.get(dataType); + if (valueResolver == null) { + throw new IllegalStateException(String.format("DataType[%s] can not find encoder !!!", dataType.name())); + } + resolveObjs[i] = valueResolver.decode(bytesValue); + } + return resolveObjs; + } + // 按照输入的Class进行解析 + for (int i = 0; i < bytesValues.length; i++) { + resolveObjs[i] = decode(bytesValues[i], types[i]); + } + return resolveObjs; + } + + public static Object getDefaultValue(Class type) { + if (type == void.class || type == Void.class) { + return null; + } + + if (!type.isPrimitive()) { + // 非基本类型 + return null; + } else { + // 基本类型需要处理返回值,目前采用枚举遍历方式 + // 八种基本类型:int, double, float, long, short, boolean, byte, char, void + if (type.equals(int.class)) { + return 0; + } else if (type.equals(double.class)) { + return 0.0D; + } else if (type.equals(float.class)) { + return 0F; + } else if (type.equals(long.class)) { + return 0L; + } else if (type.equals(short.class)) { + return (short) 0; + } else if (type.equals(boolean.class)) { + return Boolean.FALSE; + } else if (type.equals(byte.class)) { + return (byte) 0; + } else if (type.equals(char.class)) { + return (char) 0; + } + return null; + } + } + + public static boolean supportType(Class currParamType) { + // 支持空返回值 + if (currParamType.equals(void.class) || currParamType.equals(Void.class)) { + return true; + } + + if (currParamType.isInterface()) { + // 接口序列化必须实现DataContract注解 + if (!currParamType.isAnnotationPresent(DataContract.class)) { + throw new IllegalStateException(String.format("Interface[%s] can not be serialize !!!", currParamType.getName())); + } + return true; + } + return CLASS_RESOLVER_MAP.containsKey(currParamType); + } + + + public static class BytesValueListData implements BytesValueList { + + private List bytesValues = new ArrayList<>(); + + public void add(BytesValue bytesValue) { + bytesValues.add(bytesValue); + } + + @Override + public BytesValue[] getValues() { + BytesValue[] bytesValueArray = new BytesValue[bytesValues.size()]; + return bytesValues.toArray(bytesValueArray); + } + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java new file mode 100644 index 00000000..e40e27d6 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java @@ -0,0 +1,13 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code = DataCodes.BYTES_VALUE_LIST) +public interface BytesValueList { + + @DataField(order = 0, refContract = true, list = true) + BytesValue[] getValues(); + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java deleted file mode 100644 index fad0e208..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; - -import java.math.BigDecimal; - -/** - * contract args for BIG_INT; - * @author zhaogw - * date 2019-05-17 15:32 - */ -@DataContract(code = DataCodes.CONTRACT_BIG_INT) -public interface CONTRACT_BIG_INT { - - @DataField(order=2, primitiveType= PrimitiveType.BIG_INT) - BigDecimal getValue(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java deleted file mode 100644 index 7661b852..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; -import com.jd.blockchain.utils.Bytes; - -/** - * contract args for Binary; - * @author zhaogw - * date 2019-05-17 15:32 - */ -@DataContract(code = DataCodes.CONTRACT_BINARY) -public interface CONTRACT_BINARY { - - @DataField(order=2, primitiveType= PrimitiveType.BYTES) - Bytes getValue(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java deleted file mode 100644 index b6666cc0..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; - -/** - * contract args for int16; - * @author zhaogw - * date 2019-05-17 15:32 - */ -@DataContract(code = DataCodes.CONTRACT_INT16) -public interface CONTRACT_INT16 { - - @DataField(order=2, primitiveType= PrimitiveType.INT16) - short getValue(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java deleted file mode 100644 index 02fdb07e..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; - -/** - * contract args for int32; - * @author zhaogw - * date 2019-05-17 15:32 - */ -@DataContract(code = DataCodes.CONTRACT_INT32) -public interface CONTRACT_INT32 { - - @DataField(order=2, primitiveType= PrimitiveType.INT32) - int getValue(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java deleted file mode 100644 index ad092edd..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; - -/** - * contract args for int64; - * @author zhaogw - * date 2019-05-17 15:32 - */ -@DataContract(code = DataCodes.CONTRACT_INT64) -public interface CONTRACT_INT64 { - - @DataField(order=2, primitiveType= PrimitiveType.INT64) - long getValue(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java deleted file mode 100644 index f77d3de2..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; - -/** - * contract args for int8; - * @author zhaogw - * date 2019-05-17 15:32 - */ -@DataContract(code = DataCodes.CONTRACT_INT8) -public interface CONTRACT_INT8 { - - @DataField(order=2, primitiveType= PrimitiveType.INT8) - Byte getValue(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java deleted file mode 100644 index 8f5e4a4c..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; - -/** - * contract args for String; - * @author zhaogw - * date 2019-05-17 15:32 - */ -@DataContract(code = DataCodes.CONTRACT_TEXT) -public interface CONTRACT_TEXT { - - @DataField(order=2, primitiveType= PrimitiveType.TEXT) - String getValue(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractArgs.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractArgs.java deleted file mode 100644 index 9cce0cee..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractArgs.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.jd.blockchain.ledger; -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.consts.DataCodes; - -import java.lang.reflect.Method; - -/** - * contract's args; - */ -@DataContract(code = DataCodes.CONTRACT_ARGS) -public interface ContractArgs { - Method getMethod(); - Object[] getArgs(); -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java deleted file mode 100644 index 56e6bc24..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.jd.blockchain.ledger; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.binaryproto.DataField; -import com.jd.blockchain.binaryproto.PrimitiveType; -import com.jd.blockchain.consts.DataCodes; - -/** - * build complex param Object, provide more String attributes; - */ -@DataContract(code = DataCodes.CONTRACT_BIZ_CONTENT) -public interface ContractBizContent { - /** - * param lists; - * @return - */ - @DataField(order = 1, list = true, primitiveType = PrimitiveType.TEXT, genericContract = true) - String[] getAttrs(); - -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java index 9b0219b0..e9de0261 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java @@ -7,6 +7,8 @@ import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.utils.Bytes; /** + * 发送合约事件的操作; + * * @author huanghaiquan * */ @@ -34,15 +36,7 @@ public interface ContractEventSendOperation extends Operation { * * @return */ - @DataField(order = 4, primitiveType = PrimitiveType.BYTES) - byte[] getArgs(); - - /** - * 获得交易操作时间; - * - * @return - */ - @DataField(order = 5, primitiveType = PrimitiveType.INT64) - long getTxOpTime(); + @DataField(order = 4, refContract = true) + BytesValueList getArgs(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java new file mode 100644 index 00000000..cb1da5c4 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java @@ -0,0 +1,13 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code= DataCodes.CONTRACT) +public interface ContractInfo extends AccountHeader { + + @DataField(order=4, primitiveType= PrimitiveType.BYTES) + byte[] getChainCode(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountKVSetOperation.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountKVSetOperation.java index 5bedb8bc..c83cea9a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountKVSetOperation.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountKVSetOperation.java @@ -7,7 +7,7 @@ import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.utils.Bytes; @DataContract(code= DataCodes.TX_OP_DATA_ACC_SET) -public interface DataAccountKVSetOperation extends Operation{ +public interface DataAccountKVSetOperation extends Operation { @DataField(order=2, primitiveType=PrimitiveType.BYTES) Bytes getAccountAddress(); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java similarity index 51% rename from source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueType.java rename to source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java index 11049ea9..1cb8fce3 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueType.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java @@ -1,8 +1,9 @@ package com.jd.blockchain.ledger; -import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.binaryproto.BaseType; import com.jd.blockchain.binaryproto.EnumContract; import com.jd.blockchain.binaryproto.EnumField; +import com.jd.blockchain.binaryproto.PrimitiveType; import com.jd.blockchain.consts.DataCodes; /** @@ -11,8 +12,8 @@ import com.jd.blockchain.consts.DataCodes; * @author huanghaiquan * */ -@EnumContract(code = DataCodes.ENUM_TYPE_BYTES_VALUE_TYPE, name = "BytesValueType", decription = "") -public enum BytesValueType { +@EnumContract(code = DataCodes.ENUM_TYPE_BYTES_VALUE_TYPE) +public enum DataType { /** * 空; @@ -37,59 +38,84 @@ public enum BytesValueType { INT64(PrimitiveType.INT64.CODE), /** - * 时间戳; + * 文本数据; */ - TIMESTAMP(PrimitiveType.TIMESTAMP.CODE), + TEXT(PrimitiveType.TEXT.CODE), /** - * 文本数据; + * 二进制数据; */ - TEXT(PrimitiveType.TEXT.CODE), + BYTES(PrimitiveType.BYTES.CODE), /** - * 文本数据; + * 时间戳; */ - JSON(PrimitiveType.JSON.CODE), + TIMESTAMP((byte) (BaseType.INTEGER | 0x08)), /** * 文本数据; */ - XML(PrimitiveType.XML.CODE), + JSON((byte) (BaseType.TEXT | 0x01)), /** - * 二进制数据; + * 文本数据; */ - BYTES(PrimitiveType.BYTES.CODE), + XML((byte) (BaseType.TEXT | 0x02)), /** * 大整数; */ - BIG_INT(PrimitiveType.BIG_INT.CODE), + BIG_INT((byte) (BaseType.BYTES | 0x01)), /** * 图片; */ - IMG(PrimitiveType.IMG.CODE), + IMG((byte) (BaseType.BYTES | 0x02)), /** * 视频; */ - VIDEO(PrimitiveType.VIDEO.CODE), + VIDEO((byte) (BaseType.BYTES | 0x03)), + + /** + * 位置坐标; + */ + LOCATION((byte) (BaseType.BYTES | 0x04)), + + /** + * 公钥; + */ + PUB_KEY((byte) (BaseType.BYTES | 0x05)), + + /** + * 签名摘要; + */ + SIGNATURE_DIGEST((byte) (BaseType.BYTES | 0x06)), + + /** + * 哈希摘要; + */ + HASH_DIGEST((byte) (BaseType.BYTES | 0x07)), + + /** + * 加密数据; + */ + ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)), /** - * 位置; + * DataContract 数据; */ - LOCATION(PrimitiveType.LOCATION.CODE); + DATA_CONTRACT((byte) (BaseType.EXT | 0x01)); @EnumField(type = PrimitiveType.INT8) public final byte CODE; - private BytesValueType(byte code) { + private DataType(byte code) { this.CODE = code; } - public static BytesValueType valueOf(byte code) { - for (BytesValueType dataType : BytesValueType.values()) { + public static DataType valueOf(byte code) { + for (DataType dataType : DataType.values()) { if (dataType.CODE == code) { return dataType; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java index 9d4e0870..396cc36d 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java @@ -25,7 +25,7 @@ public interface KVDataEntry { * * @return */ - BytesValueType getType(); + DataType getType(); /** * 值; diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java index 2f081642..2769631c 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java @@ -58,8 +58,8 @@ public class KVDataObject implements KVDataEntry { * @see com.jd.blockchain.ledger.KVDataEntry#getType() */ @Override - public BytesValueType getType() { - return bytesValue == null ? BytesValueType.NIL : bytesValue.getType(); + public DataType getType() { + return bytesValue == null ? DataType.NIL : bytesValue.getType(); } @Override @@ -95,7 +95,7 @@ public class KVDataObject implements KVDataEntry { * @return */ public boolean isNil() { - return bytesValue == null || BytesValueType.NIL == bytesValue.getType(); + return bytesValue == null || DataType.NIL == bytesValue.getType(); } /** @@ -119,10 +119,10 @@ public class KVDataObject implements KVDataEntry { * @return */ public byte tinyValue() { - if (BytesValueType.INT8 == getType()) { + if (DataType.INT8 == getType()) { return bytesValue.getValue().toBytes()[0]; } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", BytesValueType.INT8, getType())); + throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT8, getType())); } /** @@ -137,10 +137,10 @@ public class KVDataObject implements KVDataEntry { * @return */ public short shortValue() { - if (BytesValueType.INT16 == getType()) { + if (DataType.INT16 == getType()) { return BytesUtils.toShort(bytesValue.getValue().toBytes(), 0); } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", BytesValueType.INT16, getType())); + throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT16, getType())); } /** @@ -155,10 +155,10 @@ public class KVDataObject implements KVDataEntry { * @return */ public int intValue() { - if (BytesValueType.INT32 == getType()) { + if (DataType.INT32 == getType()) { return BytesUtils.toInt(bytesValue.getValue().toBytes(), 0); } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", BytesValueType.INT32, getType())); + throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT32, getType())); } /** @@ -173,10 +173,10 @@ public class KVDataObject implements KVDataEntry { * @return */ public long longValue() { - if (BytesValueType.INT64 == getType()) { + if (DataType.INT64 == getType()) { return BytesUtils.toLong(bytesValue.getValue().toBytes(), 0); } - throw new IllegalStateException(String.format("Expected type [%s], but [%s]", BytesValueType.INT64, getType())); + throw new IllegalStateException(String.format("Expected type [%s], but [%s]", DataType.INT64, getType())); } @@ -192,11 +192,11 @@ public class KVDataObject implements KVDataEntry { * @return */ public BigInteger bigIntValue() { - if (BytesValueType.BIG_INT == getType()) { + if (DataType.BIG_INT == getType()) { return new BigInteger(bytesValue.getValue().toBytes()); } throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", BytesValueType.BIG_INT, getType())); + String.format("Expected type [%s], but [%s]", DataType.BIG_INT, getType())); } /** @@ -211,11 +211,11 @@ public class KVDataObject implements KVDataEntry { * @return */ public boolean boolValue() { - if (BytesValueType.BOOLEAN == getType()) { + if (DataType.BOOLEAN == getType()) { return BytesUtils.toBoolean(bytesValue.getValue().toBytes()[0]); } throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", BytesValueType.BOOLEAN, getType())); + String.format("Expected type [%s], but [%s]", DataType.BOOLEAN, getType())); } /** @@ -230,12 +230,12 @@ public class KVDataObject implements KVDataEntry { * @return */ public Date datetimeValue() { - if (BytesValueType.TIMESTAMP == getType()) { + if (DataType.TIMESTAMP == getType()) { long ts = BytesUtils.toLong(bytesValue.getValue().toBytes()); return new Date(ts); } throw new IllegalStateException( - String.format("Expected type [%s], but [%s]", BytesValueType.TIMESTAMP, getType())); + String.format("Expected type [%s], but [%s]", DataType.TIMESTAMP, getType())); } /** @@ -251,12 +251,12 @@ public class KVDataObject implements KVDataEntry { * @return */ public String stringValue() { - BytesValueType type = getType(); - if (BytesValueType.TEXT == type || BytesValueType.JSON == type || BytesValueType.XML == type) { + DataType type = getType(); + if (DataType.TEXT == type || DataType.JSON == type || DataType.XML == type) { return bytesValue.getValue().toUTF8String(); } throw new IllegalStateException(String.format("Expected type [%s] or [%s] or [%s] , but [%s]", - PrimitiveType.TEXT, BytesValueType.JSON, BytesValueType.XML, type)); + PrimitiveType.TEXT, DataType.JSON, DataType.XML, type)); } // // ---------------- diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataVO.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataVO.java index 4fc214d0..10ffad7a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataVO.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataVO.java @@ -8,6 +8,14 @@ public class KVDataVO { private String key; private long[] version; + public KVDataVO() { + } + + public KVDataVO(String key, long[] version) { + this.key = key; + this.version = version; + } + public String getKey() { return key; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVInfoVO.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVInfoVO.java index 5f49e3de..2077810d 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVInfoVO.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVInfoVO.java @@ -8,6 +8,13 @@ package com.jd.blockchain.ledger; public class KVInfoVO { private KVDataVO[] data; + public KVInfoVO() { + } + + public KVInfoVO(KVDataVO[] data) { + this.data = data; + } + public KVDataVO[] getData() { return data; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java new file mode 100644 index 00000000..b6c6c3bd --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java @@ -0,0 +1,16 @@ +package com.jd.blockchain.ledger; + +import com.jd.blockchain.binaryproto.DataContract; +import com.jd.blockchain.binaryproto.DataField; +import com.jd.blockchain.binaryproto.PrimitiveType; +import com.jd.blockchain.consts.DataCodes; + +@DataContract(code = DataCodes.TX_OP_RESULT) +public interface OperationResult { + + @DataField(order = 1, primitiveType = PrimitiveType.INT32) + int getIndex(); + + @DataField(order = 2, refContract = true) + BytesValue getResult(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java new file mode 100644 index 00000000..336887cf --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java @@ -0,0 +1,35 @@ +package com.jd.blockchain.ledger; + + +public class OperationResultData implements OperationResult { + + private int index; + + private BytesValue result; + + public OperationResultData() { + } + + public OperationResultData(int index, BytesValue result) { + this.index = index; + this.result = result; + } + + @Override + public int getIndex() { + return index; + } + + @Override + public BytesValue getResult() { + return result; + } + + public void setIndex(int index) { + this.index = index; + } + + public void setResult(BytesValue result) { + this.result = result; + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java index d73d6091..20d4d9ad 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java @@ -1,8 +1,9 @@ package com.jd.blockchain.ledger; +import java.io.Closeable; + import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.SignatureFunction; /** * 已就绪的交易; @@ -10,7 +11,7 @@ import com.jd.blockchain.crypto.SignatureFunction; * @author huanghaiquan * */ -public interface PreparedTransaction extends HashObject { +public interface PreparedTransaction extends HashObject, Closeable { /** * 交易内容的 Hash; @@ -33,10 +34,8 @@ public interface PreparedTransaction extends HashObject { /** * 对交易进行签名; * - * @param address - * 签名账户的地址; - * @param privKey - * 签名账户的私钥; + * @param address 签名账户的地址; + * @param privKey 签名账户的私钥; * @return */ DigitalSignature sign(AsymmetricKeypair keyPair); @@ -44,17 +43,18 @@ public interface PreparedTransaction extends HashObject { /** * 加入签名; * - * @param address - * 签名账户的地址; - * @param digest - * Base64格式的签名摘要; + * @param address 签名账户的地址; + * @param digest Base64格式的签名摘要; * @return */ void addSignature(DigitalSignature signature); /** - * 生成交易请求; + * 提交交易请求到共识节点;
+ * + * 这是同步方法,将阻塞当前线程,直到交易处理完成并返回结果之后,此方法才返回给调用者; * */ TransactionResponse commit(); + } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java index a2442521..542a3a49 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java @@ -5,7 +5,6 @@ import com.jd.blockchain.binaryproto.DataField; import com.jd.blockchain.binaryproto.PrimitiveType; import com.jd.blockchain.consts.DataCodes; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.utils.io.ByteArray; /** * Transaction 区块链交易,是被原子执行的操作集合; @@ -13,7 +12,7 @@ import com.jd.blockchain.utils.io.ByteArray; * @author huanghaiquan * */ -@DataContract(code= DataCodes.TX) +@DataContract(code = DataCodes.TX) public interface Transaction extends NodeRequest, HashObject { /** @@ -23,7 +22,7 @@ public interface Transaction extends NodeRequest, HashObject { * * @return */ - @DataField(order=1, primitiveType = PrimitiveType.BYTES) + @DataField(order = 1, primitiveType = PrimitiveType.BYTES) @Override HashDigest getHash(); @@ -32,7 +31,7 @@ public interface Transaction extends NodeRequest, HashObject { * * @return */ - @DataField(order=2, primitiveType=PrimitiveType.INT64) + @DataField(order = 2, primitiveType = PrimitiveType.INT64) long getBlockHeight(); /** @@ -42,7 +41,14 @@ public interface Transaction extends NodeRequest, HashObject { * * @return */ - @DataField(order=3, refEnum=true) + @DataField(order = 3, refEnum = true) TransactionState getExecutionState(); + /** + * 交易的返回结果 + * + * @return + */ + @DataField(order=4, list = true, refContract=true) + OperationResult[] getOperationResults(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java index 8695ab7e..3856f668 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java @@ -27,7 +27,7 @@ public class TransactionRespHandle implements TransactionResponse { private TransactionState globalResult; - private String[] contractReturn; + private OperationResult[] operationResults; public TransactionRespHandle(TransactionRequest request, TransactionState result, TransactionState globalResult) { this.request = request; @@ -51,8 +51,8 @@ public class TransactionRespHandle implements TransactionResponse { this.result = result; } - public void setContractReturn(String[] contractReturn) { - this.contractReturn = contractReturn; + public void setOperationResults(OperationResult[] operationResults) { + this.operationResults = operationResults; } public LedgerBlock getBlock() { @@ -97,7 +97,7 @@ public class TransactionRespHandle implements TransactionResponse { } @Override - public String[] getContractReturn() { - return contractReturn; + public OperationResult[] getOperationResults() { + return operationResults; } } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java index e7aa1197..662d595b 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java @@ -12,7 +12,7 @@ import com.jd.blockchain.crypto.HashDigest; * @author huanghaiquan * */ -@DataContract(code= DataCodes.TX_RESPONSE) +@DataContract(code = DataCodes.TX_RESPONSE) public interface TransactionResponse { /** @@ -20,7 +20,7 @@ public interface TransactionResponse { * * @return */ - @DataField(order=1, primitiveType = PrimitiveType.BYTES) + @DataField(order = 1, primitiveType = PrimitiveType.BYTES) HashDigest getContentHash(); /** @@ -28,7 +28,7 @@ public interface TransactionResponse { * * @return */ - @DataField(order=2, refEnum=true) + @DataField(order = 2, refEnum = true) TransactionState getExecutionState(); /** @@ -36,7 +36,7 @@ public interface TransactionResponse { * * @return */ - @DataField(order=3, primitiveType = PrimitiveType.BYTES) + @DataField(order = 3, primitiveType = PrimitiveType.BYTES) HashDigest getBlockHash(); /** @@ -47,7 +47,7 @@ public interface TransactionResponse { * * @return */ - @DataField(order=4, primitiveType=PrimitiveType.INT64) + @DataField(order = 4, primitiveType = PrimitiveType.INT64) long getBlockHeight(); /** @@ -55,7 +55,7 @@ public interface TransactionResponse { * * @return */ - @DataField(order=5, primitiveType=PrimitiveType.BOOLEAN) + @DataField(order = 5, primitiveType = PrimitiveType.BOOLEAN) boolean isSuccess(); /** @@ -63,6 +63,6 @@ public interface TransactionResponse { * * @return */ - @DataField(order=6, list=true, primitiveType=PrimitiveType.TEXT) - String[] getContractReturn(); + @DataField(order=6, list=true, refContract = true) + OperationResult[] getOperationResults(); } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionTemplate.java index 3c5acdcf..0696e768 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionTemplate.java @@ -1,5 +1,7 @@ package com.jd.blockchain.ledger; +import java.io.Closeable; + import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.transaction.ClientOperator; @@ -9,7 +11,7 @@ import com.jd.blockchain.transaction.ClientOperator; * @author huanghaiquan * */ -public interface TransactionTemplate extends ClientOperator { +public interface TransactionTemplate extends ClientOperator, Closeable { HashDigest getLedgerHash(); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java new file mode 100644 index 00000000..995d5522 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java @@ -0,0 +1,54 @@ +package com.jd.blockchain.ledger.resolver; + +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.utils.Bytes; + +public abstract class AbstractBytesValueResolver implements BytesValueResolver { + + protected boolean isSupport(Class type) { + if (type == null) { + return false; + } + Class[] supports = supportClasses(); + if (supports != null && supports.length > 0) { + for (Class clazz : supports) { + if (type.equals(clazz)) { + return true; + } + } + } + return false; + } + + protected boolean isSupport(DataType dataType) { + if (dataType == null) { + return false; + } + DataType[] supports = supportDataTypes(); + if (supports != null && supports.length > 0) { + for (DataType dt : supports) { + if (dataType.equals(dt)) { + return true; + } + } + } + return false; + } + + @Override + public BytesValue encode(Object value) { + return encode(value, value.getClass()); + } + + @Override + public Object decode(BytesValue value) { + DataType dataType = value.getType(); + if (!isSupport(dataType)) { + throw new IllegalStateException(String.format("Un-support encode DataType[%s] Object !!!", dataType.name())); + } + return decode(value.getValue()); + } + + protected abstract Object decode(Bytes value); +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java new file mode 100644 index 00000000..f4871515 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java @@ -0,0 +1,58 @@ +package com.jd.blockchain.ledger.resolver; + +import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.utils.Bytes; + +import java.util.Set; + +public class BytesToBytesValueResolver extends AbstractBytesValueResolver { + + private final Class[] supportClasses = {Bytes.class, byte[].class}; + + private final DataType[] supportDataTypes = {DataType.BYTES}; + + private final Set> convertClasses = initByteConvertSet(); + + @Override + public BytesValue encode(Object value, Class type) { + if (!isSupport(type)) { + throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); + } + if (type.equals(byte[].class)) { + return BytesData.fromBytes((byte[]) value); + } + return BytesData.fromBytes((Bytes) value); + } + + @Override + public Class[] supportClasses() { + return supportClasses; + } + + @Override + public DataType[] supportDataTypes() { + return supportDataTypes; + } + + @Override + protected Object decode(Bytes value) { + return value; + } + + @Override + public Object decode(BytesValue value, Class clazz) { + Bytes bytesVal = (Bytes) decode(value); + if (!convertClasses.contains(clazz)) { + throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); + } + + if (clazz.equals(String.class)) { + return bytesVal.toUTF8String(); + } else if (clazz.equals(byte[].class)) { + return bytesVal.toBytes(); + } + return bytesVal; + } +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesValueResolver.java new file mode 100644 index 00000000..08e48658 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesValueResolver.java @@ -0,0 +1,80 @@ +package com.jd.blockchain.ledger.resolver; + +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.utils.Bytes; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public interface BytesValueResolver { + + /** + * Int相关的可转换Class集合 + */ + Class[] supportIntConvertClasses = { + short.class, Short.class, int.class, Integer.class, long.class, Long.class}; + + /** + * 字节数组(字符串)相关可转换的Class集合 + */ + Class[] supportByteConvertClasses = { + String.class, Bytes.class, byte[].class}; + + default Set> initIntConvertSet() { + return new HashSet<>(Arrays.asList(supportIntConvertClasses)); + } + + default Set> initByteConvertSet() { + return new HashSet<>(Arrays.asList(supportByteConvertClasses)); + } + + /** + * 将对象转换为BytesValue + * + * @param value + * @return + */ + BytesValue encode(Object value); + + /** + * 将对象转换为BytesValue + * + * @param value + * @param type + * @return + */ + BytesValue encode(Object value, Class type); + + /** + * 当前解析器支持的Class列表 + * + * @return + */ + Class[] supportClasses(); + + /** + * 当前解析器支持的DataType列表 + * + * @return + */ + DataType[] supportDataTypes(); + + /** + * 将BytesValue解析为对应的Object + * + * @param value + * @return + */ + Object decode(BytesValue value); + + /** + * 将BytesValue转换为指定Class的Object + * + * @param value + * @param clazz + * @return + */ + Object decode(BytesValue value, Class clazz); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java new file mode 100644 index 00000000..a8400f02 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/IntegerToBytesValueResolver.java @@ -0,0 +1,58 @@ +package com.jd.blockchain.ledger.resolver; + +import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; + +import java.util.Set; + +public class IntegerToBytesValueResolver extends AbstractBytesValueResolver { + + private final Class[] supportClasses = {Integer.class, int.class}; + + private final DataType[] supportDataTypes = {DataType.INT32}; + + private final Set> convertClasses = initIntConvertSet(); + + @Override + public BytesValue encode(Object value, Class type) { + if (!isSupport(type)) { + throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); + } + return BytesData.fromInt32((int) value); + } + + @Override + public Class[] supportClasses() { + return supportClasses; + } + + @Override + public DataType[] supportDataTypes() { + return supportDataTypes; + } + + @Override + protected Object decode(Bytes value) { + return BytesUtils.toInt(value.toBytes()); + } + + @Override + public Object decode(BytesValue value, Class clazz) { + // 支持转换为short、int、long + int intVal = (int)decode(value); + if (convertClasses.contains(clazz)) { + // 对于short和Short需要强制类型转换 + if (clazz.equals(short.class) || clazz.equals(Short.class)) { + return (short) intVal; + } else if (clazz.equals(long.class) || clazz.equals(Long.class)) { + return (long) intVal; + } + return intVal; + } else { + throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); + } + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java new file mode 100644 index 00000000..fa11bcf4 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/LongToBytesValueResolver.java @@ -0,0 +1,58 @@ +package com.jd.blockchain.ledger.resolver; + +import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; + +import java.util.Set; + +public class LongToBytesValueResolver extends AbstractBytesValueResolver { + + private final Class[] supportClasses = {Long.class, long.class}; + + private final DataType[] supportDataTypes = {DataType.INT64}; + + private final Set> convertClasses = initIntConvertSet(); + + @Override + public BytesValue encode(Object value, Class type) { + if (!isSupport(type)) { + throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); + } + return BytesData.fromInt64((long)value); + } + + @Override + public Class[] supportClasses() { + return supportClasses; + } + + @Override + public DataType[] supportDataTypes() { + return supportDataTypes; + } + + @Override + protected Object decode(Bytes value) { + return BytesUtils.toLong(value.toBytes()); + } + + @Override + public Object decode(BytesValue value, Class clazz) { + // 支持转换为short、int、long + long longVal = (long)decode(value); + if (convertClasses.contains(clazz)) { + // 对于short和Short需要强制类型转换 + if (clazz.equals(short.class) || clazz.equals(Short.class)) { + return (short) longVal; + } else if (clazz.equals(int.class) || clazz.equals(Integer.class)) { + return (int) longVal; + } + return longVal; + } else { + throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); + } + } +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java new file mode 100644 index 00000000..b8eea38c --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/ShortToBytesValueResolver.java @@ -0,0 +1,57 @@ +package com.jd.blockchain.ledger.resolver; + +import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; + +import java.util.Set; + +public class ShortToBytesValueResolver extends AbstractBytesValueResolver { + + private final Class[] supportClasses = {Short.class, short.class}; + + private final DataType[] supportDataTypes = {DataType.INT16}; + + private final Set> convertClasses = initIntConvertSet(); + + @Override + public BytesValue encode(Object value, Class type) { + if (!isSupport(type)) { + throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); + } + return BytesData.fromInt16((short)value); + } + + @Override + public Class[] supportClasses() { + return supportClasses; + } + + @Override + public DataType[] supportDataTypes() { + return supportDataTypes; + } + + @Override + protected Object decode(Bytes value) { + return BytesUtils.toShort(value.toBytes()); + } + + @Override + public Object decode(BytesValue value, Class clazz) { + // 支持转换为short、int、long,由short转int、long无需转换 + short shortVal = (short)decode(value); + if (convertClasses.contains(clazz)) { + if (clazz.equals(int.class) || clazz.equals(Integer.class)) { + return (int) shortVal; + } else if (clazz.equals(long.class) || clazz.equals(Long.class)) { + return (long) shortVal; + } + return shortVal; + } else { + throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); + } + } +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java new file mode 100644 index 00000000..dca8e5d1 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/StringToBytesValueResolver.java @@ -0,0 +1,66 @@ +package com.jd.blockchain.ledger.resolver; + +import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; +import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; + +import java.util.Set; + + +public class StringToBytesValueResolver extends AbstractBytesValueResolver { + + private final Class[] supportClasses = {String.class}; + + private final DataType[] supportDataTypes = {DataType.TEXT, DataType.XML, DataType.JSON}; + + private final Set> convertClasses = initByteConvertSet(); + + @Override + public BytesValue encode(Object value, Class type) { + if (!isSupport(type)) { + throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); + } + // 类型判断 + String valString = (String)value; + if (JSONSerializeUtils.isJSON(valString)) { + return BytesData.fromJSON(valString); + } + // 暂不处理XML格式 + return BytesData.fromText(valString); + } + + @Override + public Class[] supportClasses() { + return supportClasses; + } + + @Override + public DataType[] supportDataTypes() { + return supportDataTypes; + } + + @Override + protected Object decode(Bytes value) { + return BytesUtils.toString(value.toBytes()); + } + + @Override + public Object decode(BytesValue value, Class clazz) { + // 支持三种类型对象返回,String.class,byte[].class,Bytes.class + String textValue = (String)decode(value); + + if (!convertClasses.contains(clazz)) { + throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); + } + + if (clazz.equals(byte[].class)) { + return BytesUtils.toBytes(textValue); + } else if (clazz.equals(Bytes.class)) { + return Bytes.fromString(textValue); + } + return textValue; + } +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java index 9f2d97d1..ef9b138a 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java @@ -5,6 +5,8 @@ import java.util.Collection; import java.util.List; import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.BytesValueList; import com.jd.blockchain.ledger.ContractCodeDeployOperation; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.ledger.DataAccountKVSetOperation; @@ -29,7 +31,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe private static final ContractCodeDeployOperationBuilderImpl CONTRACT_CODE_DEPLOY_OP_BUILDER = new ContractCodeDeployOperationBuilderImpl(); - private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); +// private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter(); @@ -43,6 +45,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe private ContractInvocationProxyBuilder contractInvoProxyBuilder = new ContractInvocationProxyBuilder(); + // TODO: 暂时只支持单线程情形,未考虑多线程; private List operationList = new ArrayList<>(); @Override @@ -89,11 +92,43 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); } + /** + * 返回已经定义的操作列表; + * + * @return + */ public Collection getOperations() { - // TODO: 合并操作列表中可能的重复操作; return operationList; } + /** + * 返回与操作列表对应的返回值处理器; + * + * @return + */ + public Collection getReturnValuetHandlers() { + List resultHandlers = new ArrayList(); + int index = 0; + for (Operation op : operationList) { + if (op instanceof ContractEventSendOperation) { + // 操作具有返回值,创建对应的结果处理器; + ContractEventSendOpTemplate opTemp = (ContractEventSendOpTemplate) op; + ContractInvocation invocation = opTemp.getInvocation(); + OperationResultHandle retnHandler; + if (invocation == null) { + retnHandler = new NullOperationReturnValueHandler(index); + } else { + invocation.setOperationIndex(index); + retnHandler = invocation; + } + resultHandlers.add(retnHandler); + } + index++; + } + + return resultHandlers; + } + public void clear() { operationList.clear(); } @@ -130,7 +165,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe operationList.add(op); return op; } - } private class DataAccountKVSetOperationBuilderFilter implements DataAccountKVSetOperationBuilder { @@ -155,13 +189,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe } } -// @Override -// public DataAccountKVSetOperationBuilder set(String key, byte[] value, long expVersion) { -// innerBuilder.set(key, value, expVersion); -// addOperation(); -// return this; -// } - @Override public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { innerBuilder.setText(key, value, expVersion); @@ -197,13 +224,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe return this; } -// @Override -// public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) { -// innerBuilder.setText(key, value, expVersion); -// addOperation(); -// return this; -// } - @Override public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { innerBuilder.setJSON(key, value, expVersion); @@ -228,32 +248,58 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe } private class ContractCodeDeployOperationBuilderFilter implements ContractCodeDeployOperationBuilder { - @Override public ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode) { ContractCodeDeployOperation op = CONTRACT_CODE_DEPLOY_OP_BUILDER.deploy(id, chainCode); operationList.add(op); return op; } - } private class ContractEventSendOperationBuilderFilter implements ContractEventSendOperationBuilder { @Override - public ContractEventSendOperation send(String address, String event, byte[] args) { - ContractEventSendOperation op = CONTRACT_EVENT_SEND_OP_BUILDER.send(address, event, args); - operationList.add(op); - return op; + public ContractEventSendOperation send(String address, String event, BytesValueList args) { + return send(Bytes.fromBase58(address), event, args); } @Override - public ContractEventSendOperation send(Bytes address, String event, byte[] args) { - ContractEventSendOperation op = CONTRACT_EVENT_SEND_OP_BUILDER.send(address, event, args); + public synchronized ContractEventSendOperation send(Bytes address, String event, BytesValueList args) { + ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); operationList.add(op); return op; } } + /** + * 不做任何操作的返回值处理器; + * + * @author huanghaiquan + * + */ + private static class NullOperationReturnValueHandler implements OperationResultHandle { + + private int operationIndex; + + public NullOperationReturnValueHandler(int operationIndex) { + this.operationIndex = operationIndex; + } + + @Override + public int getOperationIndex() { + return operationIndex; + } + + @Override + public Object complete(BytesValue bytesValue) { + return null; + } + + @Override + public void complete(Throwable error) { + } + + } + } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java index 1b46f1aa..a9f47141 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java @@ -296,7 +296,7 @@ public interface BlockchainQueryService { * @param address * @return */ - AccountHeader getContract(HashDigest ledgerHash, String address); + ContractInfo getContract(HashDigest ledgerHash, String address); /** * get users by ledgerHash and its range; diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BooleanValueHolder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BooleanValueHolder.java new file mode 100644 index 00000000..480e3d30 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BooleanValueHolder.java @@ -0,0 +1,22 @@ +package com.jd.blockchain.transaction; + +public class BooleanValueHolder extends ValueHolderWrapper { + + BooleanValueHolder(OperationResultHolder resultHolder) { + super(resultHolder); + } + + /** + * 获取值;
+ * + * 此方法不堵塞,调用立即返回;
+ * + * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 false; + * + * @return + */ + public boolean get() { + return super.isCompleted() ? (boolean) super.getValue() : false; + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ByteValueHolder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ByteValueHolder.java new file mode 100644 index 00000000..d9c024ff --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ByteValueHolder.java @@ -0,0 +1,22 @@ +package com.jd.blockchain.transaction; + +public class ByteValueHolder extends ValueHolderWrapper { + + ByteValueHolder(OperationResultHolder resultHolder) { + super(resultHolder); + } + + /** + * 获取值;
+ * + * 此方法不堵塞,调用立即返回;
+ * + * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; + * + * @return + */ + public byte get() { + return super.isCompleted() ? (byte) super.getValue() : 0; + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java new file mode 100644 index 00000000..4cacf19c --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java @@ -0,0 +1,6 @@ +package com.jd.blockchain.transaction; + +public interface ContractEventExecutor { + + T execute(); +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java index 7acc42ba..de304958 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java @@ -1,28 +1,26 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.ledger.BytesValueList; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.utils.Bytes; public class ContractEventSendOpTemplate implements ContractEventSendOperation { + static { DataContractRegistry.register(ContractEventSendOperation.class); } private Bytes contractAddress; - private byte[] args; + private BytesValueList args; private String event; - //交易操作时间; - private long txOpTime; - - public ContractEventSendOpTemplate() { - } + + private ContractInvocation invocation; - public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args) { + public ContractEventSendOpTemplate(Bytes contractAddress, String event, BytesValueList args) { this.contractAddress = contractAddress; this.event = event; this.args = args; - this.txOpTime = System.currentTimeMillis(); } @Override @@ -36,12 +34,16 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation { } @Override - public byte[] getArgs() { + public BytesValueList getArgs() { return args; } - @Override - public long getTxOpTime() { - return txOpTime; + public ContractInvocation getInvocation() { + return invocation; + } + + public void setInvocation(ContractInvocation invocation) { + this.invocation = invocation; } + } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java index 66f1ec22..675fd8d6 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java @@ -1,5 +1,6 @@ package com.jd.blockchain.transaction; +import com.jd.blockchain.ledger.BytesValueList; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.utils.Bytes; @@ -7,20 +8,17 @@ public interface ContractEventSendOperationBuilder { /** * @param address 合约地址; - * @param event 事件名; - * @param args 事件参数; + * @param event 事件名; + * @param args 事件参数; * @return */ - @Deprecated - ContractEventSendOperation send(String address, String event, byte[] args); - + ContractEventSendOperation send(String address, String event, BytesValueList args); + /** * @param address 合约地址; - * @param event 事件名; - * @param args 事件参数; + * @param event 事件名; + * @param args 事件参数; * @return */ - @Deprecated - ContractEventSendOperation send(Bytes address, String event, byte[] args); - + ContractEventSendOperation send(Bytes address, String event, BytesValueList args); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java index beccc539..faae0029 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java @@ -1,21 +1,21 @@ -package com.jd.blockchain.transaction; - -import com.jd.blockchain.ledger.ContractEventSendOperation; -import com.jd.blockchain.utils.Bytes; - -@Deprecated -class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { - - @Override - public ContractEventSendOperation send(String address, String event, byte[] args) { - ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); - return op; - } - - @Override - public ContractEventSendOperation send(Bytes address, String event, byte[] args) { - ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); - return op; - } - -} +//package com.jd.blockchain.transaction; +// +//import com.jd.blockchain.ledger.ContractEventSendOperation; +//import com.jd.blockchain.utils.Bytes; +// +//@Deprecated +//class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { +// +// @Override +// public ContractEventSendOperation send(String address, String event, byte[] args) { +// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); +// return op; +// } +// +// @Override +// public ContractEventSendOperation send(Bytes address, String event, byte[] args) { +// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); +// return op; +// } +// +//} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocation.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocation.java new file mode 100644 index 00000000..2e27fca9 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocation.java @@ -0,0 +1,50 @@ +package com.jd.blockchain.transaction; + +import java.lang.reflect.Method; + +import com.jd.blockchain.contract.ContractType; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.BytesValueEncoding; + +/** + * ContractInvocation 包装了客户端发起的一次合约方法调用的相关信息,用于在客户端交易处理上下文进行共享处理状态; + * + * @author huanghaiquan + * + */ +class ContractInvocation extends OperationResultHolder { + + private Method method; + + private ContractType contractType; + + private int operationIndex = -1; + + public ContractInvocation(ContractType contractType, Method method) { + this.contractType = contractType; + this.method = method; + } + + public ContractType getContractType() { + return contractType; + } + + @Override + public int getOperationIndex() { + return operationIndex; + } + + public void setOperationIndex(int operationIndex) { + this.operationIndex = operationIndex; + } + + public Class getReturnType() { + return method.getReturnType(); + } + + @Override + protected Object decodeResult(BytesValue bytesValue) { + return BytesValueEncoding.decode(bytesValue, method.getReturnType()); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationHandler.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationHandler.java new file mode 100644 index 00000000..8b48d509 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationHandler.java @@ -0,0 +1,75 @@ +package com.jd.blockchain.transaction; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.Arrays; + +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.contract.ContractType; +import com.jd.blockchain.ledger.BytesValueEncoding; +import com.jd.blockchain.ledger.BytesValueList; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.IllegalDataException; + +public class ContractInvocationHandler implements InvocationHandler { + + private Bytes contractAddress; + + private ContractType contractType; + + private ContractEventSendOperationBuilder sendOpBuilder; + + private int proxyHashCode; + + public ContractInvocationHandler(Bytes contractAddress, ContractType contractType, + ContractEventSendOperationBuilder sendOpBuilder) { + this.contractAddress = contractAddress; + if (contractType == null) { + throw new IllegalDataException("contractType == null, no invoke really."); + } + this.contractType = contractType; + this.sendOpBuilder = sendOpBuilder; + this.proxyHashCode = Arrays.deepHashCode(new Object[] { this, contractAddress, contractType, sendOpBuilder }); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // 判断是否是常规方法调用 + if (method.getName().equals("hashCode")) { + // 该处需要使用当前代理类的HashCode + return proxyHashCode; + } + if (method.getName().equals("toString")) { + // 该处使用当前代理类的toString + return this.toString(); + } + + String event = contractType.getEvent(method); + if (event == null) { + // 该方法不是合约可执行的方法 + throw new ContractException( + String.format("The invoking method [%s] is not annotated as event handle method by @ContractEvent!", + method.toString())); + } + // 序列化调用参数; + Class[] argTypes = method.getParameterTypes(); + BytesValueList argBytes = BytesValueEncoding.encodeArray(args, argTypes); + + // 定义合约调用操作; + ContractEventSendOpTemplate opTemplate = (ContractEventSendOpTemplate) sendOpBuilder.send(contractAddress, + event, argBytes); + + // 加入合约调用的额外信息; + ContractInvocation invocation = new ContractInvocation(contractType, method); + + // 传递给定义操作的上下文,以便在生成交易时,同步操作在交易中的索引位置; + opTemplate.setInvocation(invocation); + + // 传递给通过代理对象调用合约方法的调用者,以便可以同步操作在交易中的索引位置以及操作的返回值; + ContractInvocationStub.set(invocation); + + // 返回类型的默认值 + return BytesValueEncoding.getDefaultValue(method.getReturnType()); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java deleted file mode 100644 index f5f83708..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.jd.blockchain.transaction; - -import com.jd.blockchain.contract.ContractSerializeUtils; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.IllegalDataException; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; - -public class ContractInvocationProxy implements InvocationHandler { - - // private String contractMessage; - - private Bytes contractAddress; - - private ContractType contractType; - - private ContractEventSendOperationBuilder sendOpBuilder; - - public ContractInvocationProxy(Bytes contractAddress, ContractType contractType, - ContractEventSendOperationBuilder sendOpBuilder) { - this.contractAddress = contractAddress; - if(contractType == null){ - throw new IllegalDataException("contractType == null, no invoke really."); - } - this.contractType = contractType; - this.sendOpBuilder = sendOpBuilder; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String event = contractType.getEvent(method); - if (event == null) { - // 适配 Object 对象的方法; - // toString 方法; - return String.format("[%s]-%s", contractAddress, contractType.toString()); - - // hashCode 方法; - } - // 合约方法; - byte[] argBytes = serializeArgs(args,method); - sendOpBuilder.send(contractAddress, event, argBytes); - - // TODO: 暂时未考虑有返回值的情况; - return null; - } - - private byte[] serializeArgs(Object[] args, Method method) { - if(args == null || args.length==0){ - return null; - } - return ContractSerializeUtils.serializeMethodParam(args,contractType.getDataContractMap().get(method)); - } -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java index 06c6b386..e5e7b947 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java @@ -1,18 +1,18 @@ package com.jd.blockchain.transaction; -import com.jd.blockchain.contract.Contract; -import com.jd.blockchain.contract.ContractEvent; -import com.jd.blockchain.utils.BaseConstant; -import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.IllegalDataException; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import com.jd.blockchain.contract.ContractType; +import com.jd.blockchain.utils.Bytes; + +/** + * 合约调用代理的构建器; + * + * @author huanghaiquan + * + */ public class ContractInvocationProxyBuilder { private Map, ContractType> contractTypes = new ConcurrentHashMap<>(); @@ -25,12 +25,11 @@ public class ContractInvocationProxyBuilder { public T create(Bytes address, Class contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { ContractType contractType = resolveContractType(contractIntf); - ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType, - contractEventBuilder); + ContractInvocationHandler proxyHandler = new ContractInvocationHandler(address, contractType, contractEventBuilder); + T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { contractIntf }, proxyHandler); - - return (T) proxy; + return proxy; } private ContractType resolveContractType(Class contractIntf) { @@ -38,21 +37,8 @@ public class ContractInvocationProxyBuilder { if (contractType != null) { return contractType; } - // TODO 检查返回值类型; - - ContractType contractType1 = ContractType.resolve(contractIntf); - contractTypes.put(contractIntf,contractType1); - return contractType1; - } - - - /** - * is contractType really? identified by @Contract; - * @param contractIntf - * @return - */ - private boolean isContractType(Class contractIntf) { - Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class); - return annotation != null ? true : false; + ContractType ct = ContractType.resolve(contractIntf); + contractTypes.put(contractIntf, ct); + return ct; } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationStub.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationStub.java new file mode 100644 index 00000000..661319b1 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationStub.java @@ -0,0 +1,33 @@ +package com.jd.blockchain.transaction; + +/** + * 用于在上下文中传递合约调用返回值的工具类; + * + * @author huanghaiquan + * + */ +class ContractInvocationStub { + + private static ThreadLocal stub = new ThreadLocal(); + + private ContractInvocationStub() { + } + + public static void set(ContractInvocation invocation) { + if (invocation == null) { + throw new IllegalArgumentException("Null stub value!"); + } + stub.set(invocation); + } + + public static ContractInvocation take() { + ContractInvocation subValue = stub.get(); + if (subValue == null) { + throw new IllegalStateException( + "The latest invocation of contract has not been stubbed! It may be caused by the wrong call sequence from the upper layer!"); + } + stub.remove(); + return subValue; + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractReturnValue.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractReturnValue.java new file mode 100644 index 00000000..9fee9ea7 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractReturnValue.java @@ -0,0 +1,164 @@ +package com.jd.blockchain.transaction; + +public class ContractReturnValue { + + private ContractReturnValue() { + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * import static com.jd.blockchain.transaction.ContractReturnValue.*;

+ * + * + * ValueHolder + * + * PreparedTransaction prepTx = tx.prepare();
+ * prepTx.sign(userKey);
+ * prepTx.commit()

+ * + * String retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
+ *
+ * + * @param + * @param call + * @return + */ + public static GenericValueHolder decode(T call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new GenericValueHolder(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * import static com.jd.blockchain.transaction.ContractReturnValue.*;

+ * + * + * LongValueHolder retnHolder = decode(contract.issue(assetKey, amount));
+ * + * PreparedTransaction prepTx = tx.prepare();
+ * prepTx.sign(userKey);
+ * prepTx.commit()

+ * + * long retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
+ *
+ * + * @param call + * @return + */ + public static LongValueHolder decode(long call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new LongValueHolder(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * import static com.jd.blockchain.transaction.ContractReturnValue.*;

+ * + * + * IntValueHolder retnHolder = decode(contract.issue(assetKey, amount));
+ * + * PreparedTransaction prepTx = tx.prepare();
+ * prepTx.sign(userKey);
+ * prepTx.commit()

+ * + * int retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
+ *
+ * + * @param call + * @return + */ + public static IntValueHolder decode(int call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new IntValueHolder(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * import static com.jd.blockchain.transaction.ContractReturnValue.*;

+ * + * + * ShortValueHolder retnHolder = decode(contract.issue(assetKey, amount));
+ * + * PreparedTransaction prepTx = tx.prepare();
+ * prepTx.sign(userKey);
+ * prepTx.commit()

+ * + * short retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
+ *
+ * + * @param call + * @return + */ + public static ShortValueHolder decode(short call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new ShortValueHolder(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * import static com.jd.blockchain.transaction.ContractReturnValue.*;

+ * + * + * ByteValueHolder retnHolder = decode(contract.issue(assetKey, amount));
+ * + * PreparedTransaction prepTx = tx.prepare();
+ * prepTx.sign(userKey);
+ * prepTx.commit()

+ * + * byte retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
+ *
+ * + * @param call + * @return + */ + public static ByteValueHolder decode(byte call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new ByteValueHolder(invocation); + } + + /** + * 解析合约方法调用的返回值; + *

+ * 用法示例:
+ * + * import static com.jd.blockchain.transaction.ContractReturnValue.*;

+ * + * + * BooleanValueHolder retnHolder = decode(contract.issue(assetKey, amount));
+ * + * PreparedTransaction prepTx = tx.prepare();
+ * prepTx.sign(userKey);
+ * prepTx.commit()

+ * + * boolean retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
+ *
+ * + * @param call + * @return + */ + public static BooleanValueHolder decode(boolean call) { + ContractInvocation invocation = ContractInvocationStub.take(); + return new BooleanValueHolder(invocation); + } + + + //----------------------- 内部类型 ----------------------- + + + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java deleted file mode 100644 index 8110fc33..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.jd.blockchain.transaction; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.contract.Contract; -import com.jd.blockchain.contract.ContractEvent; -import com.jd.blockchain.contract.ContractException; -import com.jd.blockchain.contract.ContractSerializeUtils; -import com.jd.blockchain.utils.IllegalDataException; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.*; - -public class ContractType { - - private String name; - private Map events = new HashMap<>(); - private Map handleMethods = new HashMap<>(); - private Map> dataContractMap = new HashMap<>(); - - /** - * 返回声明的所有事件; - * - * @return - */ - public Set getEvents() { - return events.keySet(); - } - - public Map> getDataContractMap() { - return dataContractMap; - } - - /** - * 返回指定方法声明的事件;
- * - * 如果不存在,则返回 null; - * - * @param method - * @return - */ - public String getEvent(Method method) { - return handleMethods.get(method); - } - - /** - * 返回事件的处理方法;
- * - * 如果不存在,则返回 null; - * - * @param event - * @return - */ - public Method getHandleMethod(String event) { - return events.get(event); - } - - private ContractType() { - } - - public static ContractType resolve(Class contractIntf){ - ContractType contractType = new ContractType(); - - Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class); - - //contains: @Contract? - boolean isContractType = annotation != null ? true : false; - if(!isContractType){ - throw new IllegalDataException("is not Contract Type, becaust there is not @Contract."); - } - - //contractIntf contains @Contract and @ContractEvent; - Method[] classMethods = contractIntf.getDeclaredMethods(); - for (Method method : classMethods) { - // if current method contains @ContractEvent,then put it in this map; - ContractEvent contractEvent = method.getAnnotation(ContractEvent.class); - if (contractEvent != null) { - String eventName_ = contractEvent.name(); - //if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO! - if(contractType.events.containsKey(eventName_)){ - throw new ContractException("there is repeat definition of contractEvent to @ContractEvent."); - } - //check param's type is fit for need. - Class[] paramTypes = method.getParameterTypes(); - List dataContractList = new ArrayList(); - for(Class curParamType : paramTypes){ - DataContract dataContract = ContractSerializeUtils.parseDataContract(curParamType); - dataContractList.add(dataContract); - } - if(dataContractList.size()>0){ - contractType.dataContractMap.put(method,dataContractList); - } - - contractType.events.put(eventName_, method); - contractType.handleMethods.put(method,eventName_); - } - } - return contractType; - } - - @Override - public String toString() { - return "ContractType{" + - "name='" + name + '\'' + - ", events=" + events + - ", handleMethods=" + handleMethods + - '}'; - } -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java index d8125022..b2ccef13 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/DataAccountKVSetOperationBuilderImpl.java @@ -1,7 +1,7 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesValueEntry; +import com.jd.blockchain.ledger.BytesData; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.utils.Bytes; @@ -26,14 +26,14 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe @Override public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromBytes(value); + BytesValue bytesValue = BytesData.fromBytes(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromImage(value); + BytesValue bytesValue = BytesData.fromImage(value); operation.set(key, bytesValue, expVersion); return this; } @@ -45,42 +45,42 @@ public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOpe @Override public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromText(value); + BytesValue bytesValue = BytesData.fromText(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromBytes(value); + BytesValue bytesValue = BytesData.fromBytes(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromInt64(value); + BytesValue bytesValue = BytesData.fromInt64(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromJSON(value); + BytesValue bytesValue = BytesData.fromJSON(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromXML(value); + BytesValue bytesValue = BytesData.fromXML(value); operation.set(key, bytesValue, expVersion); return this; } @Override public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { - BytesValue bytesValue = BytesValueEntry.fromTimestamp(value); + BytesValue bytesValue = BytesData.fromTimestamp(value); operation.set(key, bytesValue, expVersion); return this; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java index fd001fb6..8540a470 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java @@ -4,14 +4,6 @@ import com.jd.blockchain.utils.Bytes; public interface EventOperator { - // /** - // * 合约事件; - // * - // * @return - // */ - // @Deprecated - // ContractEventSendOperationBuilder contractEvents(); - /** * 创建调用合约的代理实例; * @@ -30,4 +22,11 @@ public interface EventOperator { */ T contract(Bytes address, Class contractIntf); +// /** +// * 执行合约异步等待应答结果 +// * +// * @param execute +// * @return +// */ +// EventResult result(ContractEventExecutor execute); } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/GenericValueHolder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/GenericValueHolder.java new file mode 100644 index 00000000..1832f315 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/GenericValueHolder.java @@ -0,0 +1,23 @@ +package com.jd.blockchain.transaction; + +public class GenericValueHolder extends ValueHolderWrapper { + + GenericValueHolder(OperationResultHolder resultHolder) { + super(resultHolder); + } + + /** + * 获取值;
+ * + * 此方法不堵塞,调用立即返回;
+ * + * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 null; + * + * @return + */ + @SuppressWarnings("unchecked") + public T get() { + return (T) super.getValue(); + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/IntValueHolder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/IntValueHolder.java new file mode 100644 index 00000000..5e490ca3 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/IntValueHolder.java @@ -0,0 +1,22 @@ +package com.jd.blockchain.transaction; + +public class IntValueHolder extends ValueHolderWrapper { + + IntValueHolder(OperationResultHolder resultHolder) { + super(resultHolder); + } + + /** + * 获取值;
+ * + * 此方法不堵塞,调用立即返回;
+ * + * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; + * + * @return + */ + public int get() { + return super.isCompleted() ? (int) super.getValue() : 0; + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/LongValueHolder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/LongValueHolder.java new file mode 100644 index 00000000..e5409f29 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/LongValueHolder.java @@ -0,0 +1,22 @@ +package com.jd.blockchain.transaction; + +public class LongValueHolder extends ValueHolderWrapper { + + LongValueHolder(OperationResultHolder resultHolder) { + super(resultHolder); + } + + /** + * 获取值;
+ * + * 此方法不堵塞,调用立即返回;
+ * + * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; + * + * @return + */ + public long get() { + return super.isCompleted() ? (long) super.getValue() : 0; + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationCompletedContext.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationCompletedContext.java new file mode 100644 index 00000000..1197f95b --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationCompletedContext.java @@ -0,0 +1,24 @@ +package com.jd.blockchain.transaction; + +import com.jd.blockchain.ledger.BytesValue; + +public class OperationCompletedContext { + + private int operationIndex; + + private BytesValue returnBytesValue; + + public OperationCompletedContext(int operationIndex, BytesValue returnBytesValue) { + this.operationIndex = operationIndex; + this.returnBytesValue = returnBytesValue; + } + + public int getOperationIndex() { + return operationIndex; + } + + public BytesValue getReturnBytesValue() { + return returnBytesValue; + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationCompletedListener.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationCompletedListener.java new file mode 100644 index 00000000..c11f27dd --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationCompletedListener.java @@ -0,0 +1,20 @@ +package com.jd.blockchain.transaction; + +/** + * 操作完成监听器; + * + * @author huanghaiquan + * + */ +public interface OperationCompletedListener { + + /** + * 当操作完成时发生; + * + * @param retnValue 返回值; + * @param error 异常;如果值为非空,则表示由异常导致结束; + * @param context 上下文对象; + */ + void onCompleted(Object retnValue, Throwable error, OperationCompletedContext context); + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHandle.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHandle.java new file mode 100644 index 00000000..12bc7b33 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHandle.java @@ -0,0 +1,35 @@ +package com.jd.blockchain.transaction; + +import com.jd.blockchain.ledger.BytesValue; + +/** + * 操作返回值处理器; + * + * @author huanghaiquan + * + */ +interface OperationResultHandle { + + /** + * 操作的索引位置; + * + * @return + */ + int getOperationIndex(); + + /** + * 正常地完成; + * + * @param returnBytesValue + * @return + */ + Object complete(BytesValue returnBytesValue); + + /** + * 以异常方式完成; + * + * @param error + */ + void complete(Throwable error); + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHolder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHolder.java new file mode 100644 index 00000000..2f8ec8e6 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHolder.java @@ -0,0 +1,82 @@ +package com.jd.blockchain.transaction; + +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.utils.event.EventMulticaster; + +abstract class OperationResultHolder implements OperationResultHandle { + + private Object value; + + private Throwable error; + + private volatile boolean completed; + + private EventMulticaster listenerMulticaster = + new EventMulticaster<>(OperationCompletedListener.class); + + /** + * 导致结束的错误; + * + * @return + */ + public Throwable getError() { + return error; + } + + /** + * 是否已经处理完成; + * + * @return + */ + public boolean isCompleted() { + return completed; + } + + /** + * 获取操作的返回值;
+ * 在操作未完成之前,总是返回 null;
+ * 可以通过 {@link #isCompleted()} 方法判断操作是否已经完成;
+ * 可以通过 {@link #addCompletedListener(OperationCompletedListener)} + * 方法添加监听器来监听操作完成的事件; + * + * @return + */ + public Object getResult() { + return value; + } + + /** + * 添加操作完成监听器; + * + * @param listener + */ + public void addCompletedListener(OperationCompletedListener listener) { + listenerMulticaster.addListener(listener); + } + + protected abstract Object decodeResult(BytesValue bytesValue); + + @Override + public Object complete(BytesValue bytesValue) { + if (this.completed) { + throw new IllegalStateException( + "Contract invocation has been completed, and is not allowed to be completed again!"); + } + this.completed = true; + this.value = decodeResult(bytesValue); + OperationCompletedContext context = new OperationCompletedContext(getOperationIndex(), null); + listenerMulticaster.getBroadcaster().onCompleted(value, null, context); + return null; + } + + @Override + public void complete(Throwable error) { + if (completed) { + return; + } + this.completed = true; + this.error = error; + OperationCompletedContext context = new OperationCompletedContext(getOperationIndex(), null); + listenerMulticaster.getBroadcaster().onCompleted(null, error, context); + } +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java index 2b0422c0..b2d0f107 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java @@ -1,5 +1,12 @@ package com.jd.blockchain.transaction; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; + +import org.springframework.cglib.proxy.UndeclaredThrowableException; + import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.Crypto; @@ -8,6 +15,7 @@ import com.jd.blockchain.crypto.PrivKey; import com.jd.blockchain.crypto.SignatureDigest; import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.ledger.DigitalSignature; +import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionRequest; @@ -20,9 +28,32 @@ public class PreparedTx implements PreparedTransaction { private TransactionService txProcessor; - public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor) { + private OperationResultHandle[] opReturnValueHandlers; + + private TxStateManager stateManager; + + /** + * 创建一个“就绪交易”对象; + * + * @param txReqBuilder 交易请求构建器; + * @param txProcessor 交易处理服务; + * @param opReturnValueHandlerList 操作返回值处理器列表; + */ + public PreparedTx(TxStateManager stateManager, TransactionRequestBuilder txReqBuilder, + TransactionService txProcessor, Collection opReturnValueHandlerList) { + this.stateManager = stateManager; this.txReqBuilder = txReqBuilder; this.txProcessor = txProcessor; + + this.opReturnValueHandlers = opReturnValueHandlerList + .toArray(new OperationResultHandle[opReturnValueHandlerList.size()]); + // 按照操作索引升序排列; + Arrays.sort(opReturnValueHandlers, new Comparator() { + @Override + public int compare(OperationResultHandle o1, OperationResultHandle o2) { + return o1.getOperationIndex() - o2.getOperationIndex(); + } + }); } @Override @@ -53,9 +84,60 @@ public class PreparedTx implements PreparedTransaction { @Override public TransactionResponse commit() { - TransactionRequest txReq = txReqBuilder.buildRequest(); - // 发起交易请求; - TransactionResponse txResponse = txProcessor.process(txReq); + stateManager.commit(); + TransactionResponse txResponse = null; + try { + TransactionRequest txReq = txReqBuilder.buildRequest(); + // 发起交易请求; + txResponse = txProcessor.process(txReq); + + stateManager.complete(); + + } catch (Exception ex) { + stateManager.close(); + handleError(ex); + throw new UndeclaredThrowableException(ex); + } + + if (txResponse != null) { + handleResults(txResponse); + } + return txResponse; } + + @Override + public void close() throws IOException { + if (!stateManager.close()) { + TransactionCancelledExeption error = new TransactionCancelledExeption( + "Prepared transaction has been cancelled!"); + handleError(error); + } + } + + private void handleError(Throwable error) { + for (OperationResultHandle handle : opReturnValueHandlers) { + handle.complete(error); + } + } + + private void handleResults(TransactionResponse txResponse) { + // 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的; + OperationResult[] opResults = txResponse.getOperationResults(); + if (opResults != null && opResults.length > 0) { + if (opResults.length != opReturnValueHandlers.length) { + throw new IllegalStateException(String.format( + "The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]", + txResponse.getContentHash(), opResults.length, opReturnValueHandlers.length)); + } + for (int i = 0; i < opResults.length; i++) { + if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) { + throw new IllegalStateException( + "The operation indexes of the items in the result list and in the handler list don't match!"); + } + opReturnValueHandlers[i].complete(opResults[i].getResult()); + } + } + } + } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ShortValueHolder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ShortValueHolder.java new file mode 100644 index 00000000..f9867d65 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ShortValueHolder.java @@ -0,0 +1,22 @@ +package com.jd.blockchain.transaction; + +public class ShortValueHolder extends ValueHolderWrapper { + + ShortValueHolder(OperationResultHolder resultHolder) { + super(resultHolder); + } + + /** + * 获取值;
+ * + * 此方法不堵塞,调用立即返回;
+ * + * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 0; + * + * @return + */ + public short get() { + return super.isCompleted() ? (short) super.getValue() : 0; + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TransactionCancelledExeption.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TransactionCancelledExeption.java new file mode 100644 index 00000000..69e37b24 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TransactionCancelledExeption.java @@ -0,0 +1,15 @@ +package com.jd.blockchain.transaction; + +public class TransactionCancelledExeption extends RuntimeException { + + private static final long serialVersionUID = -2577951411093171806L; + + public TransactionCancelledExeption(String message) { + super(message); + } + + public TransactionCancelledExeption(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java index 12fe552f..cb32c1bd 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java @@ -1,5 +1,7 @@ package com.jd.blockchain.transaction; +import java.util.Collection; + import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.crypto.Crypto; @@ -49,6 +51,10 @@ public class TxBuilder implements TransactionBuilder { return txContent; } + public Collection getReturnValuehandlers() { + return opFactory.getReturnValuetHandlers(); + } + @Override public LedgerInitOperationBuilder ledgers() { return opFactory.ledgers(); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java index 5265b4be..7d6701a5 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java @@ -71,8 +71,7 @@ public class TxRequestBuilder implements TransactionRequestBuilder { } public static SignatureDigest sign(TransactionContent txContent, PrivKey privKey) { - return Crypto.getSignatureFunction(privKey.getAlgorithm()).sign(privKey, - txContent.getHash().toBytes()); + return Crypto.getSignatureFunction(privKey.getAlgorithm()).sign(privKey, txContent.getHash().toBytes()); } public static boolean verifySignature(TransactionContent txContent, SignatureDigest signDigest, PubKey pubKey) { diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java index 5d143898..57107ff3 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java @@ -2,6 +2,7 @@ package com.jd.blockchain.transaction; import com.jd.blockchain.ledger.TransactionState; import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.TransactionResponse; /** @@ -18,10 +19,19 @@ public class TxResponseMessage implements TransactionResponse { private TransactionState executionState; - private String[] contractReturn; + private OperationResult[] operationResults; public TxResponseMessage() { } + + // 重新包装operationResults + public TxResponseMessage(TransactionResponse transactionResponse, OperationResult[] operationResults) { + this.contentHash = transactionResponse.getContentHash(); + this.blockHash = transactionResponse.getBlockHash(); + this.blockHeight = transactionResponse.getBlockHeight(); + this.executionState = transactionResponse.getExecutionState(); + this.operationResults = operationResults; + } public TxResponseMessage(HashDigest contentHash) { this.contentHash = contentHash; @@ -59,8 +69,8 @@ public class TxResponseMessage implements TransactionResponse { this.blockHeight = blockHeight; } - public void setContractReturn(String[] contractReturn) { - this.contractReturn = contractReturn; + public void setOperationResults(OperationResult[] operationResults) { + this.operationResults = operationResults; } @Override @@ -69,8 +79,8 @@ public class TxResponseMessage implements TransactionResponse { } @Override - public String[] getContractReturn() { - return contractReturn; + public OperationResult[] getOperationResults() { + return operationResults; } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxStateManager.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxStateManager.java new file mode 100644 index 00000000..db799f1d --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxStateManager.java @@ -0,0 +1,76 @@ +package com.jd.blockchain.transaction; + +class TxStateManager { + + private State state = State.OPERABLE; + + public void operate() { + if (state != State.OPERABLE) { + throw new IllegalStateException(String.format("Cannot define operations in %s state!", state)); + } + } + + public void prepare() { + if (state != State.OPERABLE) { + throw new IllegalStateException( + String.format("Cannot switch to %s state in %s state!", State.PREPARED, state)); + } + state = State.PREPARED; + } + + public void commit() { + if (state != State.PREPARED) { + throw new IllegalStateException( + String.format("Cannot switch to %s state in %s state!", State.COMMITTED, state)); + } + state = State.COMMITTED; + } + + public void complete() { + if (state != State.COMMITTED) { + throw new IllegalStateException(String.format("Cannot complete normally in %s state!", state)); + } + state = State.CLOSED; + } + + /** + * 关闭交易; + * + * @param error + * @return 此次操作前是否已经处于关闭状态;
+ * 如果返回 true ,则表示之前已经处于关闭状态,此次操作将被忽略;
+ * 如果返回 fasle,则表示之前处于非关闭状态,此次操作将切换为关闭状态; + */ + public boolean close() { + if (state == State.CLOSED) { + return true; + } + state = State.CLOSED; + return false; + } + + private static enum State { + + /** + * 可操作; + */ + OPERABLE, + + /** + * 就绪; + */ + PREPARED, + + /** + * 已提交; + */ + COMMITTED, + + /** + * 已关闭; + */ + CLOSED + + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java index 984ecf07..9777d238 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java @@ -1,5 +1,8 @@ package com.jd.blockchain.transaction; +import java.io.IOException; +import java.util.Collection; + import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.PreparedTransaction; import com.jd.blockchain.ledger.TransactionRequestBuilder; @@ -12,7 +15,10 @@ public class TxTemplate implements TransactionTemplate { private TransactionService txService; + private TxStateManager stateManager; + public TxTemplate(HashDigest ledgerHash, TransactionService txService) { + this.stateManager = new TxStateManager(); this.txBuilder = new TxBuilder(ledgerHash); this.txService = txService; } @@ -24,48 +30,63 @@ public class TxTemplate implements TransactionTemplate { @Override public PreparedTransaction prepare() { + stateManager.prepare(); TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); - return new PreparedTx(txReqBuilder, txService); + return new PreparedTx(stateManager, txReqBuilder, txService, txBuilder.getReturnValuehandlers()); } @Override public UserRegisterOperationBuilder users() { + stateManager.operate(); return txBuilder.users(); } @Override public DataAccountRegisterOperationBuilder dataAccounts() { + stateManager.operate(); return txBuilder.dataAccounts(); } - + @Override public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { + stateManager.operate(); return txBuilder.dataAccount(accountAddress); } @Override public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { + stateManager.operate(); return txBuilder.dataAccount(accountAddress); } @Override public ContractCodeDeployOperationBuilder contracts() { + stateManager.operate(); return txBuilder.contracts(); } -// @Override -// public ContractEventSendOperationBuilder contractEvents() { -// return txBuilder.contractEvents(); -// } - @Override public T contract(Bytes address, Class contractIntf) { + stateManager.operate(); return txBuilder.contract(address, contractIntf); } - + @Override public T contract(String address, Class contractIntf) { + stateManager.operate(); return txBuilder.contract(address, contractIntf); } + @Override + public void close() throws IOException { + if (!stateManager.close()) { + Collection handlers = txBuilder.getReturnValuehandlers(); + if (handlers.size() > 0) { + TransactionCancelledExeption error = new TransactionCancelledExeption("Transaction template has been cancelled!"); + for (OperationResultHandle handle : handlers) { + handle.complete(error); + } + } + } + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ValueHolderWrapper.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ValueHolderWrapper.java new file mode 100644 index 00000000..42c4f86b --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ValueHolderWrapper.java @@ -0,0 +1,34 @@ +package com.jd.blockchain.transaction; + +class ValueHolderWrapper { + private OperationResultHolder valueHolder; + + protected ValueHolderWrapper(OperationResultHolder valueHolder) { + this.valueHolder = valueHolder; + } + + public boolean isCompleted() { + return valueHolder.isCompleted(); + } + + public Throwable getError() { + return valueHolder.getError(); + } + + /** + * 获取值;
+ * + * 此方法不堵塞,调用立即返回;
+ * + * 如果未完成时( {@link #isCompleted()} 为 false ),总是返回 null; + * + * @return + */ + protected Object getValue() { + return valueHolder.getResult(); + } + + public void addCompletedListener(OperationCompletedListener listener) { + valueHolder.addCompletedListener(listener); + } +} \ No newline at end of file diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/BytesToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/BytesToBytesValueResolverTest.java new file mode 100644 index 00000000..fb470200 --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/BytesToBytesValueResolverTest.java @@ -0,0 +1,43 @@ +package test.com.jd.blockchain.ledger.data; + +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.ledger.resolver.BytesToBytesValueResolver; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; +import static org.junit.Assert.*; +import org.junit.Test; + +public class BytesToBytesValueResolverTest { + + private BytesToBytesValueResolver resolver = new BytesToBytesValueResolver(); + + @Test + public void test() { + String text = "www.jd.com"; + + byte[] bytes = BytesUtils.toBytes(text); + + Bytes bytesObj = Bytes.fromString(text); + + BytesValue bytesValue = resolver.encode(bytes); + + assertNotNull(bytesValue); + + assertEquals(bytesValue.getType(), DataType.BYTES); + + assertEquals(bytesObj, bytesValue.getValue()); + + Bytes resolveBytesObj = (Bytes)resolver.decode(bytesValue); + + assertEquals(bytesObj, resolveBytesObj); + + byte[] resolveBytes = (byte[])resolver.decode(bytesValue, byte[].class); + + assertArrayEquals(bytes, resolveBytes); + + String resolveText = (String)resolver.decode(bytesValue, String.class); + + assertEquals(text, resolveText); + } +} diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/BytesValueEncodingTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/BytesValueEncodingTest.java new file mode 100644 index 00000000..73d51d7b --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/BytesValueEncodingTest.java @@ -0,0 +1,69 @@ +package test.com.jd.blockchain.ledger.data; + +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.utils.Bytes; +import static org.junit.Assert.*; +import org.junit.Test; + +public class BytesValueEncodingTest { + @Test + public void testSupport() { + assertTrue(BytesValueEncoding.supportType(byte[].class)); + assertTrue(BytesValueEncoding.supportType(int.class)); + assertTrue(BytesValueEncoding.supportType(Integer.class)); + assertTrue(BytesValueEncoding.supportType(short.class)); + assertTrue(BytesValueEncoding.supportType(Short.class)); + assertTrue(BytesValueEncoding.supportType(long.class)); + assertTrue(BytesValueEncoding.supportType(Long.class)); + assertTrue(BytesValueEncoding.supportType(String.class)); + assertTrue(BytesValueEncoding.supportType(Bytes.class)); + assertTrue(BytesValueEncoding.supportType(Operation.class)); + assertFalse(BytesValueEncoding.supportType(byte.class)); + } + + @Test + public void testSingle() { + long longVal = 1024L; + BytesValue longBytesVal1 = BytesValueEncoding.encodeSingle(longVal, null); + BytesValue longBytesVal2 = BytesValueEncoding.encodeSingle(longVal, long.class); + BytesValue longBytesVal3 = BytesValueEncoding.encodeSingle(longVal, Long.class); + + assertEquals(longBytesVal1.getValue(), longBytesVal2.getValue()); + assertEquals(longBytesVal1.getType(), longBytesVal2.getType()); + assertEquals(longBytesVal2.getValue(), longBytesVal3.getValue()); + assertEquals(longBytesVal2.getType(), longBytesVal3.getType()); + + long resolveLongVal1 = (long)BytesValueEncoding.decode(longBytesVal1); + long resolveLongVal2 = (long)BytesValueEncoding.decode(longBytesVal2); + long resolveLongVal3 = (long)BytesValueEncoding.decode(longBytesVal3); + + assertEquals(resolveLongVal1, 1024L); + assertEquals(resolveLongVal2, 1024L); + assertEquals(resolveLongVal3, 1024L); + } + + @Test + public void testArray() { + Object[] values = new Object[]{1024L, "zhangsan", "lisi".getBytes(), 16}; + Class[] classes = new Class[]{long.class, String.class, byte[].class, int.class}; + + BytesValueList bytesValueList = BytesValueEncoding.encodeArray(values, null); + BytesValueList bytesValueList1 = BytesValueEncoding.encodeArray(values, classes); + + assertEquals(bytesValueList1.getValues().length, values.length); + + + BytesValue[] bytesValues = bytesValueList.getValues(); + assertEquals(bytesValues.length, values.length); + + assertEquals(DataType.INT64, bytesValues[0].getType()); + assertEquals(DataType.TEXT, bytesValues[1].getType()); + assertEquals(DataType.BYTES, bytesValues[2].getType()); + assertEquals(DataType.INT32, bytesValues[3].getType()); + + Object[] resolveObjs = BytesValueEncoding.decode(bytesValueList, classes); + + assertArrayEquals(resolveObjs, values); + } + +} diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractEventSendOpTemplateTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractEventSendOpTemplateTest.java index fb197953..bdfaaa80 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractEventSendOpTemplateTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractEventSendOpTemplateTest.java @@ -8,21 +8,22 @@ */ package test.com.jd.blockchain.ledger.data; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.ledger.BytesData; +import com.jd.blockchain.ledger.BytesDataList; +import com.jd.blockchain.ledger.BytesValueList; import com.jd.blockchain.ledger.ContractEventSendOperation; -import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.transaction.ContractEventSendOpTemplate; -import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; import com.jd.blockchain.utils.Bytes; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - /** * * @author shaozhuguang @@ -32,34 +33,37 @@ import static org.junit.Assert.assertEquals; public class ContractEventSendOpTemplateTest { - private ContractEventSendOpTemplate data; + private ContractEventSendOpTemplate data; - @Before - public void initContractEventSendOpTemplate() { - DataContractRegistry.register(ContractEventSendOperation.class); - DataContractRegistry.register(Operation.class); - String contractAddress = "zhangsan-address", event = "zhangsan-event"; - byte[] args = "zhangsan-args".getBytes(); - data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args); - } + @Before + public void initContractEventSendOpTemplate() { + DataContractRegistry.register(BytesValueList.class); + DataContractRegistry.register(ContractEventSendOperation.class); + DataContractRegistry.register(Operation.class); + String contractAddress = "zhangsan-address", event = "zhangsan-event"; + BytesValueList args = new BytesDataList(BytesData.fromText("zhangsan-args")); + data = new ContractEventSendOpTemplate(Bytes.fromString(contractAddress), event, args); + } - @Test - public void testSerialize_ContractEventSendOperation() throws Exception { - byte[] serialBytes = BinaryProtocol.encode(data, ContractEventSendOperation.class); - ContractEventSendOperation resolvedData = BinaryProtocol.decode(serialBytes); - System.out.println("------Assert start ------"); - assertEquals(resolvedData.getContractAddress(), data.getContractAddress()); - assertEquals(resolvedData.getEvent(), data.getEvent()); - assertArrayEquals(resolvedData.getArgs(), data.getArgs()); - System.out.println("------Assert OK ------"); - } + @Test + public void testSerialize_ContractEventSendOperation() throws Exception { + byte[] serialBytes = BinaryProtocol.encode(data, ContractEventSendOperation.class); + ContractEventSendOperation resolvedData = BinaryProtocol.decode(serialBytes); + System.out.println("------Assert start ------"); + assertEquals(resolvedData.getContractAddress(), data.getContractAddress()); + assertEquals(resolvedData.getEvent(), data.getEvent()); + byte[] expectedBytes = BinaryProtocol.encode(resolvedData.getArgs(), BytesValueList.class); + byte[] actualBytes = BinaryProtocol.encode(data.getArgs(), BytesValueList.class); + assertArrayEquals(expectedBytes, actualBytes); + System.out.println("------Assert OK ------"); + } - @Test - public void testSerialize_Operation() throws Exception { - byte[] serialBytes = BinaryProtocol.encode(data, Operation.class); - Operation resolvedData = BinaryProtocol.decode(serialBytes); - System.out.println("------Assert start ------"); - System.out.println(resolvedData); - System.out.println("------Assert OK ------"); - } + @Test + public void testSerialize_Operation() throws Exception { + byte[] serialBytes = BinaryProtocol.encode(data, Operation.class); + Operation resolvedData = BinaryProtocol.decode(serialBytes); + System.out.println("------Assert start ------"); + System.out.println(resolvedData); + System.out.println("------Assert OK ------"); + } } \ No newline at end of file diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractTypeTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractTypeTest.java new file mode 100644 index 00000000..beceb39c --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractTypeTest.java @@ -0,0 +1,68 @@ +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("NORMAL-CONTRACT", contractType.getName()); + + Set 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 ex = null; + try { + ContractType.resolve(NormalContractImpl.class); + } catch (ContractException e) { + ex = e; + } + assertNull(ex); + } + +} diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/DataAccountKVSetOpTemplateTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/DataAccountKVSetOpTemplateTest.java index 005af7c6..a87919b4 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/DataAccountKVSetOpTemplateTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/DataAccountKVSetOpTemplateTest.java @@ -16,7 +16,7 @@ import org.junit.Test; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.ledger.BytesValueEntry; +import com.jd.blockchain.ledger.BytesData; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; @@ -29,7 +29,6 @@ import com.jd.blockchain.utils.Bytes; * @create 2018/8/30 * @since 1.0.0 */ -//todo 尚未测试通过,等张爽处理完再测试 public class DataAccountKVSetOpTemplateTest { private DataAccountKVSetOpTemplate data; @@ -42,11 +41,11 @@ public class DataAccountKVSetOpTemplateTest { String accountAddress = "zhangsandhakhdkah"; data = new DataAccountKVSetOpTemplate(Bytes.fromString(accountAddress)); KVData kvData1 = - new KVData("test1", BytesValueEntry.fromText("zhangsan"), 9999L); + new KVData("test1", BytesData.fromText("zhangsan"), 9999L); KVData kvData2 = - new KVData("test2", BytesValueEntry.fromText("lisi"), 9990L); + new KVData("test2", BytesData.fromText("lisi"), 9990L); KVData kvData3 = - new KVData("test3", BytesValueEntry.fromText("wangwu"), 1990L); + new KVData("test3", BytesData.fromText("wangwu"), 1990L); data.set(kvData1); data.set(kvData2); data.set(kvData3); diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/IntegerToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/IntegerToBytesValueResolverTest.java new file mode 100644 index 00000000..4b65ae16 --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/IntegerToBytesValueResolverTest.java @@ -0,0 +1,51 @@ +package test.com.jd.blockchain.ledger.data; + +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.ledger.resolver.IntegerToBytesValueResolver; +import static org.junit.Assert.*; + +import com.jd.blockchain.utils.Bytes; +import org.junit.Test; + +public class IntegerToBytesValueResolverTest { + + private IntegerToBytesValueResolver resolver = new IntegerToBytesValueResolver(); + + @Test + public void test() { + int intVal = 1024; + + BytesValue intBytesValue = resolver.encode(intVal); + + BytesValue intBytesValue1 = resolver.encode(intVal, int.class); + + BytesValue intBytesValue2 = resolver.encode(intVal, Integer.class); + + assertEquals(intBytesValue.getValue(), intBytesValue1.getValue()); + + assertEquals(intBytesValue.getValue(), intBytesValue2.getValue()); + + Bytes intBytes = Bytes.fromInt(intVal); + + assertEquals(intBytes, intBytesValue.getValue()); + + assertEquals(intBytesValue.getType(), DataType.INT32); + + int resolveInt = (int)resolver.decode(intBytesValue); + + assertEquals(intVal, resolveInt); + + short resolveShort = (short) resolver.decode(intBytesValue, short.class); + assertEquals(resolveShort, 1024); + Short resolveShortObj = (Short) resolver.decode(intBytesValue, Short.class); + assertEquals((short)resolveShortObj, resolveShort); + + long resolveLong = (long) resolver.decode(intBytesValue, long.class); + assertEquals(resolveLong, 1024L); + + Long resolveLongObj = (Long) resolver.decode(intBytesValue, Long.class); + assertEquals(resolveLong, (long) resolveLongObj); + + } +} diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/KVDataTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/KVDataTest.java index 39824505..229c308d 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/KVDataTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/KVDataTest.java @@ -16,7 +16,7 @@ import org.junit.Test; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.ledger.BytesValueEntry; +import com.jd.blockchain.ledger.BytesData; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; import com.jd.blockchain.transaction.KVData; @@ -38,7 +38,7 @@ public class KVDataTest { byte[] value = "test-value".getBytes(); long expectedVersion = 9999L; - kvData = new KVData(key, BytesValueEntry.fromBytes(value), expectedVersion); + kvData = new KVData(key, BytesData.fromBytes(value), expectedVersion); } @Test diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/LongToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/LongToBytesValueResolverTest.java new file mode 100644 index 00000000..19cbdcbd --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/LongToBytesValueResolverTest.java @@ -0,0 +1,52 @@ +package test.com.jd.blockchain.ledger.data; + +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.ledger.resolver.IntegerToBytesValueResolver; +import com.jd.blockchain.ledger.resolver.LongToBytesValueResolver; +import com.jd.blockchain.utils.Bytes; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class LongToBytesValueResolverTest { + + private LongToBytesValueResolver resolver = new LongToBytesValueResolver(); + + @Test + public void test() { + long longVal = 65536L; + + BytesValue longBytesValue = resolver.encode(longVal); + + BytesValue longBytesValue1 = resolver.encode(longVal, long.class); + + BytesValue longBytesValue2 = resolver.encode(longVal, Long.class); + + assertEquals(longBytesValue.getValue(), longBytesValue1.getValue()); + + assertEquals(longBytesValue.getValue(), longBytesValue2.getValue()); + + Bytes longBytes = Bytes.fromLong(longVal); + + assertEquals(longBytes, longBytesValue.getValue()); + + assertEquals(longBytesValue.getType(), DataType.INT64); + + long resolveLong = (long)resolver.decode(longBytesValue); + + assertEquals(longVal, resolveLong); + + short resolveShort = (short) resolver.decode(longBytesValue, short.class); + assertEquals(resolveShort, (short)65536); + + Short resolveShortObj = (Short) resolver.decode(longBytesValue, Short.class); + assertEquals((short)resolveShortObj, resolveShort); + + int resolveInt = (int) resolver.decode(longBytesValue, int.class); + assertEquals(resolveInt, 65536); + + Integer resolveIntObj = (Integer) resolver.decode(longBytesValue, Integer.class); + assertEquals(resolveInt, (int) resolveIntObj); + } +} diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/NormalContract.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/NormalContract.java new file mode 100644 index 00000000..87dcd127 --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/NormalContract.java @@ -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); +} diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/NormalContractImpl.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/NormalContractImpl.java new file mode 100644 index 00000000..ad71598d --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/NormalContractImpl.java @@ -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 + + } + +} diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ShortToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ShortToBytesValueResolverTest.java new file mode 100644 index 00000000..6c4ef0c8 --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ShortToBytesValueResolverTest.java @@ -0,0 +1,43 @@ +package test.com.jd.blockchain.ledger.data; + +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.ledger.resolver.ShortToBytesValueResolver; +import com.jd.blockchain.utils.Bytes; +import com.jd.blockchain.utils.io.BytesUtils; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ShortToBytesValueResolverTest { + + private ShortToBytesValueResolver resolver = new ShortToBytesValueResolver(); + + @Test + public void test() { + short shortVal = 64; + + BytesValue shortBytesValue = resolver.encode(shortVal); + + Bytes shortBytes = new Bytes(BytesUtils.toBytes(shortVal)); + + assertEquals(shortBytes, shortBytesValue.getValue()); + + assertEquals(shortBytesValue.getType(), DataType.INT16); + + short resolveShort = (short)resolver.decode(shortBytesValue); + + assertEquals(shortVal, resolveShort); + + int resolveInt = (int) resolver.decode(shortBytesValue, int.class); + assertEquals(resolveInt, 64); + Integer resolveIntObj = (Integer) resolver.decode(shortBytesValue, Integer.class); + assertEquals((int)resolveIntObj, resolveShort); + + long resolveLong = (long) resolver.decode(shortBytesValue, long.class); + assertEquals(resolveLong, 64L); + + Long resolveLongObj = (Long) resolver.decode(shortBytesValue, Long.class); + assertEquals(resolveLong, (long) resolveLongObj); + } +} diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/StringToBytesValueResolverTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/StringToBytesValueResolverTest.java new file mode 100644 index 00000000..6538e88e --- /dev/null +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/StringToBytesValueResolverTest.java @@ -0,0 +1,79 @@ +package test.com.jd.blockchain.ledger.data; + +import com.alibaba.fastjson.JSON; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataType; +import com.jd.blockchain.ledger.resolver.StringToBytesValueResolver; +import com.jd.blockchain.utils.Bytes; +import static org.junit.Assert.*; + +import com.jd.blockchain.utils.io.BytesUtils; +import org.junit.Test; + +public class StringToBytesValueResolverTest { + + private StringToBytesValueResolver resolver = new StringToBytesValueResolver(); + + @Test + public void testText() { + String textVal = "JDChain"; + + BytesValue textBytesValue = resolver.encode(textVal); + + assertEquals(Bytes.fromString(textVal), textBytesValue.getValue()); + + assertEquals(textBytesValue.getType(), DataType.TEXT); + + String resolveText = (String)resolver.decode(textBytesValue); + + assertEquals(resolveText, textVal); + + byte[] resolveBytes = (byte[]) resolver.decode(textBytesValue, byte[].class); + + assertArrayEquals(resolveBytes, BytesUtils.toBytes(textVal)); + + Bytes resolveBytesObj = (Bytes) resolver.decode(textBytesValue, Bytes.class); + + assertEquals(resolveBytesObj, Bytes.fromString(textVal)); + + } + + @Test + public void testJson() { + Person person = new Person("zhangsan", 80); + String personJson = JSON.toJSONString(person); + BytesValue textBytesValue = resolver.encode(personJson); + assertEquals(Bytes.fromString(personJson), textBytesValue.getValue()); + assertEquals(textBytesValue.getType(), DataType.JSON); + } + + public static class Person { + private String name; + + private int age; + + public Person() { + } + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } +} diff --git a/source/ledger/ledger-rpc/src/main/java/com/jd/blockchain/web/serializes/ByteArrayObjectJsonSerializer.java b/source/ledger/ledger-rpc/src/main/java/com/jd/blockchain/web/serializes/ByteArrayObjectJsonSerializer.java index 896e1f4a..e4a82b13 100644 --- a/source/ledger/ledger-rpc/src/main/java/com/jd/blockchain/web/serializes/ByteArrayObjectJsonSerializer.java +++ b/source/ledger/ledger-rpc/src/main/java/com/jd/blockchain/web/serializes/ByteArrayObjectJsonSerializer.java @@ -2,7 +2,7 @@ package com.jd.blockchain.web.serializes; import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.ObjectSerializer; -import com.jd.blockchain.binaryproto.DataType; +import com.jd.blockchain.binaryproto.BaseType; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.crypto.SignatureDigest; @@ -92,20 +92,20 @@ public class ByteArrayObjectJsonSerializer implements ObjectSerializer { public static class BytesValueJson { - public BytesValueJson(DataType type, Object value) { + public BytesValueJson(BaseType type, Object value) { this.type = type; this.value = value; } - DataType type; + BaseType type; Object value; - public DataType getType() { + public BaseType getType() { return type; } - public void setType(DataType type) { + public void setType(BaseType type) { this.type = type; } diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java b/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java index ae62e2d6..d207d725 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java @@ -2,6 +2,7 @@ package com.jd.blockchain.peer.consensus; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -309,8 +310,8 @@ public class ConsensusMessageDispatcher implements MessageHandle { } @Override - public String[] getContractReturn() { - return txResp.getContractReturn(); + public OperationResult[] getOperationResults() { + return txResp.getOperationResults(); } } diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java b/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java index 01c2ef61..53f5b36e 100644 --- a/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java +++ b/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java @@ -3,6 +3,7 @@ package com.jd.blockchain.peer.web; import java.util.ArrayList; import java.util.List; +import com.jd.blockchain.ledger.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -13,19 +14,6 @@ import org.springframework.web.bind.annotation.RestController; import com.jd.blockchain.contract.ContractException; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.AccountHeader; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVDataObject; -import com.jd.blockchain.ledger.KVDataVO; -import com.jd.blockchain.ledger.KVInfoVO; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInfo; -import com.jd.blockchain.ledger.LedgerMetadata; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.UserInfo; import com.jd.blockchain.ledger.core.ContractAccountSet; import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.DataAccountSet; @@ -454,8 +442,8 @@ public class LedgerQueryController implements BlockchainQueryService { @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") @Override - public AccountHeader getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address) { + public ContractInfo getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "address") String address) { LedgerRepository ledger = ledgerService.getLedger(ledgerHash); LedgerBlock block = ledger.getLatestBlock(); ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); diff --git a/source/pom.xml b/source/pom.xml index f8c9dfce..11ba5866 100644 --- a/source/pom.xml +++ b/source/pom.xml @@ -41,7 +41,7 @@ 0.8.1-SNAPSHOT 0.0.8.RELEASE - 0.6.6.RELEASE + 0.7.0.RELEASE @@ -49,7 +49,7 @@ 1.2.2 1.8.8 - + 0.5.35 1.0.18 1.2.2 1.2.4 @@ -112,8 +112,8 @@ com.jd.blockchain - browser - ${browser.version} + explorer + ${explorer.version} @@ -147,6 +147,27 @@ ${disruptor.version} + + org.bitbucket.mstrobel + procyon-core + ${procyon.version} + + + org.bitbucket.mstrobel + procyon-expressions + ${procyon.version} + + + org.bitbucket.mstrobel + procyon-reflection + ${procyon.version} + + + org.bitbucket.mstrobel + procyon-compilertools + ${procyon.version} + + com.alibaba fastjson diff --git a/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/Module.java b/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/Module.java index e2c064cd..885d9aac 100644 --- a/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/Module.java +++ b/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/Module.java @@ -10,7 +10,7 @@ public interface Module { String getName(); Class loadClass(String className); - + InputStream loadResourceAsStream(String name); String getMainClass(); diff --git a/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java b/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java index c161371e..569a95a5 100644 --- a/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java +++ b/source/runtime/runtime-context/src/main/java/com/jd/blockchain/runtime/RuntimeContext.java @@ -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; } diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/ContractSettings.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/ContractSettings.java new file mode 100644 index 00000000..4a004b2b --- /dev/null +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/ContractSettings.java @@ -0,0 +1,64 @@ +package com.jd.blockchain.sdk; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.utils.Bytes; + +public class ContractSettings { + + private Bytes address; + + private PubKey pubKey; + + private HashDigest rootHash; + + private String chainCode; + + public ContractSettings() { + } + + public ContractSettings(Bytes address, PubKey pubKey, HashDigest rootHash) { + this.address = address; + this.pubKey = pubKey; + this.rootHash = rootHash; + } + + public ContractSettings(Bytes address, PubKey pubKey, HashDigest rootHash, String chainCode) { + this.address = address; + this.pubKey = pubKey; + this.rootHash = rootHash; + this.chainCode = chainCode; + } + + public Bytes getAddress() { + return address; + } + + public void setAddress(Bytes address) { + this.address = address; + } + + public PubKey getPubKey() { + return pubKey; + } + + public void setPubKey(PubKey pubKey) { + this.pubKey = pubKey; + } + + public HashDigest getRootHash() { + return rootHash; + } + + public void setRootHash(HashDigest rootHash) { + this.rootHash = rootHash; + } + + public String getChainCode() { + return chainCode; + } + + public void setChainCode(String chainCode) { + this.chainCode = chainCode; + } +} diff --git a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java similarity index 75% rename from source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java rename to source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java index f3f23779..f0f904ad 100644 --- a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/converters/ClientResolveUtil.java @@ -1,46 +1,26 @@ /** * Copyright: Copyright 2016-2020 JD.COM All Right Reserved - * FileName: com.jd.blockchain.sdk.client.ClientOperationUtil + * FileName: com.jd.blockchain.sdk.client.ClientResolveUtil * Author: shaozhuguang * Department: Y事业部 * Date: 2019/3/27 下午4:12 * Description: */ -package com.jd.blockchain.sdk.client; - -import java.lang.reflect.Field; - -import org.apache.commons.codec.binary.Base64; +package com.jd.blockchain.sdk.converters; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.jd.blockchain.crypto.CryptoProvider; import com.jd.blockchain.crypto.PubKey; -import com.jd.blockchain.ledger.BlockchainIdentityData; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesValueEntry; -import com.jd.blockchain.ledger.BytesValueType; -import com.jd.blockchain.ledger.ContractCodeDeployOperation; -import com.jd.blockchain.ledger.ContractEventSendOperation; -import com.jd.blockchain.ledger.CryptoSetting; -import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.DataAccountRegisterOperation; -import com.jd.blockchain.ledger.LedgerInitOperation; -import com.jd.blockchain.ledger.Operation; -import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.UserRegisterOperation; -import com.jd.blockchain.transaction.ContractCodeDeployOpTemplate; -import com.jd.blockchain.transaction.ContractEventSendOpTemplate; -import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; -import com.jd.blockchain.transaction.DataAccountRegisterOpTemplate; -import com.jd.blockchain.transaction.KVData; -import com.jd.blockchain.transaction.LedgerInitOpTemplate; -import com.jd.blockchain.transaction.LedgerInitSettingData; -import com.jd.blockchain.transaction.UserRegisterOpTemplate; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.transaction.*; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.codec.Base58Utils; import com.jd.blockchain.utils.codec.HexUtils; import com.jd.blockchain.utils.io.BytesUtils; +import org.apache.commons.codec.binary.Base64; + +import java.lang.reflect.Field; /** * @@ -49,7 +29,42 @@ import com.jd.blockchain.utils.io.BytesUtils; * @since 1.0.0 */ -public class ClientOperationUtil { +public class ClientResolveUtil { + + public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { + if (kvDataEntries == null || kvDataEntries.length == 0) { + return kvDataEntries; + } + KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; + // kvDataEntries是代理对象,需要处理 + for (int i = 0; i < kvDataEntries.length; i++) { + KVDataEntry kvDataEntry = kvDataEntries[i]; + String key = kvDataEntry.getKey(); + long version = kvDataEntry.getVersion(); + DataType dataType = kvDataEntry.getType(); + KvData innerKvData = new KvData(key, version, dataType); + Object valueObj = kvDataEntry.getValue(); + switch (dataType) { + case NIL: + break; + case BYTES: + case TEXT: + case JSON: + innerKvData.setValue(valueObj.toString()); + break; + case INT32: + innerKvData.setValue(Integer.parseInt(valueObj.toString())); + break; + case INT64: + innerKvData.setValue(Long.parseLong(valueObj.toString())); + break; + default: + throw new IllegalStateException("Unsupported value type[" + dataType + "] to resolve!"); + } + resolveKvDataEntries[i] = innerKvData; + } + return resolveKvDataEntries; + } public static Operation read(Operation operation) { @@ -83,7 +98,7 @@ public class ClientOperationUtil { } public static Object readValueByBytesValue(BytesValue bytesValue) { - BytesValueType dataType = bytesValue.getType(); + DataType dataType = bytesValue.getType(); Bytes saveVal = bytesValue.getValue(); Object showVal; switch (dataType) { @@ -125,8 +140,8 @@ public class ClientOperationUtil { String typeStr = valueObj.getString("type"); String realValBase58 = valueObj.getString("value"); String key = currWriteSetObj.getString("key"); - BytesValueType dataType = BytesValueType.valueOf(typeStr); - BytesValue bytesValue =BytesValueEntry.fromType(dataType, Base58Utils.decode(realValBase58)); + DataType dataType = DataType.valueOf(typeStr); + BytesValue bytesValue = BytesData.fromType(dataType, Base58Utils.decode(realValBase58)); KVData kvData = new KVData(key, bytesValue, expectedVersion); kvOperation.set(kvData); } @@ -204,7 +219,8 @@ public class ClientOperationUtil { String contractAddress = contractAddressObj.getString("value"); String argsStr = jsonObject.getString("args"); String event = jsonObject.getString("event"); - return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, BytesUtils.toBytes(argsStr)); + return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, + BytesValueEncoding.encodeArray(new Object[]{argsStr}, null)); } private static BlockchainIdentityData blockchainIdentity(JSONObject jsonObject) { @@ -297,4 +313,65 @@ public class ClientOperationUtil { this.id = id; } } + + public static class KvData implements KVDataEntry { + + private String key; + + private long version; + + private DataType dataType; + + private Object value; + + public KvData() { + } + + public KvData(String key, long version, DataType dataType) { + this(key, version, dataType, null); + } + + public KvData(String key, long version, DataType dataType, Object value) { + this.key = key; + this.version = version; + this.dataType = dataType; + this.value = value; + } + + public void setKey(String key) { + this.key = key; + } + + public void setVersion(long version) { + this.version = version; + } + + public void setDataType(DataType dataType) { + this.dataType = dataType; + } + + public void setValue(Object value) { + this.value = value; + } + + @Override + public String getKey() { + return key; + } + + @Override + public long getVersion() { + return version; + } + + @Override + public DataType getType() { + return dataType; + } + + @Override + public Object getValue() { + return value; + } + } } \ No newline at end of file diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java index e18f1df7..c850b57a 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java @@ -5,6 +5,7 @@ import com.jd.blockchain.ledger.*; import com.jd.blockchain.sdk.BlockchainEventHandle; import com.jd.blockchain.sdk.BlockchainEventListener; import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.converters.ClientResolveUtil; import com.jd.blockchain.transaction.BlockchainQueryService; import com.jd.blockchain.transaction.TransactionService; import com.jd.blockchain.transaction.TxTemplate; @@ -144,17 +145,20 @@ public abstract class BlockchainServiceProxy implements BlockchainService { @Override public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { - return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); + KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); + return ClientResolveUtil.read(kvDataEntries); } @Override public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { - return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); + KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); + return ClientResolveUtil.read(kvDataEntries); } @Override public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { - return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); + KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); + return ClientResolveUtil.read(kvDataEntries); } @Override @@ -163,7 +167,7 @@ public abstract class BlockchainServiceProxy implements BlockchainService { } @Override - public AccountHeader getContract(HashDigest ledgerHash, String address) { + public ContractInfo getContract(HashDigest ledgerHash, String address) { return getQueryService(ledgerHash).getContract(ledgerHash, address); } diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java index bd063a5d..838ad829 100644 --- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java +++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java @@ -544,7 +544,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService */ @HttpAction(method=HttpMethod.GET, path="ledgers/{ledgerHash}/contracts/address/{address}") @Override - AccountHeader getContract(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, + ContractInfo getContract(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash, @PathParam(name="address") String address); diff --git a/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientResolveUtil.java b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientResolveUtil.java new file mode 100644 index 00000000..72cd4cb8 --- /dev/null +++ b/source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientResolveUtil.java @@ -0,0 +1,385 @@ +///** +// * Copyright: Copyright 2016-2020 JD.COM All Right Reserved +// * FileName: com.jd.blockchain.sdk.client.ClientResolveUtil +// * Author: shaozhuguang +// * Department: Y事业部 +// * Date: 2019/3/27 下午4:12 +// * Description: +// */ +//package com.jd.blockchain.sdk.client; +// +//import java.lang.reflect.Field; +// +//import com.jd.blockchain.ledger.*; +//import com.jd.blockchain.utils.io.ByteArray; +//import org.apache.commons.codec.binary.Base64; +// +//import com.alibaba.fastjson.JSONArray; +//import com.alibaba.fastjson.JSONObject; +//import com.jd.blockchain.crypto.CryptoProvider; +//import com.jd.blockchain.crypto.PubKey; +//import com.jd.blockchain.transaction.ContractCodeDeployOpTemplate; +//import com.jd.blockchain.transaction.ContractEventSendOpTemplate; +//import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; +//import com.jd.blockchain.transaction.DataAccountRegisterOpTemplate; +//import com.jd.blockchain.transaction.KVData; +//import com.jd.blockchain.transaction.LedgerInitOpTemplate; +//import com.jd.blockchain.transaction.LedgerInitSettingData; +//import com.jd.blockchain.transaction.UserRegisterOpTemplate; +//import com.jd.blockchain.utils.Bytes; +//import com.jd.blockchain.utils.codec.Base58Utils; +//import com.jd.blockchain.utils.codec.HexUtils; +//import com.jd.blockchain.utils.io.BytesUtils; +// +///** +// * +// * @author shaozhuguang +// * @create 2019/3/27 +// * @since 1.0.0 +// */ +// +//public class ClientResolveUtil { +// +// public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { +// if (kvDataEntries == null || kvDataEntries.length == 0) { +// return kvDataEntries; +// } +// KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; +// // kvDataEntries是代理对象,需要处理 +// for (int i = 0; i < kvDataEntries.length; i++) { +// KVDataEntry kvDataEntry = kvDataEntries[i]; +// String key = kvDataEntry.getKey(); +// long version = kvDataEntry.getVersion(); +// DataType dataType = kvDataEntry.getType(); +// KvData innerKvData = new KvData(key, version, dataType); +// Object valueObj = kvDataEntry.getValue(); +// switch (dataType) { +// case NIL: +// break; +// case BYTES: +// case TEXT: +// case JSON: +// innerKvData.setValue(valueObj.toString()); +// break; +// case INT32: +// innerKvData.setValue(Integer.parseInt(valueObj.toString())); +// break; +// case INT64: +// innerKvData.setValue(Long.parseLong(valueObj.toString())); +// break; +// default: +// throw new IllegalStateException("Unsupported value type[" + dataType + "] to resolve!"); +// } +// resolveKvDataEntries[i] = innerKvData; +// } +// return resolveKvDataEntries; +// } +// +// public static Operation read(Operation operation) { +// +// try { +// // Class +// Class clazz = operation.getClass(); +// Field field = clazz.getSuperclass().getDeclaredField("h"); +// field.setAccessible(true); +// Object object = field.get(operation); +// if (object instanceof JSONObject) { +// JSONObject jsonObject = (JSONObject) object; +// if (jsonObject.containsKey("accountID")) { +// return convertDataAccountRegisterOperation(jsonObject); +// } else if (jsonObject.containsKey("userID")) { +// return convertUserRegisterOperation(jsonObject); +// } else if (jsonObject.containsKey("contractID")) { +// return convertContractCodeDeployOperation(jsonObject); +// } else if (jsonObject.containsKey("writeSet")) { +// return convertDataAccountKVSetOperation(jsonObject); +// } else if (jsonObject.containsKey("initSetting")) { +// return convertLedgerInitOperation(jsonObject); +// } else if (jsonObject.containsKey("contractAddress")) { +// return convertContractEventSendOperation(jsonObject); +// } +// } +// } catch (Exception e) { +// throw new RuntimeException(e); +// } +// +// return null; +// } +// +// public static Object readValueByBytesValue(BytesValue bytesValue) { +// DataType dataType = bytesValue.getType(); +// Bytes saveVal = bytesValue.getValue(); +// Object showVal; +// switch (dataType) { +// case BYTES: +// // return hex +// showVal = HexUtils.encode(saveVal.toBytes()); +// break; +// case TEXT: +// case JSON: +// showVal = saveVal.toUTF8String(); +// break; +// case INT64: +// showVal = BytesUtils.toLong(saveVal.toBytes()); +// break; +// default: +// showVal = HexUtils.encode(saveVal.toBytes()); +// break; +// } +// return showVal; +// } +// +// public static DataAccountRegisterOperation convertDataAccountRegisterOperation(JSONObject jsonObject) { +// JSONObject account = jsonObject.getJSONObject("accountID"); +// return new DataAccountRegisterOpTemplate(blockchainIdentity(account)); +// } +// +// public static DataAccountKVSetOperation convertDataAccountKVSetOperation(JSONObject jsonObject) { +// // 写入集合处理 +// JSONArray writeSetObj = jsonObject.getJSONArray("writeSet"); +// JSONObject accountAddrObj = jsonObject.getJSONObject("accountAddress"); +// String addressBase58 = accountAddrObj.getString("value"); +// Bytes address = Bytes.fromBase58(addressBase58); +// +// DataAccountKVSetOpTemplate kvOperation = new DataAccountKVSetOpTemplate(address); +// for (int i = 0; i tools-initializer ${project.version} + + com.jd.blockchain + contract-samples + ${project.version} + diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java index 03e6e720..8af3a729 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java @@ -1,53 +1,53 @@ -package com.jd.blockchain.contract.samples; - -import com.jd.blockchain.binaryproto.DataContract; -import com.jd.blockchain.consts.DataCodes; -import com.jd.blockchain.contract.Contract; -import com.jd.blockchain.contract.ContractEvent; -import com.jd.blockchain.ledger.ContractBizContent; -import com.jd.blockchain.ledger.TransactionContentBody; -import com.jd.blockchain.utils.Bytes; - -import java.math.BigDecimal; - -/** - * 示例:一个“资产管理”智能合约; - * - * @author zhaogw - */ -@Contract -public interface AssetContract2 { - - /** - * 发行资产; - * 新发行的资产数量; - * @param assetHolderAddress - * 新发行的资产的持有账户; - */ - @ContractEvent(name = "issue-asset-0") - void issue(ContractBizContent contractBizContent, String assetHolderAddress); - - /** - * issue asset; - * @param contractBizContent - * @param assetHolderAddress - * @param cashNumber - */ - @ContractEvent(name = "issue-asset") - public void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber); - - /** - * Bytes can bring the byte[]; - * @param bytes - * @param assetHolderAddress - * @param cashNumber - */ - @ContractEvent(name = "issue-asset-2") - void issue(Bytes bytes,String assetHolderAddress, long cashNumber); - - @ContractEvent(name = "issue-asset-3") - void issue(Byte bytes, String assetHolderAddress, long cashNumber); - - @ContractEvent(name = "issue-asset-4") - void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber); -} \ No newline at end of file +//package com.jd.blockchain.contract.samples; +// +//import com.jd.blockchain.binaryproto.DataContract; +//import com.jd.blockchain.consts.DataCodes; +//import com.jd.blockchain.contract.Contract; +//import com.jd.blockchain.contract.ContractEvent; +//import com.jd.blockchain.ledger.ContractBizContent; +//import com.jd.blockchain.ledger.TransactionContentBody; +//import com.jd.blockchain.utils.Bytes; +// +//import java.math.BigDecimal; +// +///** +// * 示例:一个“资产管理”智能合约; +// * +// * @author zhaogw +// */ +//@Contract +//public interface AssetContract2 { +// +// /** +// * 发行资产; +// * 新发行的资产数量; +// * @param assetHolderAddress +// * 新发行的资产的持有账户; +// */ +// @ContractEvent(name = "issue-asset-0") +// void issue(ContractBizContent contractBizContent, String assetHolderAddress); +// +// /** +// * issue asset; +// * @param contractBizContent +// * @param assetHolderAddress +// * @param cashNumber +// */ +// @ContractEvent(name = "issue-asset") +// public void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber); +// +// /** +// * Bytes can bring the byte[]; +// * @param bytes +// * @param assetHolderAddress +// * @param cashNumber +// */ +// @ContractEvent(name = "issue-asset-2") +// void issue(Bytes bytes,String assetHolderAddress, long cashNumber); +// +// @ContractEvent(name = "issue-asset-3") +// void issue(Byte bytes, String assetHolderAddress, long cashNumber); +// +// @ContractEvent(name = "issue-asset-4") +// void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber); +//} \ No newline at end of file diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java index 770f78c4..02258ed2 100644 --- a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContractImpl.java @@ -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"; // 保存资产总数的键; @@ -171,17 +171,7 @@ public class AssetContractImpl implements EventProcessingAwire, AssetContract { * com.jd.blockchain.contract.model.ContractError) */ @Override - public void postEvent(ContractEventContext eventContext, ContractException error) { + public void postEvent(ContractEventContext eventContext, Exception error) { this.eventContext = null; } - - @Override - public void postEvent(ContractException error) { - - } - - @Override - public void postEvent() { - - } } diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Constant.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Constant.java new file mode 100644 index 00000000..aa5ac2f7 --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Constant.java @@ -0,0 +1,38 @@ +package com.jd.blockchain.sdk.samples; + +import org.apache.commons.io.FileUtils; +import org.springframework.core.io.ClassPathResource; + +import java.io.File; + +public class SDKDemo_Constant { + + public static final String GW_IPADDR = "127.0.0.1"; + + public static final int GW_PORT = 11000; + + public static final String[] PUB_KEYS = { + "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", + "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", + "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", + "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk"}; + + public static final String[] PRIV_KEYS = { + "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", + "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", + "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", + "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns"}; + + public static final String PASSWORD = "abc"; + + public static final byte[] readChainCodes(String contractZip) { + // 构建合约的字节数组; + try { + ClassPathResource contractPath = new ClassPathResource(contractZip); + File contractFile = new File(contractPath.getURI()); + return FileUtils.readFileToByteArray(contractFile); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Base_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Base_Demo.java new file mode 100644 index 00000000..bbd4ed71 --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Base_Demo.java @@ -0,0 +1,51 @@ +package com.jd.blockchain.sdk.samples; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.tools.keygen.KeyGenCommand; + +public abstract class SDK_Base_Demo { + + protected BlockchainKeypair adminKey; + + protected HashDigest ledgerHash; + + protected BlockchainService blockchainService; + + public SDK_Base_Demo() { + init(); + } + + public void init() { + // 生成连接网关的账号 + PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], SDKDemo_Constant.PASSWORD); + + PubKey pubKey = KeyGenCommand.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]); + + adminKey = new BlockchainKeypair(pubKey, privKey); + + // 连接网关 + GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, + SDKDemo_Constant.GW_PORT, false, adminKey); + + // 获取网关对应的Service处理类 + blockchainService = serviceFactory.getBlockchainService(); + + HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); + // 获取当前账本Hash + ledgerHash = ledgerHashs[0]; + } + + public TransactionResponse commit(TransactionTemplate txTpl) { + PreparedTransaction ptx = txTpl.prepare(); + ptx.sign(adminKey); + return ptx.commit(); + } +} diff --git a/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java new file mode 100644 index 00000000..9d43b199 --- /dev/null +++ b/source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java @@ -0,0 +1,156 @@ +package com.jd.blockchain.sdk.samples; + +import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; +import static com.jd.blockchain.transaction.ContractReturnValue.decode; + +import com.jd.blockchain.contract.TransferContract; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.transaction.LongValueHolder; +import com.jd.blockchain.transaction.GenericValueHolder; +import com.jd.blockchain.utils.Bytes; + +public class SDK_Contract_Demo extends SDK_Base_Demo { + + public static void main(String[] args) { + new SDK_Contract_Demo().executeContract(); + } + + public void executeContract() { + + // 发布jar包 + // 定义交易模板 + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + + // 将jar包转换为二进制数据 + byte[] contractCode = readChainCodes("transfer.jar"); + + // 生成一个合约账号 + BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); + + // 生成发布合约操作 + txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); + + // 生成预发布交易; + PreparedTransaction ptx = txTpl.prepare(); + + // 对交易进行签名 + ptx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse txResp = ptx.commit(); + + // 获取合约地址 + Bytes contractAddress = contractDeployKey.getAddress(); + + // 打印交易返回信息 + System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n", + txResp.getContentHash().toBase58(), txResp.getBlockHeight(), txResp.getBlockHash().toBase58(), + txResp.isSuccess(), txResp.getExecutionState()); + + // 打印合约地址 + System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58()); + + // 注册一个数据账户 + BlockchainKeypair dataAccount = createDataAccount(); + // 获取数据账户地址 + String dataAddress = dataAccount.getAddress().toBase58(); + // 打印数据账户地址 + System.out.printf("DataAccountAddress = %s \r\n", dataAddress); + + // 创建两个账号: + String account0 = "jd_zhangsan", account1 = "jd_lisi"; + long account0Money = 3000L, account1Money = 2000L; + // 创建两个账户 + // 使用KV操作创建一个账户 + System.out.println(create(dataAddress, account0, account0Money, false, null)); + // 使用合约创建一个账户 + System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); + + // 转账,使得双方钱达到一致 + System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); + + // 通过合约读取account0的当前信息 + System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By Contract)\r\n", dataAddress, + account0, readByContract(dataAddress, account0, contractAddress)); + // 通过KV读取account1的当前信息 + System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By KV Operation)\r\n", dataAddress, + account1, readByKvOperation(dataAddress, account1)); + + // 通过合约读取account0的历史信息 + System.out.println(readAll(dataAddress, account0, contractAddress)); + // 通过合约读取account1的历史信息 + System.out.println(readAll(dataAddress, account1, contractAddress)); + } + + private String readAll(String address, String account, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + GenericValueHolder result = decode(transferContract.readAll(address, account)); + commit(txTpl); + return result.get(); + } + + private long readByContract(String address, String account, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + LongValueHolder result = decode(transferContract.read(address, account)); + commit(txTpl); + return result.get(); + } + + private long readByKvOperation(String address, String account) { + KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); + if (kvDataEntries == null || kvDataEntries.length == 0) { + throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); + } + KVDataEntry kvDataEntry = kvDataEntries[0]; + if (kvDataEntry.getVersion() == -1) { + return 0L; + } + return (long) (kvDataEntry.getValue()); + } + + private String transfer(String address, String from, String to, long money, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + GenericValueHolder result = decode(transferContract.transfer(address, from, to, money)); + commit(txTpl); + return result.get(); + } + + private BlockchainKeypair createDataAccount() { + // 首先注册一个数据账户 + BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + txTpl.dataAccounts().register(newDataAccount.getIdentity()); + commit(txTpl); + return newDataAccount; + } + + private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + if (useContract) { + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + GenericValueHolder result = decode(transferContract.create(address, account, money)); + commit(txTpl); + return result.get(); + } else { + // 通过KV创建 + txTpl.dataAccount(address).setInt64(account, money, -1); + TransactionResponse txResp = commit(txTpl); + return String.format( + "DataAccountAddress[%s] -> Create(By KV Operation) Account = %s and Money = %s Success!!! \r\n", + address, account, money); + } + } +} diff --git a/source/sdk/sdk-samples/src/main/resources/transfer.jar b/source/sdk/sdk-samples/src/main/resources/transfer.jar new file mode 100644 index 00000000..a161392e Binary files /dev/null and b/source/sdk/sdk-samples/src/main/resources/transfer.jar differ diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test_.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test_.java new file mode 100644 index 00000000..2f7755da --- /dev/null +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test_.java @@ -0,0 +1,165 @@ +package test.com.jd.blockchain.sdk.test; + +import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; +import static com.jd.blockchain.transaction.ContractReturnValue.decode; + +import org.junit.Before; +import org.junit.Test; + +import com.jd.blockchain.contract.TransferContract; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.sdk.BlockchainService; +import com.jd.blockchain.sdk.client.GatewayServiceFactory; +import com.jd.blockchain.sdk.samples.SDKDemo_Constant; +import com.jd.blockchain.tools.keygen.KeyGenCommand; +import com.jd.blockchain.transaction.LongValueHolder; +import com.jd.blockchain.transaction.GenericValueHolder; +import com.jd.blockchain.utils.Bytes; + +public class SDKDemo_Contract_Test_ { + + private BlockchainKeypair adminKey; + + private HashDigest ledgerHash; + + private BlockchainService blockchainService; + + @Before + public void init() { + // 生成连接网关的账号 + PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], + SDKDemo_Constant.PASSWORD); + + PubKey pubKey = KeyGenCommand.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]); + + adminKey = new BlockchainKeypair(pubKey, privKey); + + // 连接网关 + GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, + SDKDemo_Constant.GW_PORT, false, adminKey); + + blockchainService = serviceFactory.getBlockchainService(); + + HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); + + ledgerHash = ledgerHashs[0]; + } + + @Test + public void testContract() { + + // 发布jar包 + // 定义交易; + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + + byte[] contractCode = readChainCodes("transfer.jar"); + + // 生成一个合约账号 + BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); + + txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); + + // 签名; + PreparedTransaction ptx = txTpl.prepare(); + + ptx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse txResp = ptx.commit(); + + System.out.println(txResp.isSuccess()); + + // 首先注册一个数据账户 + BlockchainKeypair dataAccount = createDataAccount(); + + String dataAddress = dataAccount.getAddress().toBase58(); + + Bytes contractAddress = contractDeployKey.getAddress(); + + // 创建两个账号: + String account0 = "jd_zhangsan", account1 = "jd_lisi"; + long account0Money = 3000L, account1Money = 2000L; + // 创建两个账户 + // 使用KV创建一个账户 + System.out.println(create(dataAddress, account0, account0Money, false, null)); + // 使用合约创建一个账户 + System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); + + // 转账,使得双方钱达到一致 + System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); + + // 读取当前结果 + System.out.println(read(dataAddress, account0, contractAddress)); + System.out.println(read(dataAddress, account1, contractAddress)); + + // 读取账号历史信息 + System.out.println(readAll(dataAddress, account0, contractAddress)); + System.out.println(readAll(dataAddress, account1, contractAddress)); + } + + private String readAll(String address, String account, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + GenericValueHolder result = decode(transferContract.readAll(address, account)); + commit(txTpl); + return result.get(); + } + + private long read(String address, String account, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + LongValueHolder result = decode(transferContract.read(address, account)); + commit(txTpl); + return result.get(); + } + + private String transfer(String address, String from, String to, long money, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + GenericValueHolder result = decode(transferContract.transfer(address, from, to, money)); + commit(txTpl); + return result.get(); + } + + private BlockchainKeypair createDataAccount() { + // 首先注册一个数据账户 + BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); + + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + txTpl.dataAccounts().register(newDataAccount.getIdentity()); + commit(txTpl); + return newDataAccount; + } + + private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { + TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + if (useContract) { + // 使用合约创建 + TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); + GenericValueHolder result = decode(transferContract.create(address, account, money)); + commit(txTpl); + return result.get(); + } else { + // 通过KV创建 + txTpl.dataAccount(address).setInt64(account, money, -1); + TransactionResponse txResp = commit(txTpl); + return account + money; + } + } + + private TransactionResponse commit(TransactionTemplate txTpl) { + PreparedTransaction ptx = txTpl.prepare(); + ptx.sign(adminKey); + return ptx.commit(); + } +} diff --git a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java index 608c3788..244d8071 100644 --- a/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java +++ b/source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java @@ -1,10 +1,29 @@ package test.com.jd.blockchain.sdk.test; -import com.jd.blockchain.binaryproto.BinaryProtocol; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +import org.junit.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; + import com.jd.blockchain.contract.samples.AssetContract; -import com.jd.blockchain.contract.samples.AssetContract2; -import com.jd.blockchain.crypto.*; -import com.jd.blockchain.ledger.*; +import com.jd.blockchain.crypto.AsymmetricKeypair; +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.crypto.SignatureFunction; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.sdk.client.GatewayServiceFactory; import com.jd.blockchain.sdk.samples.SDKDemo_Contract; @@ -13,19 +32,6 @@ import com.jd.blockchain.utils.codec.Base58Utils; import com.jd.blockchain.utils.io.ByteArray; import com.jd.blockchain.utils.net.NetworkAddress; import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.util.ReflectionUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.reflect.Method; - -import static org.junit.Assert.*; /** * 演示合约执行的过程; @@ -62,63 +68,63 @@ public class SDK_Contract_Test { bcsrv = serviceFactory.getBlockchainService(); } - /** - * 演示合约执行的过程; - */ -// @Test - public void demoContract1() { - String dataAddress = registerData4Contract(); - // 发起交易; - TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - String contractAddress = "LdeNg8JHFCKABJt6AaRNVCZPgY4ofGPd8MgcR"; - AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); -// assetContract.issue(transactionContentBody,contractAddress); -// assetContract.issue(transactionContentBody,contractAddress,888888); -// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); -// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); - Byte byteObj = Byte.parseByte("127"); - assetContract.issue(byteObj,dataAddress,321123); -// assetContract.issue(contractBizContent,dataAddress); - assetContract.issue(Byte.parseByte("126"),dataAddress,Bytes.fromString("100.234")); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - prepTx.sign(signKeyPair); - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - //check; - KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,"total"); - assertEquals("100",dataEntries[0].getValue().toString()); - } - - /** - * 演示合约执行的过程; - */ -// @Test - public void demoContract2() throws IOException { - String contractAddress = deploy(); - String dataAddress = registerData4Contract(); - System.out.println("dataAddress="+dataAddress); - // 发起交易; - TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); - - AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); - ContractBizContent contractBizContent = () -> new String[]{"param1","param2"}; - assetContract.issue(contractBizContent,dataAddress,123456); - - // TX 准备就绪; - PreparedTransaction prepTx = txTemp.prepare(); - prepTx.sign(signKeyPair); - // 提交交易; - TransactionResponse transactionResponse = prepTx.commit(); - - //check; - assertTrue(transactionResponse.isSuccess()); - KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,contractBizContent.getAttrs()[0],contractBizContent.getAttrs()[1]); - assertEquals("value1",dataEntries[0].getValue().toString()); - assertEquals(888,dataEntries[1].getValue()); - } +// /** +// * 演示合约执行的过程; +// */ +//// @Test +// public void demoContract1() { +// String dataAddress = registerData4Contract(); +// // 发起交易; +// TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); +// String contractAddress = "LdeNg8JHFCKABJt6AaRNVCZPgY4ofGPd8MgcR"; +// AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); +//// assetContract.issue(transactionContentBody,contractAddress); +//// assetContract.issue(transactionContentBody,contractAddress,888888); +//// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); +//// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777); +// Byte byteObj = Byte.parseByte("127"); +// assetContract.issue(byteObj,dataAddress,321123); +//// assetContract.issue(contractBizContent,dataAddress); +// assetContract.issue(Byte.parseByte("126"),dataAddress,Bytes.fromString("100.234")); +// +// // TX 准备就绪; +// PreparedTransaction prepTx = txTemp.prepare(); +// prepTx.sign(signKeyPair); +// // 提交交易; +// TransactionResponse transactionResponse = prepTx.commit(); +// +// //check; +// KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,"total"); +// assertEquals("100",dataEntries[0].getValue().toString()); +// } + +// /** +// * 演示合约执行的过程; +// */ +//// @Test +// public void demoContract2() throws IOException { +// String contractAddress = deploy(); +// String dataAddress = registerData4Contract(); +// System.out.println("dataAddress="+dataAddress); +// // 发起交易; +// TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash); +// +// AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class); +// ContractBizContent contractBizContent = () -> new String[]{"param1","param2"}; +// assetContract.issue(contractBizContent,dataAddress,123456); +// +// // TX 准备就绪; +// PreparedTransaction prepTx = txTemp.prepare(); +// prepTx.sign(signKeyPair); +// // 提交交易; +// TransactionResponse transactionResponse = prepTx.commit(); +// +// //check; +// assertTrue(transactionResponse.isSuccess()); +// KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,contractBizContent.getAttrs()[0],contractBizContent.getAttrs()[1]); +// assertEquals("value1",dataEntries[0].getValue().toString()); +// assertEquals(888,dataEntries[1].getValue()); +// } // @Test public void registerData(){ @@ -346,31 +352,31 @@ public class SDK_Contract_Test { } - @Test - public void testStringArr(){ - ContractBizContent contractBizContent = () -> new String[]{"1","2","you are welcome!"}; - byte[] bizBytes = BinaryProtocol.encode(contractBizContent,ContractBizContent.class); - ContractBizContent actualObj = BinaryProtocol.decodeAs(bizBytes,ContractBizContent.class); - assertArrayEquals(contractBizContent.getAttrs(),actualObj.getAttrs()); - } - - @Test - public void testContractArgs(){ - ContractBizContent contractBizContent = () -> new String[]{"param1"}; - Method method = ReflectionUtils.findMethod(AssetContract2.class,"issue",ContractBizContent.class,String.class); - ContractArgs contractArgs = new ContractArgs() { - @Override - public Method getMethod() { - return method; - } - - @Override - public Object[] getArgs() { - return new Object[]{contractBizContent,"hello"}; - } - }; - - //add the annotation; +// @Test +// public void testStringArr(){ +// ContractBizContent contractBizContent = () -> new String[]{"1","2","you are welcome!"}; +// byte[] bizBytes = BinaryProtocol.encode(contractBizContent,ContractBizContent.class); +// ContractBizContent actualObj = BinaryProtocol.decodeAs(bizBytes,ContractBizContent.class); +// assertArrayEquals(contractBizContent.getAttrs(),actualObj.getAttrs()); +// } - } +// @Test +// public void testContractArgs(){ +// ContractBizContent contractBizContent = () -> new String[]{"param1"}; +// Method method = ReflectionUtils.findMethod(AssetContract2.class,"issue",ContractBizContent.class,String.class); +// ContractArgs contractArgs = new ContractArgs() { +// @Override +// public Method getMethod() { +// return method; +// } +// +// @Override +// public Object[] getArgs() { +// return new Object[]{contractBizContent,"hello"}; +// } +// }; +// +// //add the annotation; +// +// } } diff --git a/source/sdk/sdk-samples/src/test/resources/transfer.jar b/source/sdk/sdk-samples/src/test/resources/transfer.jar new file mode 100644 index 00000000..a161392e Binary files /dev/null and b/source/sdk/sdk-samples/src/test/resources/transfer.jar differ diff --git a/source/storage/storage-composite/src/main/java/com/jd/blockchain/storage/service/impl/composite/CompositeConnectionFactory.java b/source/storage/storage-composite/src/main/java/com/jd/blockchain/storage/service/impl/composite/CompositeConnectionFactory.java index 96a5d6b8..ed1633c6 100644 --- a/source/storage/storage-composite/src/main/java/com/jd/blockchain/storage/service/impl/composite/CompositeConnectionFactory.java +++ b/source/storage/storage-composite/src/main/java/com/jd/blockchain/storage/service/impl/composite/CompositeConnectionFactory.java @@ -42,7 +42,7 @@ public class CompositeConnectionFactory implements DbConnectionFactory { connectionFactoryMap.put(dbPrefix, dbConnectionFactory); } } catch (Exception e) { - LOGGER.error("class:{%s} init error {%s}", clazz.getName(), e.getMessage()); + LOGGER.error("class:{} init error {}", clazz.getName(), e.getMessage()); } } } diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java index 1e318f97..25a40ad0 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java @@ -10,20 +10,18 @@ import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.DoubleStream; +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.ledger.core.CryptoConfig; import org.springframework.core.io.ClassPathResource; import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.consensus.ConsensusProvider; import com.jd.blockchain.consensus.ConsensusProviders; import com.jd.blockchain.consensus.ConsensusSettings; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.CryptoAlgorithm; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PrivKey; import com.jd.blockchain.ledger.BlockchainIdentity; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.BytesDataList; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.DataAccountRegisterOperation; import com.jd.blockchain.ledger.LedgerBlock; @@ -143,8 +141,9 @@ public class LedgerPerformanceTest { batchCount = Integer.parseInt(args[1]); } } - if (contract){ - testContract(ledgerHash, testNode.getPartiKey(), ledgerManager, opHandler, batchSize, batchCount, silent); + if (contract) { + testContract(ledgerHash, testNode.getPartiKey(), ledgerManager, opHandler, batchSize, batchCount, + silent); } if (usertest) { @@ -177,8 +176,9 @@ public class LedgerPerformanceTest { * @param batchCount * @param silent */ - private static void testUserRegistering(HashDigest ledgerHash, AsymmetricKeypair adminKey, LedgerManager ledgerManager, - DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { + private static void testUserRegistering(HashDigest ledgerHash, AsymmetricKeypair adminKey, + LedgerManager ledgerManager, DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, + boolean silent) { LedgerRepository ledger = ledgerManager.getLedger(ledgerHash); ConsoleUtils.info("\r\n\r\n================= 准备测试交易 [注册用户] ================="); @@ -273,7 +273,7 @@ public class LedgerPerformanceTest { * @param silent */ private static void testContract(HashDigest ledgerHash, AsymmetricKeypair adminKey, LedgerManager ledgerManager, - DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { + DefaultOperationHandleRegisteration opHandler, int batchSize, int batchCount, boolean silent) { LedgerRepository ledger = ledgerManager.getLedger(ledgerHash); ConsoleUtils.info("\r\n\r\n================= 准备测试交易 [执行合约] ================="); @@ -285,8 +285,8 @@ public class LedgerPerformanceTest { // 准备请求 int totalCount = batchSize * batchCount; - List contractTxList = prepareContractRequests(ledgerHash, - adminKey, totalCount, false, txProc); + List contractTxList = prepareContractRequests(ledgerHash, adminKey, totalCount, false, + txProc); Prompter consolePrompter = new PresetAnswerPrompter("N"); @@ -303,6 +303,7 @@ public class LedgerPerformanceTest { } } + private static void execPerformanceTest(int batchCount, int batchSize, List txList, LedgerRepository ledger, LedgerManager ledgerManager, DefaultOperationHandleRegisteration opHandler, boolean statistic) { @@ -407,8 +408,7 @@ public class LedgerPerformanceTest { // BlockchainKeyPair dataAccountKey = // BlockchainKeyGenerator.getInstance().generate(); BlockchainIdentity targetAccount = dataAccounts[count % dataAccounts.length]; - txbuilder.dataAccount(targetAccount.getAddress()).setText("key-" + startTs + "-" + i, - "value-" + i, -1L); + txbuilder.dataAccount(targetAccount.getAddress()).setText("key-" + startTs + "-" + i, "value-" + i, -1L); TransactionRequestBuilder reqBuilder = txbuilder.prepareRequest(); reqBuilder.signAsEndpoint(adminKey); txList.add(reqBuilder.buildRequest()); @@ -426,8 +426,9 @@ public class LedgerPerformanceTest { public static ConsensusProvider getConsensusProvider(String provider) { return ConsensusProviders.getProvider(provider); } - public static List prepareContractRequests(HashDigest ledgerHash, - AsymmetricKeypair adminKey, int count, boolean statistic, TransactionBatchProcessor txProc) { + + public static List prepareContractRequests(HashDigest ledgerHash, AsymmetricKeypair adminKey, + int count, boolean statistic, TransactionBatchProcessor txProc) { // deploy contract byte[] chainCode; @@ -436,7 +437,7 @@ public class LedgerPerformanceTest { InputStream input = LedgerPerformanceTest.class.getClassLoader().getResourceAsStream("example1.jar"); chainCode = new byte[input.available()]; input.read(chainCode); - }catch (IOException e){ + } catch (IOException e) { e.printStackTrace(); return null; } @@ -457,10 +458,10 @@ public class LedgerPerformanceTest { System.out.println(resp.isSuccess()); TransactionBatchResultHandle handle = txProc.prepare(); handle.commit(); - try{ + try { Thread.sleep(1000); - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); } @@ -468,8 +469,9 @@ public class LedgerPerformanceTest { List txList = new ArrayList<>(); for (int i = 0; i < count; i++) { txbuilder = new TxBuilder(ledgerHash); - String args = dataIdentity.getAddress().toString() + "##"+Integer.toString(i)+ "##"+Integer.toString(i); - txbuilder.contractEvents().send(contractIdentity.getAddress(), "hello", args.getBytes()); + String args = dataIdentity.getAddress().toString() + "##" + Integer.toString(i) + "##" + + Integer.toString(i); + txbuilder.contractEvents().send(contractIdentity.getAddress(), "print", BytesDataList.singleText("hello")); // txbuilder.contractEvents().send(contractIdentity.getAddress(), "print", args.getBytes()); reqBuilder = txbuilder.prepareRequest(); reqBuilder.signAsEndpoint(adminKey); @@ -485,7 +487,8 @@ public class LedgerPerformanceTest { return txList; } - public static NodeContext[] initLedgers(boolean optimized, CryptoAlgorithm hashAlg, DBType dbType, String provider, String config) { + public static NodeContext[] initLedgers(boolean optimized, CryptoAlgorithm hashAlg, DBType dbType, String provider, + String config) { Map serviceRegisterMap = new ConcurrentHashMap<>(); Prompter consolePrompter = new PresetAnswerPrompter("N"); // new ConsolePrompter(); diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java index 33d494a3..b5bcd809 100644 --- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java +++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java @@ -6,16 +6,13 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; +import com.jd.blockchain.crypto.*; +import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; +import com.jd.blockchain.crypto.service.sm.SMCryptoService; import org.springframework.core.io.ClassPathResource; import com.jd.blockchain.consensus.ConsensusProvider; import com.jd.blockchain.consensus.ConsensusSettings; -import com.jd.blockchain.crypto.CryptoAlgorithm; -import com.jd.blockchain.crypto.AsymmetricKeypair; -import com.jd.blockchain.crypto.Crypto; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.crypto.PrivKey; -import com.jd.blockchain.crypto.SignatureDigest; import com.jd.blockchain.ledger.CryptoSetting; import com.jd.blockchain.ledger.core.CryptoConfig; import com.jd.blockchain.ledger.core.LedgerInitDecision; @@ -39,16 +36,20 @@ public class Utils { public static final String PASSWORD = "abc"; - public static final String[] PUB_KEYS = { "3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu", - "3snPdw7i7Ph1SYLQt9uqVEqiuvNXjxCdGvEdN6otJsg5rbr7Aze7kf", - "3snPdw7i7PezptA6dNBkotPjmKEbTkY8fmusLBnfj8Cf7eFwhWDwKr", - "3snPdw7i7PerZYfRzEB61SAN9tFK4yHm9wUSRtkLSSGXHkQRbB5PkS" }; + public static final String[] PUB_KEYS = { + "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", + "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", + "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", + "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk" }; public static final String[] PRIV_KEYS = { - "177gjyoEUhdD1NkQSxBVvfSyovMd1ha5H46zsb9kyErLNBuQkLRAf2ea6CNjStjCFJQN8S1", - "177gjsa6KcyxUpx7T3tvCVMuqHvvguiQFRLmDY9jaMcH6L9R4k7XgANLfY3paC5XaXeASej", - "177gju7AgXp371qqprjEN3Lg4Hc4EWHnDH9eWgTttEUoN8PuNpQTbS253uTxdKn5w1zZXUp", - "177gjtddYr7CtN6iN6KRgu1kKzFn6quQsx3DQLnUD1xgj5E2QhUTMDnpZKzSKbB7kt35gzj" }; + "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", + "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", + "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", + "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns" }; + + private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), + SMCryptoService.class.getName() }; private Map serviceRegisterMap = new ConcurrentHashMap<>(); @@ -131,7 +132,14 @@ public class Utils { public AsyncCallback startInit(int currentId, PrivKey privKey, LedgerInitProperties setting, ConsensusSettings csProps, ConsensusProvider consensusProvider, DBConnectionConfig dbConnConfig, Prompter prompter, boolean autoVerifyHash, CryptoAlgorithm hashAlg) { + + CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length]; + for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) { + supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]); + } CryptoConfig cryptoSetting = new CryptoConfig(); + cryptoSetting.setSupportedProviders(supportedProviders); + cryptoSetting.setSupportedProviders(supportedProviders); cryptoSetting.setAutoVerifyHash(autoVerifyHash); cryptoSetting.setHashAlgorithm(hashAlg); diff --git a/source/test/test-integration/src/main/resources/ledger_init_test_web2.init b/source/test/test-integration/src/main/resources/ledger_init_test_web2.init index 888d5e61..5d64bdb6 100644 --- a/source/test/test-integration/src/main/resources/ledger_init_test_web2.init +++ b/source/test/test-integration/src/main/resources/ledger_init_test_web2.init @@ -4,6 +4,17 @@ ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323 #账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; #ledger.name= +#共识服务提供者;必须; +consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider + +#共识服务的参数配置;必须; +consensus.conf=classpath:bftsmart.config + +#密码服务提供者列表,以英文逗点“,”分隔;必须; +crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ +com.jd.blockchain.crypto.service.sm.SMCryptoService + + #参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; cons_parti.count=4 @@ -12,7 +23,7 @@ cons_parti.0.name=jd.com #第0个参与方的公钥文件路径; cons_parti.0.pubkey-path=keys/jd-com.pub #第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; -cons_parti.0.pubkey=3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu +cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 #第0个参与方的账本初始服务的主机; cons_parti.0.initializer.host=127.0.0.1 #第0个参与方的账本初始服务的端口; @@ -25,7 +36,7 @@ cons_parti.1.name=at.com #第1个参与方的公钥文件路径; cons_parti.1.pubkey-path=keys/at-com.pub #第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; -cons_parti.1.pubkey=3snPdw7i7Ph1SYLQt9uqVEqiuvNXjxCdGvEdN6otJsg5rbr7Aze7kf +cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX #第1个参与方的账本初始服务的主机; cons_parti.1.initializer.host=127.0.0.1 #第1个参与方的账本初始服务的端口; @@ -38,7 +49,7 @@ cons_parti.2.name=bt.com #第2个参与方的公钥文件路径; cons_parti.2.pubkey-path=keys/bt-com.pub #第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; -cons_parti.2.pubkey=3snPdw7i7PezptA6dNBkotPjmKEbTkY8fmusLBnfj8Cf7eFwhWDwKr +cons_parti.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x #第2个参与方的账本初始服务的主机; cons_parti.2.initializer.host=127.0.0.1 #第2个参与方的账本初始服务的端口; @@ -51,7 +62,7 @@ cons_parti.3.name=xt.com #第3个参与方的公钥文件路径; cons_parti.3.pubkey-path=keys/xt-com.pub #第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; -cons_parti.3.pubkey=3snPdw7i7PerZYfRzEB61SAN9tFK4yHm9wUSRtkLSSGXHkQRbB5PkS +cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk #第3个参与方的账本初始服务的主机; cons_parti.3.initializer.host=127.0.0.1 #第3个参与方的账本初始服务的端口; diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java index 81a04e7e..455940dd 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java @@ -8,44 +8,53 @@ */ package test.com.jd.blockchain.intgr; +import static com.jd.blockchain.transaction.ContractReturnValue.decode; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.commons.io.FileUtils; +import org.springframework.core.io.ClassPathResource; + import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.contract.ReadContract; import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.*; -import com.jd.blockchain.ledger.core.LedgerManage; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.KVDataEntry; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInitOperation; +import com.jd.blockchain.ledger.OperationResult; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.TransactionTemplate; +import com.jd.blockchain.ledger.UserRegisterOperation; import com.jd.blockchain.ledger.core.LedgerRepository; import com.jd.blockchain.ledger.core.impl.LedgerManager; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.storage.service.DbConnection; import com.jd.blockchain.storage.service.DbConnectionFactory; import com.jd.blockchain.tools.initializer.LedgerBindingConfig; +import com.jd.blockchain.transaction.GenericValueHolder; import com.jd.blockchain.utils.Bytes; -import com.jd.blockchain.utils.codec.HexUtils; import com.jd.blockchain.utils.concurrent.ThreadInvoker; import com.jd.blockchain.utils.net.NetworkAddress; -import org.apache.commons.io.FileUtils; -import org.junit.Assert; -import org.springframework.core.io.ClassPathResource; -import test.com.jd.blockchain.intgr.contract.AssetContract; -import test.com.jd.blockchain.intgr.contract.AssetContract2; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicLong; - -import static org.junit.Assert.*; - /** * * @author shaozhuguang @@ -63,7 +72,8 @@ public class IntegrationBase { public static final String PASSWORD = "abc"; - public static final String[] PUB_KEYS = { "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", + public static final String[] PUB_KEYS = { + "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk" }; @@ -441,9 +451,9 @@ public class IntegrationBase { // 合约测试使用的初始化数据; static BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate(); static BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); - // 保存资产总数的键; - // 第二个参数; - private static String contractZipName = "contract.jar"; + // 保存资产总数的键; + // 第二个参数; + private static String contractZipName = "contract-read.jar"; static HashDigest txContentHash; public static LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash, @@ -477,67 +487,146 @@ public class IntegrationBase { assertArrayEquals(contractCode, contractCodeInDb); // execute the contract; - testContractExe(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); - testContractExe1(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); - +// testContractExe(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); +// testContractExe1(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository); + testExeReadContract(adminKey, ledgerHash, blockchainService); return block; } - private static void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey, - BlockchainService blockchainService, LedgerRepository ledgerRepository) { - LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); - LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); +// private static void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey, +// BlockchainService blockchainService, LedgerRepository ledgerRepository) { +// LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); +// LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); +// +// // 定义交易; +// TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); +// +// Byte byteObj = Byte.parseByte("123"); +//// txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj, +//// contractDeployKey.getAddress().toBase58(),321123); +// txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj, +// dataKey.getAddress().toBase58(),Bytes.fromString("123321")); +// +// // 签名; +// PreparedTransaction ptx = txTpl.prepare(); +// ptx.sign(adminKey); +// +// // 提交并等待共识返回; +// TransactionResponse txResp = ptx.commit(); +// +// // 验证结果; +// Assert.assertTrue(txResp.isSuccess()); +// assertEquals(ptx.getHash(),txResp.getContentHash()); +// LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight()); +// KVDataEntry[] kvDataEntries = ledgerRepository.getDataAccountSet(block).getDataAccount(dataKey.getAddress()).getDataEntries(0,1); +// assertEquals("100",kvDataEntries[0].getValue().toString()); +// } + +// private static void testContractExe1(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey, +// BlockchainService blockchainService,LedgerRepository ledgerRepository) { +// LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); +// LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); +// +// // 定义交易; +// TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); +// +// AssetContract2 assetContract = txTpl.contract(contractDeployKey.getAddress(), AssetContract2.class); +// ContractBizContent contractBizContent = () -> new String[]{"param1","param2"}; +// assetContract.issue(contractBizContent,dataKey.getAddress().toBase58(),123456); +// +// // 签名; +// PreparedTransaction ptx = txTpl.prepare(); +// ptx.sign(adminKey); +// +// // 提交并等待共识返回; +// TransactionResponse txResp = ptx.commit(); +// +// // 验证结果; +// Assert.assertTrue(txResp.isSuccess()); +// assertEquals(ptx.getHash(),txResp.getContentHash()); +// LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight()); +// KVDataEntry[] kvDataEntries = ledgerRepository.getDataAccountSet(block).getDataAccount(dataKey.getAddress()).getDataEntries(1,2); +// assertEquals("value1",kvDataEntries[0].getValue().toString()); +// assertEquals(888L,kvDataEntries[1].getValue()); +// } + + private static void testExeReadContract(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainService blockchainService) { + + // 首先注册一个数据账户 + BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); - // 定义交易; TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + txTpl.dataAccounts().register(newDataAccount.getIdentity()); - Byte byteObj = Byte.parseByte("123"); -// txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj, -// contractDeployKey.getAddress().toBase58(),321123); - txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj, - dataKey.getAddress().toBase58(),Bytes.fromString("123321")); - - // 签名; PreparedTransaction ptx = txTpl.prepare(); ptx.sign(adminKey); // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); + ptx.commit(); - // 验证结果; - Assert.assertTrue(txResp.isSuccess()); - assertEquals(ptx.getHash(),txResp.getContentHash()); - LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight()); - KVDataEntry[] kvDataEntries = ledgerRepository.getDataAccountSet(block).getDataAccount(dataKey.getAddress()).getDataEntries(0,1); - assertEquals("100",kvDataEntries[0].getValue().toString()); - } + // 再提交一个KV写入 + String key1 = "JingDong", value1 = "www.jd.com"; + String key2 = "JD", value2 = "JingDong"; + String key3 = "Test", value3 = "OK"; + + TransactionTemplate txKv = blockchainService.newTransaction(ledgerHash); + txKv.dataAccount(newDataAccount.getAddress()) + .setText(key1, value1, -1) + .setBytes(key2, Bytes.fromString(value2), -1) + .setBytes(key3, Bytes.fromString(value3).toBytes(), -1); + PreparedTransaction kvPtx = txKv.prepare(); + kvPtx.sign(adminKey); - private static void testContractExe1(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey, - BlockchainService blockchainService,LedgerRepository ledgerRepository) { - LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash); - LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1); + // 提交并等待共识返回; + kvPtx.commit(); - // 定义交易; - TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); + // 下面才是执行Read交易 + // 定义交易; + TransactionTemplate txContract = blockchainService.newTransaction(ledgerHash); - AssetContract2 assetContract = txTpl.contract(contractDeployKey.getAddress(), AssetContract2.class); - ContractBizContent contractBizContent = () -> new String[]{"param1","param2"}; - assetContract.issue(contractBizContent,dataKey.getAddress().toBase58(),123456); + ReadContract readContract1 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); - // 签名; - PreparedTransaction ptx = txTpl.prepare(); - ptx.sign(adminKey); + GenericValueHolder result1 = decode(readContract1.read(newDataAccount.getAddress().toBase58(), key1)); - // 提交并等待共识返回; - TransactionResponse txResp = ptx.commit(); + ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); - // 验证结果; - Assert.assertTrue(txResp.isSuccess()); - assertEquals(ptx.getHash(),txResp.getContentHash()); - LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight()); - KVDataEntry[] kvDataEntries = ledgerRepository.getDataAccountSet(block).getDataAccount(dataKey.getAddress()).getDataEntries(1,2); - assertEquals("value1",kvDataEntries[0].getValue().toString()); - assertEquals(888L,kvDataEntries[1].getValue()); + readContract2.read(newDataAccount.getAddress().toBase58(), key2); + + ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); + + GenericValueHolder result3 = decode(readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2)); + + // 签名; + PreparedTransaction contractPtx = txContract.prepare(); + contractPtx.sign(adminKey); + + // 提交并等待共识返回; + TransactionResponse readTxResp = contractPtx.commit(); + + OperationResult[] operationResults = readTxResp.getOperationResults(); + + // 通过EventResult获取结果 + System.out.printf("readContract1.result = %s \r\n", result1.get()); + System.out.printf("readContract3.result = %s \r\n", result3.get()); + + +// // 打印结果 +// for (OperationResult or : operationResults) { +// System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), ContractSerializeUtils.resolve(or.getResult())); +// } +// +// // 验证结果 +// assertNotNull(contractReturn); +// assertEquals(contractReturn.length, 3); +// +// String returnVal1 = contractReturn[0]; +// assertEquals(value1, returnVal1); +// +// String returnVal2 = contractReturn[1]; +// assertEquals(value2, returnVal2); +// +// String returnVal3 = contractReturn[2]; +// assertEquals("0", returnVal3); } /** diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java index 1da5341b..f1f5288c 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java @@ -1,12 +1,32 @@ package test.com.jd.blockchain.intgr; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; + +import org.junit.Test; +import org.springframework.core.io.ClassPathResource; + import com.jd.blockchain.consensus.ConsensusProvider; import com.jd.blockchain.consensus.ConsensusSettings; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.PrivKey; import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; -import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerInfo; +import com.jd.blockchain.ledger.PreparedTransaction; +import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionTemplate; import com.jd.blockchain.ledger.core.LedgerRepository; import com.jd.blockchain.sdk.BlockchainService; import com.jd.blockchain.sdk.client.GatewayServiceFactory; @@ -17,22 +37,12 @@ import com.jd.blockchain.tools.initializer.Prompter; import com.jd.blockchain.tools.keygen.KeyGenCommand; import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback; import com.jd.blockchain.utils.net.NetworkAddress; -import org.junit.Test; -import org.springframework.core.io.ClassPathResource; + import test.com.jd.blockchain.intgr.IntegratedContext.Node; import test.com.jd.blockchain.intgr.contract.AssetContract; import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest; import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest.NodeWebContext; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.*; - /** * 测试合约,提交后不立即进行验证,因为此时可能还没有完成正式结块; */ diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/capability/LedgerPerfCapabilityTest.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/capability/LedgerPerfCapabilityTest.java index 6c6e4642..6e23c83f 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/capability/LedgerPerfCapabilityTest.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/capability/LedgerPerfCapabilityTest.java @@ -38,22 +38,22 @@ public class LedgerPerfCapabilityTest { @Test public void testKvStorage4Memory() { - LedgerPerformanceTest.test(new String[]{SILENT, CONSENSUS}); + LedgerPerformanceTest.test(new String[]{SILENT}); } @Test public void testUserRegister4Memory() { - LedgerPerformanceTest.test(new String[]{USERTEST, SILENT, CONSENSUS}); + LedgerPerformanceTest.test(new String[]{USERTEST, SILENT}); } @Test public void testKvStorage4Rocksdb() { - LedgerPerformanceTest.test(new String[]{ROCKSDB, SILENT, CONSENSUS}); + LedgerPerformanceTest.test(new String[]{ROCKSDB, SILENT}); } @Test public void testUserRegister4Rocksdb() { - LedgerPerformanceTest.test(new String[]{USERTEST, ROCKSDB, SILENT, CONSENSUS}); + LedgerPerformanceTest.test(new String[]{USERTEST, ROCKSDB, SILENT}); } public void testUserRegister4Redis() { diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java deleted file mode 100644 index a70142fb..00000000 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java +++ /dev/null @@ -1,44 +0,0 @@ -package test.com.jd.blockchain.intgr.contract; - -import com.jd.blockchain.contract.Contract; -import com.jd.blockchain.contract.ContractEvent; -import com.jd.blockchain.ledger.ContractBizContent; -import com.jd.blockchain.utils.Bytes; - -import java.math.BigDecimal; - -/** - * 示例:一个“资产管理”智能合约; - * - * @author zhaogw - */ -@Contract -public interface AssetContract2 { - - /** - * 发行资产; - * 新发行的资产数量; - * @param assetHolderAddress - * 新发行的资产的持有账户; - */ - @ContractEvent(name = "issue-asset-0") - void issue(ContractBizContent contractBizContent, String assetHolderAddress); - - /** - * 发行资产; - * 新发行的资产数量; - * @param assetHolderAddress - * 新发行的资产的持有账户; - */ - @ContractEvent(name = "issue-asset") - void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber); - - @ContractEvent(name = "issue-asset-2") - void issue(Bytes bytes, String assetHolderAddress, long cashNumber); - - @ContractEvent(name = "issue-asset-3") - void issue(Byte byteObj, String assetHolderAddress, long cashNumber); - - @ContractEvent(name = "issue-asset-4") - void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber); -} \ No newline at end of file diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContractImpl.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContractImpl.java new file mode 100644 index 00000000..9c1ec6e1 --- /dev/null +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContractImpl.java @@ -0,0 +1,5 @@ +package test.com.jd.blockchain.intgr.contract; + +public class AssetContractImpl { + +} diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/ContractInvocationTest.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/ContractInvocationTest.java new file mode 100644 index 00000000..46698426 --- /dev/null +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/ContractInvocationTest.java @@ -0,0 +1,14 @@ +package test.com.jd.blockchain.intgr.contract; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class ContractInvocationTest { + + @Test + public void test() { + + } + +} diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/ledger/LedgerBlockGeneratingTest.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/ledger/LedgerBlockGeneratingTest.java index a97a26c4..77bdef66 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/ledger/LedgerBlockGeneratingTest.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/ledger/LedgerBlockGeneratingTest.java @@ -58,8 +58,6 @@ public class LedgerBlockGeneratingTest { DefaultOperationHandleRegisteration opHandler = new DefaultOperationHandleRegisteration(); - System.gc(); - test(ledgerHash, node.getPartiKey(), ledgerManager, opHandler, 1000, 5); } diff --git a/source/test/test-integration/src/test/resources/contract-read.jar b/source/test/test-integration/src/test/resources/contract-read.jar index 38f81951..ddf9c668 100644 Binary files a/source/test/test-integration/src/test/resources/contract-read.jar and b/source/test/test-integration/src/test/resources/contract-read.jar differ diff --git a/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/web/LedgerInitializeWebController.java b/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/web/LedgerInitializeWebController.java index 4c9af288..ecf5f640 100644 --- a/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/web/LedgerInitializeWebController.java +++ b/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/web/LedgerInitializeWebController.java @@ -425,7 +425,7 @@ public class LedgerInitializeWebController implements LedgerInitProcess, LedgerI userRegOP.getUserID().getPubKey()); } - txCtx.commit(TransactionState.SUCCESS); + txCtx.commit(TransactionState.SUCCESS, null); return ledgerEditor.prepare(); } diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java index b03d88af..570ccfc4 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java @@ -293,7 +293,7 @@ public class MockerLedgerInitializer implements LedgerInitProcess, LedgerInitCon userRegOP.getUserID().getPubKey()); } - txCtx.commit(TransactionState.SUCCESS); + txCtx.commit(TransactionState.SUCCESS, null); return ledgerEditor.prepare(); } diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java index 1d7f91ec..8e32d3df 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java @@ -19,32 +19,7 @@ import com.jd.blockchain.crypto.PubKey; import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; -import com.jd.blockchain.ledger.AccountHeader; -import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.ContractCodeDeployOperation; -import com.jd.blockchain.ledger.ContractEventSendOperation; -import com.jd.blockchain.ledger.DataAccountKVSetOperation; -import com.jd.blockchain.ledger.DataAccountRegisterOperation; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.KVDataEntry; -import com.jd.blockchain.ledger.KVInfoVO; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInfo; -import com.jd.blockchain.ledger.LedgerMetadata; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.NodeRequest; -import com.jd.blockchain.ledger.Operation; -import com.jd.blockchain.ledger.ParticipantNode; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionRequestBuilder; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.UserInfo; -import com.jd.blockchain.ledger.UserRegisterOperation; +import com.jd.blockchain.ledger.*; import com.jd.blockchain.ledger.core.CryptoConfig; import com.jd.blockchain.ledger.core.LedgerDataSet; import com.jd.blockchain.ledger.core.LedgerEditor; @@ -398,7 +373,7 @@ public class MockerNodeContext implements BlockchainQueryService { } @Override - public AccountHeader getContract(HashDigest ledgerHash, String address) { + public ContractInfo getContract(HashDigest ledgerHash, String address) { return queryService.getContract(ledgerHash, address); } @@ -427,15 +402,16 @@ public class MockerNodeContext implements BlockchainQueryService { return reqBuilder.buildRequest(); } - public void txProcess(TransactionRequest txRequest) { + public OperationResult[] txProcess(TransactionRequest txRequest) { LedgerEditor newEditor = ledgerRepository.createNextBlock(); LedgerBlock latestBlock = ledgerRepository.getLatestBlock(); LedgerDataSet previousDataSet = ledgerRepository.getDataSet(latestBlock); TransactionBatchProcessor txProc = new TransactionBatchProcessor(newEditor, previousDataSet, opHandler, ledgerManager); - txProc.schedule(txRequest); + TransactionResponse txResp = txProc.schedule(txRequest); TransactionBatchResultHandle handle = txProc.prepare(); handle.commit(); + return txResp.getOperationResults(); } private LedgerRepository registerLedger(HashDigest ledgerHash, DBConnectionConfig dbConnConf) { diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java index 5813849b..e414e2df 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java @@ -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; @@ -65,17 +65,8 @@ public class AccountContractImpl implements EventProcessingAwire, AccountContrac } @Override - public void postEvent(ContractEventContext eventContext, ContractException error) { + public void postEvent(ContractEventContext eventContext, Exception error) { } - @Override - public void postEvent(ContractException error) { - - } - - @Override - public void postEvent() { - - } } diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java index 2dbd8ae5..9662dd68 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java @@ -10,5 +10,5 @@ public interface WriteContract { void print(String name); @ContractEvent(name = "writeKv") - void writeKv(String address, String key, String value); + String writeKv(String address, String key, String value); } diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java index 48874420..83f5521d 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java @@ -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; @@ -15,8 +15,9 @@ public class WriteContractImpl implements EventProcessingAwire, WriteContract { } @Override - public void writeKv(String address, String key, String value) { + public String writeKv(String address, String key, String value) { eventContext.getLedger().dataAccount(address).setText(key, value, -1); + return String.format("address = %s, key = %s, value = %s, version = %s", address, key, value, 0); } @Override @@ -25,17 +26,8 @@ public class WriteContractImpl implements EventProcessingAwire, WriteContract { } @Override - public void postEvent(ContractEventContext eventContext, ContractException error) { + public void postEvent(ContractEventContext eventContext, Exception error) { System.out.println("----- postEvent1 -----"); } - @Override - public void postEvent(ContractException error) { - System.out.println("----- postEvent2 -----"); - } - - @Override - public void postEvent() { - System.out.println("----- postEvent3 -----"); - } } diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java index 53bc9417..cb26ac92 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java @@ -1,26 +1,25 @@ package com.jd.blockchain.mocker.handler; +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.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; -import com.jd.blockchain.ledger.ContractEventSendOperation; -import com.jd.blockchain.ledger.Operation; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.ledger.*; +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.LedgerQueryService; import com.jd.blockchain.ledger.core.impl.OperationHandleContext; import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext; import com.jd.blockchain.mocker.proxy.ExecutorProxy; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - - public class MockerContractExeHandle implements OperationHandle { private Map executorProxyMap = new ConcurrentHashMap<>(); @@ -30,7 +29,7 @@ public class MockerContractExeHandle implements OperationHandle { private HashDigest ledgerHash; @Override - public void process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { ContractEventSendOperation contractOP = (ContractEventSendOperation) op; @@ -38,28 +37,39 @@ public class MockerContractExeHandle implements OperationHandle { ExecutorProxy executorProxy = executorProxyMap.get(txHash); + Object result = null; if (executorProxy != null) { LedgerQueryService queryService = new LedgerQueryService(ledgerManager); ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext); - MockerContractEventContext contractEventContext = new MockerContractEventContext( - ledgerHash, contractOP.getEvent(), requestContext.getRequest(), ledgerContext); + MockerContractEventContext contractEventContext = new MockerContractEventContext(ledgerHash, + contractOP.getEvent(), requestContext.getRequest(), ledgerContext); - EventProcessingAwire eventProcessingAwire = (EventProcessingAwire) executorProxy.getInstance(); - try { - // - // Before处理过程 - eventProcessingAwire.beforeEvent(contractEventContext); - executorProxy.invoke(); + Object instance = executorProxy.getInstance(); + EventProcessingAware awire = null; - // After处理过程 - eventProcessingAwire.postEvent(); + if (instance instanceof EventProcessingAware) { + awire = (EventProcessingAware) instance; + awire.beforeEvent(contractEventContext); + } + + try { + result = executorProxy.invoke(); + if (awire != null) { + // After处理过程 + awire.postEvent(contractEventContext, null); + } } catch (Exception e) { - eventProcessingAwire.postEvent(new ContractException(e.getMessage())); + if (awire != null) { + awire.postEvent(contractEventContext, new ContractException(e.getMessage())); + } } finally { removeExecutorProxy(txHash); } } + + // No return value; + return BytesValueEncoding.encodeSingle(result, null); } @Override @@ -90,8 +100,8 @@ public class MockerContractExeHandle implements OperationHandle { private LedgerContext ledgerContext; - public MockerContractEventContext(HashDigest ledgeHash, String event, - TransactionRequest transactionRequest, LedgerContext ledgerContext) { + public MockerContractEventContext(HashDigest ledgeHash, String event, TransactionRequest transactionRequest, + LedgerContext ledgerContext) { this.ledgeHash = ledgeHash; this.event = event; this.transactionRequest = transactionRequest; @@ -119,7 +129,7 @@ public class MockerContractExeHandle implements OperationHandle { } @Override - public byte[] getArgs() { + public BytesValueList getArgs() { return null; } diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java index 69fc305c..b2e23766 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java @@ -1,80 +1,88 @@ package com.jd.blockchain.mocker.proxy; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + import com.jd.blockchain.contract.Contract; import com.jd.blockchain.contract.ContractEvent; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BytesValueEncoding; +import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.mocker.MockerNodeContext; import com.jd.blockchain.mocker.handler.MockerContractExeHandle; import com.jd.blockchain.transaction.TxBuilder; -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; - public class ContractProxy implements InvocationHandler { - private BlockchainIdentity identity; + private BlockchainIdentity identity; + + private MockerNodeContext mockerNodeContext; - private MockerNodeContext mockerNodeContext; + private T instance; - private T instance; + private MockerContractExeHandle operationHandle; - private MockerContractExeHandle operationHandle; + public ContractProxy(BlockchainIdentity identity, MockerNodeContext mockerNodeContext, T instance, + MockerContractExeHandle operationHandle) { + this.identity = identity; + this.mockerNodeContext = mockerNodeContext; + this.instance = instance; + this.operationHandle = operationHandle; + } - public ContractProxy(BlockchainIdentity identity, MockerNodeContext mockerNodeContext, - T instance, MockerContractExeHandle operationHandle) { - this.identity = identity; - this.mockerNodeContext = mockerNodeContext; - this.instance = instance; - this.operationHandle = operationHandle; - } + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // 实际执行时,首先判断执行的是否是添加注解的方法 + if (!isExecuteContractMethod(method)) { + return method.invoke(instance, args); + } - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // 实际执行时,首先判断执行的是否是添加注解的方法 - if (!isExecuteContractMethod(method)) { - return method.invoke(instance, args); - } + // 首先发送一次执行的请求 + TxBuilder txBuilder = mockerNodeContext.txBuilder(); - // 首先发送一次执行的请求 - TxBuilder txBuilder = mockerNodeContext.txBuilder(); + Class contractInft = null; - Class contractInft = null; + Class[] instanceInfts = instance.getClass().getInterfaces(); - Class[] instanceInfts = instance.getClass().getInterfaces(); + for (Class instanceInft : instanceInfts) { + if (instanceInft.isAnnotationPresent(Contract.class)) { + contractInft = instanceInft; + break; + } + } - for (Class instanceInft : instanceInfts) { - if (instanceInft.isAnnotationPresent(Contract.class)) { - contractInft = instanceInft; - break; - } - } + if (contractInft == null) { + throw new IllegalStateException( + "This object does not implement the interface for the @Contract annotation !!!"); + } - if (contractInft == null) { - throw new IllegalStateException("This object does not implement the interface for the @Contract annotation !!!"); - } + // 生成代理类 + Object proxyInstance = txBuilder.contract(identity.getAddress().toBase58(), contractInft); + // 代理方式执行一次 + method.invoke(proxyInstance, args); - // 生成代理类 - Object proxyInstance = txBuilder.contract(identity.getAddress().toBase58(), contractInft); - // 代理方式执行一次 - method.invoke(proxyInstance, args); + TransactionRequest txRequest = mockerNodeContext.txRequest(txBuilder); - TransactionRequest txRequest = mockerNodeContext.txRequest(txBuilder); + // 放入到Map中 + HashDigest txHash = txRequest.getTransactionContent().getHash(); + operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args)); - // 放入到Map中 - HashDigest txHash = txRequest.getTransactionContent().getHash(); - operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args)); + // 提交该请求至整个区块链系统 + OperationResult[] operationResults = mockerNodeContext.txProcess(txRequest); + if (operationResults == null || operationResults.length == 0) { + return null; + } + OperationResult opResult = operationResults[0]; - // 提交该请求至整个区块链系统 - mockerNodeContext.txProcess(txRequest); - // 不处理返回值 - return null; - } + // 处理返回值 + return BytesValueEncoding.decode(opResult.getResult(), method.getReturnType()); + } - private boolean isExecuteContractMethod(Method method) { - Annotation annotation = method.getAnnotation(ContractEvent.class); - return annotation != null; - } + private boolean isExecuteContractMethod(Method method) { + Annotation annotation = method.getAnnotation(ContractEvent.class); + return annotation != null; + } } diff --git a/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java index d52a3732..5058ebdc 100644 --- a/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java +++ b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java @@ -39,7 +39,7 @@ public class AccountMockerTest { accountContract.create(address, accountTo, 1000L); - accountContract.print(address, accountFrom, accountTo); +// accountContract.print(address, accountFrom, accountTo); // 开始转账 accountContract.transfer(address, accountFrom, accountTo, 500); diff --git a/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java index c388ef99..19cd34df 100644 --- a/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java +++ b/source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java @@ -33,7 +33,9 @@ public class SampleTest { writeContract = mockerNodeContext.deployContract(writeContract); - writeContract.writeKv(dataAccountAddress, key, value); + String result = writeContract.writeKv(dataAccountAddress, key, value); + + System.out.println(result); // 查询结果 KVDataEntry[] dataEntries = mockerNodeContext.getDataEntries(ledgerHash, dataAccountAddress, key); diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/event/DefaultExceptionHandle.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/event/DefaultExceptionHandle.java index 998e619c..5ff08720 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/event/DefaultExceptionHandle.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/event/DefaultExceptionHandle.java @@ -5,8 +5,6 @@ import java.lang.reflect.Method; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.jd.blockchain.utils.console.CommandConsole; - public class DefaultExceptionHandle implements ExceptionHandle { @Override @@ -21,9 +19,8 @@ public class DefaultExceptionHandle implements ExceptionHandle implements Disposable { } public EventMulticaster(Class listenerClass, Logger errorLogger) { - this(listenerClass, new ExceptionLoggingHandle(errorLogger)); + this(listenerClass, new RethrowExceptionHandler(errorLogger)); } @SuppressWarnings("unchecked") public EventMulticaster(Class listenerClass, ExceptionHandle exHandle) { + if (!listenerClass.isInterface()) { + throw new IllegalArgumentException("The specified class of listener does not represent an interface!"); + } // 初始化错误处理器; - this.exHandle = exHandle == null ? new DefaultExceptionHandle() : exHandle; + this.exHandle = exHandle == null + ? new RethrowExceptionHandler(LoggerFactory.getLogger(EventMulticaster.class)) + : exHandle; // 解析出不支持的方法; Method[] methods = ReflectionUtils.getAllDeclaredMethods(listenerClass); - List supMths = new LinkedList(); + List supMths = new ArrayList(); for (Method method : methods) { if (method.getDeclaringClass() == Object.class) { // 不支持 Object 方法; @@ -86,14 +92,14 @@ public class EventMulticaster implements Disposable { throw new UnsupportedOperationException("Unsupported method for event multicasting!"); } } - - protected void doNotify(List listeners, Method method, Object[] args){ + + protected void doNotify(List listeners, Method method, Object[] args) { for (TListener listener : listeners) { doNotifySingle(listener, method, args); } } - - protected void doNotifySingle(TListener listener, Method method, Object[] args){ + + protected void doNotifySingle(TListener listener, Method method, Object[] args) { try { ReflectionUtils.invokeMethod(method, listener, args); } catch (Exception e) { @@ -104,12 +110,12 @@ public class EventMulticaster implements Disposable { public void addListener(TListener listener) { listeners.add(listener); } - + public void removeListener(TListener listener) { listeners.remove(listener); } - public TListener broadcast() { + public TListener getBroadcaster() { return listenerProxy; } diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java index 255ebd2a..93520e0e 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/BytesUtils.java @@ -6,6 +6,7 @@ import java.io.InputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.math.BigInteger; import com.jd.blockchain.utils.IllegalDataException; @@ -370,6 +371,10 @@ public class BytesUtils { return value; } + public static short toShort(byte[] bytes) { + return toShort(bytes, 0); + } + public static char toChar(byte[] bytes, int offset) { char value = 0; value = (char) ((value | (bytes[offset] & 0xFF)) << 8); diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/FileUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/FileUtils.java index 77cfca01..0d4d86e1 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/FileUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/FileUtils.java @@ -442,37 +442,44 @@ public class FileUtils { } public static void deleteFile(File file) { - deleteFile(file, false); + deletePath(file, false); } public static void deleteFile(String dir, boolean silent) { File directory = new File(dir); - deleteFile(directory, silent); + deletePath(directory, silent); } /** - * 删除文件; + * 删除文件;
* - * @param file - * @param silent 是否静默删除;如果为 true ,则吞噬删除过程中的异常,意味着方法即便正常返回时也有可能删除不完全; + * @param path 如果指定的路径是单个文件,则删除该文件;如果指定路径是目录,则删除该目录及其下的全部文件; + * @param silent 是否静默删除;如果为 true ,则吞噬删除过程中的异常, 意味着方法即便正常返回时也有可能删除不完全; + * @return 如果删除成功,则返回 true; 否则返回 false,或者抛出 {@link RuntimeIOException}; */ - public static void deleteFile(File file, boolean silent) { - if (file.isFile()) { + public static boolean deletePath(File path, boolean silent) { + if (path.isFile()) { try { - file.delete(); - return; + path.delete(); + return true; } catch (Exception e) { if (!silent) { throw new RuntimeIOException(e.getMessage(), e); } } + + return false; } - File[] files = file.listFiles(); + + // delete dir; + File[] files = path.listFiles(); if (files == null) { - return; + return false; } + for (File f : files) { - deleteFile(f, silent); + deletePath(f, silent); } + return path.delete(); } }