Browse Source

Merge remote-tracking branch 'origin/feature/contract_invocation' into develop-local

# Conflicts:
#	source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java
tags/1.0.0
shaozhuguang 6 years ago
parent
commit
09d14c3040
100 changed files with 2861 additions and 1530 deletions
  1. +8
    -12
      source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
  2. +63
    -0
      source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BaseType.java
  3. +2
    -0
      source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java
  4. +0
    -24
      source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataType.java
  5. +13
    -39
      source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/PrimitiveType.java
  6. +2
    -4
      source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java
  7. +2
    -3
      source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java
  8. +105
    -0
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java
  9. +24
    -0
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/ContractDefinition.java
  10. +0
    -1
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java
  11. +65
    -92
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java
  12. +1
    -1
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java
  13. +0
    -1
      source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java
  14. +0
    -1
      source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java
  15. +2
    -2
      source/contract/contract-samples/pom.xml
  16. +5
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java
  17. +21
    -14
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java
  18. +17
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java
  19. +109
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java
  20. +11
    -5
      source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java
  21. +18
    -0
      source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java
  22. +18
    -1
      source/gateway/pom.xml
  23. +249
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java
  24. +218
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java
  25. +13
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java
  26. +18
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java
  27. +13
    -5
      source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
  28. +4
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java
  29. +7
    -6
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java
  30. +4
    -4
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java
  31. +27
    -6
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java
  32. +26
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java
  33. +4
    -4
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java
  34. +21
    -32
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/DefaultOperationHandleRegisteration.java
  35. +0
    -85
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerInitializer.java
  36. +7
    -19
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java
  37. +21
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java
  38. +23
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java
  39. +25
    -30
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java
  40. +11
    -31
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java
  41. +12
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java
  42. +10
    -26
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java
  43. +18
    -7
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java
  44. +14
    -6
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java
  45. +43
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java
  46. +13
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java
  47. +7
    -7
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/BaseAccountTest.java
  48. +50
    -0
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingHandle.java
  49. +223
    -0
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
  50. +7
    -45
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java
  51. +2
    -2
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java
  52. +69
    -35
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java
  53. +1
    -1
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTransactionDataTest.java
  54. +58
    -0
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContract.java
  55. +49
    -0
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContractImpl.java
  56. +140
    -392
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java
  57. +19
    -7
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java
  58. +0
    -1
      source/ledger/ledger-model/pom.xml
  59. +11
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractAware.java
  60. +4
    -3
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractEventContext.java
  61. +8
    -7
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractException.java
  62. +1
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractLifecycleAware.java
  63. +0
    -11
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractRuntimeAwire.java
  64. +165
    -196
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java
  65. +147
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java
  66. +0
    -52
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ErrorCodeEnum.java
  67. +2
    -15
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAware.java
  68. +39
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java
  69. +4
    -11
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java
  70. +23
    -23
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java
  71. +31
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesDataList.java
  72. +1
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValue.java
  73. +199
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEncoding.java
  74. +13
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java
  75. +0
    -20
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java
  76. +0
    -19
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java
  77. +0
    -18
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java
  78. +0
    -18
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java
  79. +0
    -18
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java
  80. +0
    -18
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java
  81. +0
    -18
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java
  82. +0
    -14
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractArgs.java
  83. +0
    -20
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java
  84. +4
    -10
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java
  85. +13
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java
  86. +1
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountKVSetOperation.java
  87. +46
    -20
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java
  88. +1
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataEntry.java
  89. +20
    -20
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataObject.java
  90. +8
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataVO.java
  91. +7
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVInfoVO.java
  92. +16
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java
  93. +35
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java
  94. +11
    -11
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java
  95. +11
    -5
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java
  96. +5
    -5
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java
  97. +8
    -8
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java
  98. +3
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionTemplate.java
  99. +54
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java
  100. +58
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java

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

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


+ 63
- 0
source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BaseType.java View File

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

/**
* 扩展类型;<br>
*
* 最高位为1,用作保留字段;
*/
public static final byte EXT = (byte) 0x80;

}

+ 2
- 0
source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/BinaryProtocol.java View File

@@ -57,5 +57,7 @@ public class BinaryProtocol {
}

}

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

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

}

+ 13
- 39
source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/PrimitiveType.java View File

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


+ 2
- 4
source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java View File

@@ -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<String> execReturn);
BytesValue processEvent(ContractEventContext eventContext);
}

+ 2
- 3
source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractEngine.java View File

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

}

+ 105
- 0
source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java View File

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

}

+ 24
- 0
source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/ContractDefinition.java View File

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

}

+ 0
- 1
source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JVMContractEngine.java View File

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


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

@@ -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<String> 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<DataContract> 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<String> contractReturn;
private class ContractExecution implements Callable<BytesValue> {
private ContractEventContext eventContext;

public ContractExecution(CompletableFuture<String> 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);
}
}



+ 1
- 1
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java View File

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


+ 0
- 1
source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java View File

@@ -1,6 +1,5 @@
package com.jd.blockchain.contract;

import com.jd.blockchain.ledger.ContractBizContent;
import com.jd.blockchain.utils.Bytes;

/**


+ 0
- 1
source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java View File

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


+ 2
- 2
source/contract/contract-samples/pom.xml View File

@@ -34,11 +34,11 @@
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>contract</finalName>
<finalName>transfer</finalName>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<mainClass>com.jd.blockchain.contract.ReadContractImpl</mainClass>
<mainClass>com.jd.blockchain.contract.TransferContractImpl</mainClass>
</manifest>
</archive>
<descriptorRefs>


+ 5
- 0
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java View File

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


+ 21
- 14
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java View File

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

+ 17
- 0
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContract.java View File

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

+ 109
- 0
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/TransferContractImpl.java View File

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

}
}

+ 11
- 5
source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java View File

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


+ 18
- 0
source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java View File

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

+ 18
- 1
source/gateway/pom.xml View File

@@ -45,7 +45,7 @@

<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>browser</artifactId>
<artifactId>explorer</artifactId>
</dependency>

<dependency>
@@ -78,6 +78,23 @@
<version>${commons-io.version}</version>
</dependency>

<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-core</artifactId>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-expressions</artifactId>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-reflection</artifactId>
</dependency>
<dependency>
<groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-compilertools</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>


+ 249
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java View File

@@ -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<String, LinkedHashSet<byte[]>> packageLocations;
private final Map<String, byte[]> 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<byte[]> 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<byte[]> 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;
}
}

+ 218
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java View File

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

+ 13
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java View File

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

+ 18
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java View File

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

/**
* 初始化账本配置
*


+ 13
- 5
source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java View File

@@ -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" + "'}";


+ 4
- 2
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java View File

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


+ 7
- 6
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java View File

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


+ 4
- 4
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java View File

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


+ 27
- 6
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java View File

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

/**
* 抛弃对账本数据的修改,以指定的交易状态提交交易;<br>
* 提交对账本数据的修改,以指定的交易状态提交交易;
*
* @param txResult
* @param operationResults
*
* @return
*/
LedgerTransaction commit(TransactionState txResult, List<OperationResult> operationResults);

/**
* 抛弃对账本数据的修改,以指定的交易状态提交交易;<br>
*
* 通常来说,当在开启事务之后,修改账本或者尝试提交交易({@link #commit(TransactionState)})时发生错误,都应该抛弃数据,通过此方法记录一个表示错误状态的交易;
*
*
* @param txResult
* @return
*/
LedgerTransaction discardAndCommit(TransactionState txResult);

/**
* 抛弃对账本数据的修改,以指定的交易状态提交交易;<br>
*
* 通常来说,当在开启事务之后,修改账本或者尝试提交交易({@link #commit(TransactionState, List)})时发生错误,都应该抛弃数据,通过此方法记录一个表示错误状态的交易;
*
* @param txResult
* @return
*/
LedgerTransaction discardAndCommit(TransactionState txResult, List<OperationResult> operationResults);

/**
* 回滚事务,抛弃本次事务的所有数据更新;
*/


+ 26
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java View File

@@ -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<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext,
// LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService);
}

+ 4
- 4
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserAccount.java View File

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


+ 21
- 32
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/DefaultOperationHandleRegisteration.java View File

@@ -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<OperationHandle> 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() + "]!");
}

}

+ 0
- 85
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerInitializer.java View File

@@ -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;
//
///**
// * 账本初始化;<br>
// *
// * 初始生成账本时,所有的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();
// }
//}

+ 7
- 19
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java View File

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


+ 21
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java View File

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


+ 23
- 2
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java View File

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


+ 25
- 30
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java View File

@@ -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<CompletableFuture<String>> contractReturn = new ArrayList<>();

List<OperationResult> 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<String> 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;
}
}



source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractEventSendOperationHandle.java → source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java View File

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


}

+ 12
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java View File

@@ -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<byte[]> 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);


+ 10
- 26
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java View File

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


+ 18
- 7
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java View File

@@ -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<byte[]> 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);


+ 14
- 6
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java View File

@@ -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<byte[]> 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);


+ 43
- 0
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java View File

@@ -0,0 +1,43 @@
package com.jd.blockchain.ledger.core.impl.handles;

import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER;

import com.jd.blockchain.contract.engine.ContractCode;
import com.jd.blockchain.contract.engine.ContractEngine;
import com.jd.blockchain.contract.engine.ContractServiceProviders;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.core.ContractAccount;
import com.jd.blockchain.ledger.core.LedgerDataSet;
import com.jd.blockchain.ledger.core.LedgerService;
import com.jd.blockchain.ledger.core.TransactionRequestContext;
import com.jd.blockchain.ledger.core.impl.OperationHandleContext;
import com.jd.blockchain.utils.concurrent.AsyncFuture;

public class JVMContractEventSendOperationHandle extends AbtractContractEventHandle {

private static final ContractEngine JVM_ENGINE;

static {
JVM_ENGINE = ContractServiceProviders.getProvider(CONTRACT_SERVICE_PROVIDER).getEngine();
}

@Override
protected ContractCode loadContractCode(ContractAccount contract) {
ContractCode contractCode = JVM_ENGINE.getContract(contract.getAddress(), contract.getChaincodeVersion());
if (contractCode == null) {
// 装载合约;
contractCode = JVM_ENGINE.setupContract(contract.getAddress(), contract.getChaincodeVersion(),
contract.getChainCode());
}
return contractCode;
}

// @Override
// public AsyncFuture<byte[]> asyncProcess(Operation op, LedgerDataSet newBlockDataset,
// TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset,
// OperationHandleContext handleContext, LedgerService ledgerService) {
// // TODO Auto-generated method stub
// return null;
// }

}

+ 13
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java View File

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


+ 7
- 7
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/BaseAccountTest.java View File

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



+ 50
- 0
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingHandle.java View File

@@ -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<Bytes, ContractCode> contractInstances = new ConcurrentHashMap<Bytes, ContractCode>();

@Override
protected ContractCode loadContractCode(ContractAccount contract) {
return contractInstances.get(contract.getAddress());
}

public <T> ContractCode setup(Bytes address, Class<T> contractIntf, T instance) {
ContractCodeInstance<T> contract = new ContractCodeInstance<T>(address, 0, contractIntf, instance);
contractInstances.put(address, contract);
return contract;
}

private static class ContractCodeInstance<T> extends AbstractContractCode {

private T instance;

public ContractCodeInstance(Bytes address, long version, Class<T> delaredInterface, T instance) {
super(address, version, resolveContractDefinition(delaredInterface, instance.getClass()));
this.instance = instance;
}

private static ContractDefinition resolveContractDefinition(Class<?> declaredIntf, Class<?> implementedClass) {
ContractType contractType = ContractType.resolve(declaredIntf);
return new ContractDefinition(contractType, implementedClass);
}

@Override
protected T getContractInstance() {
return instance;
}

}

}

+ 223
- 0
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java View File

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

+ 7
- 45
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java View File

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

+ 2
- 2
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java View File

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


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

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


+ 1
- 1
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTransactionDataTest.java View File

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


+ 58
- 0
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContract.java View File

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

+ 49
- 0
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TestContractImpl.java View File

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

+ 140
- 392
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java View File

@@ -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<children.length; i++) {
// boolean success = deleteDir(new File(dir, children[i]));
// if (!success) {
// return false;
// }
// }
// }
// // 目录此时为空,可以删除
// return dir.delete();
// }
//
// @Test
// public void testContractOperations() {
// LedgerManager ledgerManager = new LedgerManager();
//
// ledgerHash = initLedger(ledgerManager, storage, sponsorKey,gatewayKey,contractKey);
// LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage);
//
// LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock());
// UserAccount userAcc = previousBlockDataset.getUserAccountSet().getUser(sponsorKey.getAddress());
// assertNotNull(userAcc);
// boolean sponsorRegistered = previousBlockDataset.getUserAccountSet().contains(sponsorKey.getAddress());
// assertTrue(sponsorRegistered);
//
// LedgerEditor newBlockEditor = ledgerRepo.createNextBlock();
//
// OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration();
// TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset,
// opReg, ledgerManager);
//
// // TODO: 生成合约交易;以及执行合约交易;
// transactionRequest = this.contractDeploy(ledgerHash, userKey, dataKey,sponsorKey,gatewayKey,contractKey);
// txbatchProcessor.schedule(transactionRequest);
//
// LedgerBlock newBlock = newBlockEditor.prepare();
// newBlockEditor.commit();
//
// //验证正确性;
// ledgerManager = new LedgerManager();
// ledgerRepo = ledgerManager.register(ledgerHash, storage);
//
// //验证合约部署
// byte[] actualChainCode = ledgerRepo.getContractAccountSet(newBlock).getContract(contractKey.getAddress()).getChainCode();
// assertArrayEquals(chainCode, actualChainCode);
//
// LedgerBlock latestBlock = ledgerRepo.getLatestBlock();
// assertEquals(newBlock.getHash(), latestBlock.getHash());
//
// //执行事件;
// LedgerEditor newBlockEditor1 = ledgerRepo.createNextBlock();
// LedgerDataSet previousBlockDataset1 = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock());
//// 采用schedule方式;
// txbatchProcessor = new TransactionBatchProcessor(newBlockEditor1, previousBlockDataset1,
// opReg, ledgerManager);
// txbatchProcessor.schedule(this.exeContractReq(ledgerHash, sponsorKey,gatewayKey,contractKey));
// //采用newTransaction方式处理;
// /**
// LedgerTransactionContext txCtx = newBlockEditor1.newTransaction(
// this.exeContractReq(ledgerHash, sponsorKey,gatewayKey,contractKey));
// LedgerDataSet ldgDS = txCtx.getDataSet();
// SignatureDigest signDigest = CryptoUtils.sign(CryptoAlgorithm.ED25519).sign(contractKey.getPrivKey(), Base58Utils.decode(contractKey.getAddress()));
// DigitalSignatureBlob dgtSign = new DigitalSignatureBlob(contractKey.getPubKey(), signDigest);
// // DataAccount dataAccount = ldgDS.getDataAccountSet().register(dataKey.getAddress(), dataKey.getPubKey(),null);
// // dataAccount.setBytes("latestBlockHash", ledgerRepo.getLatestBlock().getPreviousHash().getRawDigest(), -1);
// // 提交交易结果;
// LedgerTransaction tx = txCtx.commit(TransactionState.SUCCESS);
// */
//
// LedgerBlock newBlock1 = newBlockEditor1.prepare();
// newBlockEditor1.commit();
//// assertEquals(expected, actual);
//
// //验证合约中的赋值,外部可以获得;
// //base test;
// DataAccountSet dataAccountSet = ledgerRepo.getDataAccountSet(newBlock1);
// PubKey pubKey = new PubKey(CryptoAlgorithm.ED25519, pubKeyVal.getBytes());
// Bytes dataAddress = AddressEncoding.generateAddress(pubKey);
// assertEquals(dataAddress,dataAccountSet.getDataAccount(dataAddress).getAddress());
// assertEquals("hello",new String(dataAccountSet.getDataAccount(dataAddress).getBytes(KEY_TOTAL,-1)));
// //验证userAccount,从合约内部赋值,然后外部验证;
//// UserAccountSet userAccountSet = ledgerRepo.getUserAccountSet(newBlock1);
//// PubKey userPubKey = new PubKey(CryptoAlgorithm.ED25519, userPubKeyVal.getBytes());
//// String userAddress = AddressEncoding.generateAddress(userPubKey);
//// assertEquals(userAddress,userAccountSet.getUser(userAddress).getAddress());
//
// }
//
// private TransactionRequest contractDeploy(HashDigest ledgerHash, BlockchainKeyPair userKey, BlockchainKeyPair dataKey,
// BlockchainKeyPair sponsorKey, BlockchainKeyPair gatewayKey, BlockchainKeyPair contractKey){
// // Build transaction request;
// TransactionBuilder txBuilder = new TxBuilder(ledgerHash);
// UserRegisterOperation userRegOp = txBuilder.users().register(userKey.getIdentity());
// DataAccountRegisterOperation dataAccRegOp = txBuilder.dataAccounts().register(dataKey.getIdentity());
//
// DataAccountKVSetOperation kvsetOP = txBuilder.dataAccount(dataKey.getAddress())
// .set("A", "Value_A_0".getBytes(), -1)
// .set("B", "Value_B_0".getBytes(), -1)
// .set(KEY_TOTAL, "total value,dataAccount".getBytes(), -1)
// .set(KEY_ABC, "abc value,dataAccount".getBytes(), -1)
// //所有的模拟数据都在这个dataAccount中填充;
// .set("ledgerHash", ledgerHash.getRawDigest(), -1)
//// .set("latestBlockHash", ledgerBlock.getPreviousHash().getRawDigest(), -1)
// .getOperation();
// chainCode = this.getChainCodeBytes();
// ContractCodeDeployOperation contractDplOP = txBuilder.contracts().deploy(contractKey.getIdentity(), this.getChainCodeBytes());
//// ContractEventSendOperation contractEvtSendOP = txBuilder.contractEvents().send(contractKey.getAddress(), "test",
//// "TestContractArgs".getBytes());
// TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();
// txReqBuilder.signAsEndpoint(sponsorKey);
// txReqBuilder.signAsNode(gatewayKey);
// return txReqBuilder.buildRequest();
// }
//
// private TransactionRequest exeContractReq(HashDigest ledgerHash, BlockchainKeyPair sponsorKey, BlockchainKeyPair gatewayKey, BlockchainKeyPair contractKey){
// // Build transaction request;
// TransactionBuilder txBuilder = new TxBuilder(ledgerHash);
// LedgerManager ledgerManager = new LedgerManager();
// LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage);
// LedgerBlock ledgerBlock = ledgerRepo.getLatestBlock();
//// txBuilder.dataAccounts().register(dataKey1.getIdentity());
//// txBuilder.dataAccount(dataKey.getAddress())
//// .set("latestBlockHash", ledgerBlock.getPreviousHash().getRawDigest(), -1).getOperation();
//// HashDigest txRootHashDigest = ledgerRepo.getTransactionSet(ledgerBlock).getRootHash();
//
// LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock());
// previousBlockDataset.getUserAccountSet().getUser(userKey.getAddress());
//
//
// ContractEventSendOperation contractEvtSendOP = txBuilder.contractEvents().send(contractKey.getAddress(), "issue-asset",
// ("888##abc##"+dataKey.getAddress()+"##"+ledgerBlock.getPreviousHash().toBase58()+"##"+
// userKey.getAddress()+"##"+contractKey.getAddress()+"##"+transactionRequest.getTransactionContent().getHash().toBase58()
// +"##"+pubKeyVal).getBytes());
//
// TransactionSet txset = ledgerRepo.getTransactionSet(ledgerBlock);
// txset.get(transactionRequest.getTransactionContent().getHash());//此处有value;
//
// TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();
// txReqBuilder.signAsEndpoint(sponsorKey);
// txReqBuilder.signAsNode(gatewayKey);
// return txReqBuilder.buildRequest();
// }
//
// private HashDigest initLedger(LedgerManager ledgerManager, MemoryKVStorage storage, BlockchainKeyPair userKP,
// BlockchainKeyPair gatewayKey,BlockchainKeyPair contractKey) {
// // 创建账本初始化配置;
// LedgerInitSetting initSetting = createLedgerInitSetting();
//
// // 新建账本;
// LedgerEditor ldgEdt = ledgerManager.newLedger(initSetting, storage);
//
// // 创建一个模拟的创世交易;
// TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest(ledgerHash,
// CryptoUtils.sign(CryptoAlgorithm.ED25519));
//
// // 记录交易,注册用户;
// LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq);
// LedgerDataSet ldgDS = txCtx.getDataSet();
// UserAccount userAccount = ldgDS.getUserAccountSet().register(userKP.getAddress(), userKP.getPubKey());
// userAccount.setProperty("Name", "孙悟空", -1);
// userAccount.setProperty("Age", "10000", -1);
// System.out.println("UserAddress=" + userAccount.getAddress());
//
// UserAccount gatewayUserAccount = ldgDS.getUserAccountSet().register(gatewayKey.getAddress(), gatewayKey.getPubKey());
// userAccount.setProperty("Name", "齐天大圣", -1);
// userAccount.setProperty("Age", "11111", -1);
// System.out.println("gatewayUserAccount=" + userAccount.getAddress());
//
// //注册contract;
//// SignatureDigest signDigest = CryptoUtils.sign(CryptoAlgorithm.ED25519).sign(contractKey.getPrivKey(), Base58Utils.decode(contractKey.getAddress()));
//// DigitalSignatureBlob dgtSign = new DigitalSignatureBlob(contractKey.getPubKey(), signDigest);
//// ldgDS.getContractAccountSet().deploy(contractKey.getAddress(),contractKey.getPubKey(),dgtSign,this.contractBytes());
//
// // 提交交易结果;
// LedgerTransaction tx = txCtx.commit(TransactionState.SUCCESS);
//
// // 生成区块;
// LedgerBlock genesisBlock = ldgEdt.prepare();
// ldgEdt.commit();
// return genesisBlock.getHash();
// }
//
//// private HashDigest handleContractEvent(LedgerEditor ldgEdt,BlockchainKeyPair userKP,
//// BlockchainKeyPair gatewayKey,BlockchainKeyPair contractKey) {
//// // 记录交易,注册用户;
//// LedgerTransactionContext txCtx = ldgEdt.newTransaction(
//// this.genContractReq(ledgerHash,sponsorKey,gatewayKey,contractKey));
//// LedgerDataSet ldgDS = txCtx.getDataSet();
////
//// //注册contract;
//// SignatureDigest signDigest = CryptoUtils.sign(CryptoAlgorithm.ED25519).sign(contractKey.getPrivKey(), Base58Utils.decode(contractKey.getAddress()));
//// DigitalSignatureBlob dgtSign = new DigitalSignatureBlob(contractKey.getPubKey(), signDigest);
//// ldgDS.getContractAccountSet().deploy(contractKey.getAddress(),contractKey.getPubKey(),dgtSign,this.getChainCodeBytes());
////
//// // 提交交易结果;
//// LedgerTransaction tx = txCtx.commit(TransactionState.SUCCESS);
////
//// // 生成区块;
//// LedgerBlock newBlock = ldgEdt.prepare();
//// ldgEdt.commit();
//// return newBlock.getHash();
//// }
//
// private byte[] getChainCodeBytes(){
// //构建合约的字节数组;
// byte[] contractCode= null;
// File file = null;
// InputStream input = null;
// try {
// String contractZipName = "AssetContract1.contract";
// URL url = Paths.get(ContractPath.getOutputPath() + contractZipName).toUri().toURL();
// file = new File(url.toURI());
// assertTrue("contract zip file is not exist.",file.exists()==true);
// input = new FileInputStream(file);
// //这种暴力的读取压缩包,在class解析时有问题,所有需要改进;
// contractCode = new byte[input.available()];
// input.read(contractCode);
// } catch (URISyntaxException e) {
// e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
// } finally {
// try {
// if(input!=null){
// input.close();
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// return contractCode;
// }
//
// private LedgerInitSetting createLedgerInitSetting() {
// CryptoConfig defCryptoSetting = new CryptoConfig();
// defCryptoSetting.setAutoVerifyHash(true);
// defCryptoSetting.setHashAlgorithm(CryptoAlgorithm.SHA256);
//
// LedgerInitSettingData initSetting = new LedgerInitSettingData();
//
// initSetting.setLedgerSeed(BytesUtils.toBytes("A Test Ledger seed!", "UTF-8"));
// initSetting.setCryptoSetting(defCryptoSetting);
// ConsensusParticipantData[] parties = new ConsensusParticipantData[4];
// parties[0] = new ConsensusParticipantData();
// parties[0].setId(0);
// parties[0].setName("John");
// CryptoKeyPair kp0 = CryptoUtils.sign(CryptoAlgorithm.ED25519).generateKeyPair();
// parties[0].setPubKey(kp0.getPubKey());
// parties[0].setHostAddress(new NetworkAddress("127.0.0.1", 9000));
//
// parties[1] = new ConsensusParticipantData();
// parties[1].setId(1);
// parties[1].setName("Mary");
// CryptoKeyPair kp1 = CryptoUtils.sign(CryptoAlgorithm.ED25519).generateKeyPair();
// parties[1].setPubKey(kp1.getPubKey());
// parties[1].setHostAddress(new NetworkAddress("127.0.0.1", 9010));
//
// parties[2] = new ConsensusParticipantData();
// parties[2].setId(2);
// parties[2].setName("Jerry");
// CryptoKeyPair kp2 = CryptoUtils.sign(CryptoAlgorithm.ED25519).generateKeyPair();
// parties[2].setPubKey(kp1.getPubKey());
// parties[2].setHostAddress(new NetworkAddress("127.0.0.1", 9020));
//
// parties[3] = new ConsensusParticipantData();
// parties[3].setId(3);
// parties[3].setName("Tom");
// CryptoKeyPair kp3 = CryptoUtils.sign(CryptoAlgorithm.ED25519).generateKeyPair();
// parties[3].setPubKey(kp1.getPubKey());
// parties[3].setHostAddress(new NetworkAddress("127.0.0.1", 9030));
//
// initSetting.setConsensusParticipants(parties);
//
// return initSetting;
// }
//}
package test.com.jd.blockchain.ledger;

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 org.junit.Test;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.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.TransactionContent;
import com.jd.blockchain.ledger.TransactionContentBody;
import com.jd.blockchain.ledger.TransactionRequest;
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.OperationHandleRegisteration;
import com.jd.blockchain.ledger.core.impl.TransactionBatchProcessor;
import com.jd.blockchain.storage.service.utils.MemoryKVStorage;

public class TransactionBatchProcessorTest {
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 HashDigest ledgerHash = null;

private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate();
private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate();
private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate();
private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate();

private TransactionRequest transactionRequest;

// 采用基于内存的 Storage;
private MemoryKVStorage storage = new MemoryKVStorage();

@Test
public void testTxReqProcess() {
// 初始化账本到指定的存储库;
ledgerHash = initLedger(storage, parti0, parti1, parti2, parti3);

// 加载账本;
LedgerManager ledgerManager = new LedgerManager();
LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage);

// 验证参与方账户的存在;
LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock());
UserAccount user0 = previousBlockDataset.getUserAccountSet().getUser(parti0.getAddress());
assertNotNull(user0);
boolean partiRegistered = previousBlockDataset.getUserAccountSet().contains(parti0.getAddress());
assertTrue(partiRegistered);

// 生成新区块;
LedgerEditor newBlockEditor = ledgerRepo.createNextBlock();

OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration();
TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset,
opReg, ledgerManager);

// 注册新用户;
BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate();
transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair, parti0);
txbatchProcessor.schedule(transactionRequest);

LedgerBlock newBlock = newBlockEditor.prepare();
newBlockEditor.commit();

// 验证正确性;
ledgerManager = new LedgerManager();
ledgerRepo = ledgerManager.register(ledgerHash, storage);

LedgerBlock latestBlock = ledgerRepo.getLatestBlock();
assertEquals(newBlock.getHash(), latestBlock.getHash());
assertEquals(1, newBlock.getHeight());
}

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

}

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

@@ -1,5 +1,6 @@
package test.com.jd.blockchain.ledger;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -10,10 +11,13 @@ import java.util.Random;

import org.junit.Test;

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.BytesDataList;
import com.jd.blockchain.ledger.BytesValueList;
import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.CryptoSetting;
@@ -67,8 +71,8 @@ public class TransactionSetTest {
BlockchainKeypair dataKey = BlockchainKeyGenerator.getInstance().generate();
DataAccountRegisterOperation dataAccRegOp = txBuilder.dataAccounts().register(dataKey.getIdentity());

DataAccountKVSetOperation kvsetOP = txBuilder.dataAccount(dataKey.getAddress())
.setText("A", "Value_A_0", -1).setText("B", "Value_B_0", -1).getOperation();
DataAccountKVSetOperation kvsetOP = txBuilder.dataAccount(dataKey.getAddress()).setText("A", "Value_A_0", -1)
.setText("B", "Value_B_0", -1).getOperation();

byte[] chainCode = new byte[128];
rand.nextBytes(chainCode);
@@ -76,7 +80,7 @@ public class TransactionSetTest {
ContractCodeDeployOperation contractDplOP = txBuilder.contracts().deploy(contractKey.getIdentity(), chainCode);

ContractEventSendOperation contractEvtSendOP = txBuilder.contractEvents().send(contractKey.getAddress(), "test",
"TestContractArgs".getBytes());
BytesDataList.singleText("TestContractArgs"));

TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();

@@ -98,7 +102,8 @@ public class TransactionSetTest {
txSnapshot.setContractAccountSetHash(contractAccountSetHash);

long blockHeight = 8922L;
LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot);
LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot,
null);
txset.add(tx);

assertTrue(txset.isUpdated());
@@ -172,7 +177,8 @@ public class TransactionSetTest {
for (int i = 0; i < acutualKVWriteSet.length; i++) {
assertEquals(expKVWriteSet[i].getKey(), acutualKVWriteSet[i].getKey());
assertEquals(expKVWriteSet[i].getExpectedVersion(), acutualKVWriteSet[i].getExpectedVersion());
assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getValue().toBytes(), acutualKVWriteSet[i].getValue().getValue().toBytes()));
assertTrue(BytesUtils.equals(expKVWriteSet[i].getValue().getValue().toBytes(),
acutualKVWriteSet[i].getValue().getValue().toBytes()));
}

ContractCodeDeployOperation actualContractDplOp = (ContractCodeDeployOperation) actualOperations[3];
@@ -184,8 +190,14 @@ public class TransactionSetTest {
assertEquals(contractEvtSendOP.getContractAddress(), actualContractEvtSendOp.getContractAddress());
assertEquals(contractEvtSendOP.getEvent(), actualContractEvtSendOp.getEvent());
assertEquals("test", actualContractEvtSendOp.getEvent());
assertTrue(BytesUtils.equals(contractEvtSendOP.getArgs(), actualContractEvtSendOp.getArgs()));
assertTrue(BytesUtils.equals("TestContractArgs".getBytes(), actualContractEvtSendOp.getArgs()));

byte[] expectedBytes = BinaryProtocol.encode(contractEvtSendOP.getArgs(), BytesValueList.class);
byte[] actualBytes = BinaryProtocol.encode(actualContractEvtSendOp.getArgs(), BytesValueList.class);
assertArrayEquals(expectedBytes, actualBytes);
expectedBytes = BinaryProtocol.encode(BytesDataList.singleText("TestContractArgs"), BytesValueList.class);
actualBytes = BinaryProtocol.encode(actualContractEvtSendOp.getArgs(), BytesValueList.class);
assertArrayEquals(expectedBytes, actualBytes);
}

}

+ 0
- 1
source/ledger/ledger-model/pom.xml View File

@@ -39,7 +39,6 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

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

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

/**
* 合约实现 {@link ContractAware} 的子接口可以监听运行时的生命周期事件;
*
* @author huanghaiquan
*
*/
public interface ContractAware {
}

+ 4
- 3
source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractEventContext.java View File

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

/**
* 账本操作上下文;


+ 8
- 7
source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractException.java View File

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

source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractAppLifecycleAwire.java → source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractLifecycleAware.java View File

@@ -7,7 +7,7 @@ package com.jd.blockchain.contract;
* @author huanghaiquan
*
*/
public interface ContractAppLifecycleAwire extends ContractRuntimeAwire {
public interface ContractLifecycleAware extends ContractAware {
void postConstruct();

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

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

/**
* 合约实现 {@link ContractRuntimeAwire} 的子接口可以监听运行时的生命周期事件;
*
* @author huanghaiquan
*
*/
public interface ContractRuntimeAwire {
}

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

@@ -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<Integer, Class<?>> DATA_CONTRACT_MAP = new HashMap<>();
public static final Integer[] PRIMITIVE_DATA_CODES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32,
DataCodes.CONTRACT_INT64, DataCodes.CONTRACT_BIG_INT,DataCodes.CONTRACT_TEXT, DataCodes.CONTRACT_BINARY };

/**
* serialize the Object[] by List<DataContract> list;
* @param objArr
* @param dataContractList
* @return
*/
public static byte[] serializeMethodParam(Object[] objArr,List<DataContract> dataContractList) {
byte[][] result = new byte[objArr.length][];
//将method中形参转换为实体对象,每个形参都必须为@DataContract类型;每个形参使用系统的BinaryProtocol来进行序列化,如果有5个参数,则使用5次序列化;
int sum = 0;

for(int i=0;i<objArr.length;i++){
DataContract dataContract = dataContractList.get(i);
objArr[i] = regenObj(dataContract,objArr[i]);
//get data interface;
result[i] = BinaryProtocol.encode(objArr[i],getDataIntf().get(dataContract.code()));
sum += result[i].length;
}
/**
* return byte[] format:
return is byte[], but now is byte[][], so we should reduct dimension by adding the header info to the rtnBytes[];
rtnBytes[]=classTypes.length/first length/second length/third length/result[0]/result[1]/result[2];
rtnBytes[0]: 4 bytes(classTypes.length);
rtnBytes[1]: 4 bytes(1 param's length);
rtnBytes[2]: 4 bytes(2 param's length);
rtnBytes[3]: 4 bytes(3 param's length);
rtnBytes[...]: result[0][] bytes(1 param's length);
rtnBytes[...]: result[1][] bytes(2 param's length);
rtnBytes[...]: result[2][] bytes(3 param's length);
*/
int bodyFirstPosition = 4 + 4 * (objArr.length);
ByteBuffer byteBuffer = ByteBuffer.allocate(bodyFirstPosition + sum);
byteBuffer.putInt(objArr.length);
for(int j=0; j<result.length; j++) {
byte[] curResult = result[j];
byteBuffer.putInt(curResult.length);
}
for(int k=0; k<result.length; k++){
byteBuffer.put(result[k]);
}
return byteBuffer.array();
}

/**
* deserialize the params bytes[];
* params format: nums|first length| second length| third length| ... |bytes[0]| byte[1] | bytes[2]| ...
* @param params
* @param dataContractList
* @return
*/
public static Object[] deserializeMethodParam(byte[] params, List<DataContract> dataContractList) {
Object result[] = new Object[dataContractList.size()];
ByteBuffer byteBuffer = ByteBuffer.allocate(params.length);
byteBuffer.put(params);
int paramNums = byteBuffer.getInt(0);

if(paramNums != dataContractList.size()){
throw new IllegalArgumentException("deserialize Method param. params'length in byte[] != method's param length");
}

int offsetPosition = (1 + dataContractList.size())*4; //start position of real data;
for(int i=0; i<dataContractList.size(); i++){
DataContract dataContract = dataContractList.get(i);
int curParamLength = byteBuffer.getInt((i+1)*4);
ByteBuffer byteBuffer1 = ByteBuffer.allocate(curParamLength);
byteBuffer1.put(params,offsetPosition,curParamLength);
offsetPosition += curParamLength;
//if dataContract=primitive type(byte/short/int/long/String),only use its getValues();
Object object = BinaryProtocol.decodeAs(byteBuffer1.array(),
getDataIntf().get(dataContract.code()));
if(isPrimitiveType(dataContract.code())){
Class<?> classObj = getDataIntf().get(dataContract.code());
try {
result[i] = ReflectionUtils.invokeMethod(classObj.getMethod("getValue"),object);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("no getValue(). detail="+e.getMessage());
}
}else {
result[i] = object;
}
byteBuffer1.clear();
}

return result;
}


/**
* the param types that we can support;
* @param <T>
* @return
*/
public static <T> Map<Integer, Class<?> > getDataIntf(){
DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT8, CONTRACT_INT8.class);
DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT16, CONTRACT_INT16.class);
DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT32, CONTRACT_INT32.class);
DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_INT64, CONTRACT_INT64.class);
DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_TEXT, CONTRACT_TEXT.class);
DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BINARY, CONTRACT_BINARY.class);
DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIG_INT, CONTRACT_BIG_INT.class);
DATA_CONTRACT_MAP.put(DataCodes.CONTRACT_BIZ_CONTENT, ContractBizContent.class);
return DATA_CONTRACT_MAP;
}

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

private static Object regenObj(DataContract dataContract, Object object){
if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT8.class)){

return (CONTRACT_INT8) () -> Byte.parseByte(object.toString());
}else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT16.class)){
return (CONTRACT_INT16) () -> Short.parseShort(object.toString());
}else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT32.class)){
return (CONTRACT_INT32) () -> Integer.parseInt(object.toString());
}else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_INT64.class)){
return (CONTRACT_INT64) () -> Long.parseLong(object.toString());
}else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_TEXT.class)){
return (CONTRACT_TEXT) () -> object.toString();
}else if(getDataIntf().get(dataContract.code()).equals(CONTRACT_BINARY.class)){
return (CONTRACT_BINARY) () -> (Bytes) object;
}else if(getDataIntf().get(dataContract.code()).equals(ContractBizContent.class)){
ContractBizContent contractBizContent = (ContractBizContent)object;
return contractBizContent;
}else {
throw new IllegalDataException("cann't get new Object by dataContract and object.");
}
}

/**
* get contractType(contain @DataContract) by primitive class type;
* some class type can be supported default (byte/char/int/long/String/Bytes, and so on).
* in other words, need not contain the @DataContract in its class for contract param's serialization or deserialization.
* @param classType
* @return
*/
private static Class<?> getContractTypeByPrimitiveType(Class<?> classType) {
if(classType.equals(byte.class) || classType.equals(Byte.class)){
return CONTRACT_INT8.class;
}else if(classType.equals(char.class) || classType.equals(Character.class)){
return CONTRACT_INT16.class;
}else if(classType.equals(int.class) || classType.equals(Integer.class)){
return CONTRACT_INT32.class;
}else if(classType.equals(long.class) || classType.equals(Long.class)){
return CONTRACT_INT64.class;
}else if(classType.equals(String.class)){
return CONTRACT_TEXT.class;
}else if(classType.equals(Bytes.class)){
return CONTRACT_BINARY.class;
}else {
throw new IllegalDataException(String.format("no support the classType=%s, please check @DataContract.",classType.toString()));
}
}

public static DataContract parseDataContract(Class<?> classType){
DataContract dataContract = classType.getAnnotation(DataContract.class);
//if the param's class Type don't contain @DataContract, then check parameterAnnotations of this method.
if(dataContract == null){
boolean canPass = false;
//if parameterAnnotations don't contain @DataContract, is it primitive type?
Class<?> contractType = getContractTypeByPrimitiveType(classType);
dataContract = contractType.getAnnotation(DataContract.class);
}
if(!getDataIntf().containsKey(dataContract.code())){
throw new IllegalArgumentException(String.format(
"for now, this @dataContract(code=%s) is forbidden in the param list.",dataContract.code()));
}
return dataContract;
}
}
//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<?>, 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<byte[]> 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;
// }
// }
//}

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

@@ -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<String, Method> events = new HashMap<>();

private Map<Method, String> handleMethods = new HashMap<>();

public String getName() {
return name;
}

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

/**
* 返回指定方法声明的事件;<br>
*
* 如果不存在,则返回 null;
*
* @param method
* @return
*/
public String getEvent(Method method) {
return handleMethods.get(method);
}

/**
* 返回事件的处理方法;<br>
*
* 如果不存在,则返回 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
+ '}';
}
}

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

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



source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAwire.java → source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventProcessingAware.java View File

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

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

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

private static final long MAX_SECONDS = 30;

private CompletableFuture<T> 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());
}
}
}

+ 4
- 11
source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/LocalContractEventContext.java View File

@@ -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<BlockchainIdentity> txSigners;
private Set<BlockchainIdentity> contractOwners;
private LedgerContext ledgerContext;

public LocalContractEventContext(HashDigest ledgeHash, String event){
this.ledgeHash = ledgeHash;
this.event = event;
// this.chainCode = chainCode;
}

@Override
@@ -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<BlockchainIdentity> 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;
}


source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueEntry.java → source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesData.java View File

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


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

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

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

@@ -21,7 +21,7 @@ public interface BytesValue {
* @return
*/
@DataField(order = 0, refEnum = true)
BytesValueType getType();
DataType getType();

/**
* 数据值的二进制序列;


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

@@ -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<Class<?>, BytesValueResolver> CLASS_RESOLVER_MAP = new ConcurrentHashMap<>();

private static final Map<DataType, BytesValueResolver> 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<BytesValue> 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);
}
}
}

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

+ 4
- 10
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java View File

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

}

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

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

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

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


source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueType.java → source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java View File

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

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

@@ -25,7 +25,7 @@ public interface KVDataEntry {
*
* @return
*/
BytesValueType getType();
DataType getType();
/**
* 值;


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

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

// // ----------------


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

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


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

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


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

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

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

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

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

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

/**
* 生成交易请求;
* 提交交易请求到共识节点;<br>
*
* 这是同步方法,将阻塞当前线程,直到交易处理完成并返回结果之后,此方法才返回给调用者;
*
*/
TransactionResponse commit();

}

+ 11
- 5
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java View File

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

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

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

+ 8
- 8
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java View File

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

+ 3
- 1
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionTemplate.java View File

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


+ 54
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/AbstractBytesValueResolver.java View File

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

+ 58
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/resolver/BytesToBytesValueResolver.java View File

@@ -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<Class<?>> 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;
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save