Browse Source

Merge commit '713f8471650bee6cd2400585e517dc85197e43f0' into feature/contract_invocation

# Conflicts:
#	source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java
#	source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java
#	source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java
#	source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java
#	source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java
#	source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java
tags/1.0.0
huanghaiquan 5 years ago
parent
commit
22c4a6e825
56 changed files with 1149 additions and 314 deletions
  1. +22
    -0
      source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
  2. +3
    -0
      source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java
  3. +0
    -1
      source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContract2.java
  4. +0
    -1
      source/contract/contract-maven-plugin/src/test/resources/project-to-test/AssetContractImpl2.java
  5. +2
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java
  6. +5
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContractImpl.java
  7. +4
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java
  8. +1
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java
  9. +27
    -11
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java
  10. +25
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java
  11. +5
    -5
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java
  12. +26
    -5
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java
  13. +38
    -29
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java
  14. +12
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java
  15. +10
    -4
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java
  16. +8
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java
  17. +14
    -0
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java
  18. +15
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java
  19. +1
    -1
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
  20. +157
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java
  21. +195
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils2.java
  22. +39
    -27
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java
  23. +39
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/EventResult.java
  24. +13
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_BYTES.java
  25. +13
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_INT.java
  26. +13
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_LONG.java
  27. +13
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_SHORT.java
  28. +13
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/param/WRAP_STRING.java
  29. +0
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java
  30. +5
    -6
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java
  31. +25
    -16
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java
  32. +1
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Transaction.java
  33. +5
    -5
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRespHandle.java
  34. +2
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionResponse.java
  35. +0
    -17
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionReturnMessage.java
  36. +0
    -26
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionReturnMessageData.java
  37. +22
    -7
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java
  38. +6
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java
  39. +40
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java
  40. +13
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java
  41. +21
    -21
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java
  42. +41
    -18
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java
  43. +29
    -19
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java
  44. +8
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java
  45. +26
    -6
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java
  46. +11
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java
  47. +14
    -5
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxResponseMessage.java
  48. +18
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java
  49. +2
    -2
      source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java
  50. +93
    -14
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java
  51. +4
    -28
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java
  52. +1
    -1
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java
  53. +2
    -1
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java
  54. +32
    -15
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java
  55. +11
    -3
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java
  56. +4
    -2
      source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java

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

@@ -51,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,6 +83,26 @@ public interface DataCodes {

public static final int DATA = 0x900;

//contract related;
public static final int CONTRACT = 0xA00;
public static final int CONTRACT_BYTE = 0xA01;

public static final int CONTRACT_SHORT = 0xA02;

public static final int CONTRACT_INT = 0xA03;

public static final int CONTRACT_LONG = 0xA04;

public static final int CONTRACT_STRING = 0xA05;

public static final int CONTRACT_BYTES = 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;

public static final int CONTRACT_RETURN = 0xA22;

public static final int HASH = 0xB00;


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

@@ -3,6 +3,9 @@ package com.jd.blockchain.contract.engine;
import com.jd.blockchain.contract.ContractEventContext;
import com.jd.blockchain.utils.Bytes;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

public interface ContractCode {

Bytes getAddress();


+ 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
- 0
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ReadContract.java View File

@@ -9,5 +9,7 @@ public interface ReadContract {

@ContractEvent(name = "version-key")
Long readVersion(String address, String key);

int test();
}


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

@@ -42,4 +42,9 @@ public class ReadContractImpl implements EventProcessingAware, ReadContract {
}
return -1L;
}

@Override
public int test() {
return 0;
}
}

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


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

@@ -57,7 +57,7 @@ public class DataAccount implements AccountHeader, MerkleProvable {
BytesValue bytesValue = BytesValueEntry.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
- 11
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java View File

@@ -1,10 +1,8 @@
package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.TransactionReturnMessage;
import com.jd.blockchain.ledger.TransactionState;
import com.jd.blockchain.ledger.OperationResult;
import com.jd.blockchain.ledger.LedgerTransaction;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.*;

import java.util.List;

/**
* 事务上下文;
@@ -28,27 +26,45 @@ public interface LedgerTransactionContext {
*/
TransactionRequest getRequestTX();

/**
* 提交对账本数据的修改,以指定的交易状态提交交易;
*
* @param txResult
*
* @return
*/
LedgerTransaction commit(TransactionState txResult);

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

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

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


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

@@ -2,6 +2,8 @@ package com.jd.blockchain.ledger.core;

import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.core.impl.OperationHandleContext;
import com.jd.blockchain.utils.concurrent.AsyncFuture;


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 操作执行结果
*/
byte[] 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);
}

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

@@ -276,15 +276,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);
}
}


+ 26
- 5
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;
@@ -348,9 +349,14 @@ public class LedgerTransactionalEditor implements LedgerEditor {
public TransactionRequest getRequestTX() {
return txRequest;
}

@Override
public LedgerTransaction commit(TransactionState txResult) {
return commit(txResult, null);
}

@Override
public LedgerTransaction commit(TransactionState txResult, OperationResult... opResults) {
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, opResults);

LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null, operationResultArray(operationResults));
this.txset.add(tx);
// this.txset.commit();

@@ -374,9 +381,14 @@ public class LedgerTransactionalEditor implements LedgerEditor {
committed = true;
return tx;
}
@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) {


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

@@ -50,9 +50,12 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
private TransactionBatchResult batchResult;

/**
* @param newBlockEditor 新区块的数据编辑器;
* @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集;
* @param opHandles 操作处理对象注册表;
* @param newBlockEditor
* 新区块的数据编辑器;
* @param previousBlockDataset
* 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集;
* @param opHandles
* 操作处理对象注册表;
*/
public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataSet previousBlockDataset,
OperationHandleRegisteration opHandles, LedgerService ledgerService) {
@@ -73,9 +76,12 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
public TransactionResponse schedule(TransactionRequest request) {
// 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上;
LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request);
TransactionState txResult;
OperationResult[] opResults = null;
TransactionState result;

List<OperationResult> operationResults = new ArrayList<>();

try {

LedgerDataSet dataset = txCtx.getDataSet();
TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request);
// TODO: 验证签名者的有效性;
@@ -95,44 +101,44 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
OperationHandleContext handleContext = new OperationHandleContext() {
@Override
public void handle(Operation operation) {
// assert; Instance of operation are one of User related operations or
// DataAccount related operations;
//assert; Instance of operation are one of User related operations or DataAccount related operations;
OperationHandle hdl = opHandles.getHandle(operation.getClass());
hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService);
}
};
OperationHandle opHandle;
int contractOpIndex = 0;
List<OperationResult> opResultList = new ArrayList<OperationResult>();
int opIdx = 0;
int opIndex = 0;
for (Operation op : ops) {
opHandle = opHandles.getHandle(op.getClass());
byte[] retn = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService);
if (op instanceof ContractEventSendOperation) {
// 支持返回值的操作;
opResultList.add(new OperationResultData(opIdx, retn));
byte[] opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService);
if (opResult != null) {
operationResults.add(new OperationResultData(opIndex, opResult));
}

opIdx++;
opIndex++;
}

// 提交交易(事务);
txResult = TransactionState.SUCCESS;
opResults = opResultList.toArray(new OperationResult[opResultList.size()]);
txCtx.commit(txResult, opResults);
result = TransactionState.SUCCESS;
txCtx.commit(result, operationResults);
} catch (LedgerException e) {
// TODO: 识别更详细的异常类型以及执行对应的处理;
txResult = TransactionState.LEDGER_ERROR;
txCtx.discardAndCommit(TransactionState.LEDGER_ERROR);
result = 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) {
txResult = TransactionState.SYSTEM_ERROR;
txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR);
result = 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, txResult, opResults);
TxResponseHandle resp = new TxResponseHandle(request, result);

if (!operationResults.isEmpty()) {
OperationResult[] operationResultArray = new OperationResult[operationResults.size()];
resp.setOperationResults(operationResults.toArray(operationResultArray));
}

responseList.add(resp);

@@ -213,12 +219,11 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {

private TransactionState result;

private OperationResult[] opResults;
private OperationResult[] operationResults;

public TxResponseHandle(TransactionRequest request, TransactionState result, OperationResult... opResults) {
public TxResponseHandle(TransactionRequest request, TransactionState result) {
this.request = request;
this.result = result;
this.opResults = opResults;
}

@Override
@@ -247,8 +252,12 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
}

@Override
public OperationResult[] getContractReturn() {
return opResults;
public OperationResult[] getOperationResults() {
return operationResults;
}

public void setOperationResults(OperationResult[] operationResults) {
this.operationResults = operationResults;
}
}



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

@@ -1,5 +1,6 @@
package com.jd.blockchain.ledger.core.impl.handles;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.core.LedgerDataSet;
@@ -8,8 +9,12 @@ 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 com.jd.blockchain.utils.concurrent.AsyncFuture;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;

@Service
public class ContractCodeDeployOperationHandle implements OperationHandle {

@@ -20,12 +25,18 @@ public class ContractCodeDeployOperationHandle implements OperationHandle {
// TODO: 校验合约代码的正确性;
// TODO: 请求者应该提供合约账户的公钥签名,已确定注册的地址的唯一性;

dataset.getContractAccountSet().deploy(contractOP.getContractID().getAddress(),
contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode());
//No result;
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
- 4
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java View File

@@ -1,5 +1,7 @@
package com.jd.blockchain.ledger.core.impl.handles;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.utils.concurrent.AsyncFuture;
import org.springframework.stereotype.Service;

import com.jd.blockchain.binaryproto.DataContractRegistry;
@@ -26,15 +28,19 @@ public class DataAccountKVSetOperationHandle implements OperationHandle {
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());
}

// No return value;
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);


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

@@ -9,6 +9,7 @@ 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.concurrent.AsyncFuture;
import org.springframework.stereotype.Service;

@Service
@@ -20,15 +21,19 @@ public class DataAccountRegisterOperationHandle implements OperationHandle {
DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op;
BlockchainIdentity bid = dataAccountRegOp.getAccountID();

// TODO: 校验用户身份;
//TODO: 校验用户身份;

// TODO: 请求者应该提供数据账户的公钥签名,已确定注册的地址的唯一性;
//TODO: 请求者应该提供数据账户的公钥签名,已确定注册的地址的唯一性;
dataset.getDataAccountSet().register(bid.getAddress(), bid.getPubKey(), null);

// No return value;
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);


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

@@ -5,7 +5,13 @@ 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 {

@@ -26,4 +32,12 @@ public class JVMContractEventSendOperationHandle extends AbtractContractEventHan
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;
// }

}

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

@@ -8,20 +8,32 @@ 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 com.jd.blockchain.utils.concurrent.AsyncFuture;


public class UserRegisterOperationHandle implements OperationHandle {

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

// No return value;
return null;
Bytes userAddress = bid.getAddress();

dataset.getUserAccountSet().register(userAddress, bid.getPubKey());

return userAddress.toBytes();
}

// @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 UserRegisterOperation.class.isAssignableFrom(operationType);


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

@@ -116,7 +116,7 @@ public class ContractInvokingTest {

TransactionResponse resp = txbatchProcessor.schedule(txReq);
verify(contractInstance, times(1)).issue(asset, issueAmount);
OperationResult[] opResults = resp.getContractReturn();
OperationResult[] opResults = resp.getOperationResults();
assertEquals(1, opResults.length);
assertEquals(0, opResults[0].getIndex());



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

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

import com.jd.blockchain.binaryproto.*;
import com.jd.blockchain.contract.param.*;
import com.jd.blockchain.utils.io.BytesUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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 byte[] 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 byte[] 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(byte[] 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;
}
}
}

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

@@ -0,0 +1,195 @@
//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_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;
// }
//}

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

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

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.utils.IllegalDataException;

public class ContractType {
@@ -68,45 +66,59 @@ public class ContractType {
* @param delaredInterface 声明合约的接口类型;
* @return
*/
public static ContractType resolve(Class<?> delaredInterface) {
ContractType contractType = new ContractType();
public static ContractType resolve(Class<?> contractIntf) {

// 接口上必须有注解
if (!contractIntf.isAnnotationPresent(Contract.class)) {
throw new IllegalDataException("It is not a Contract Type, because there is not @Contract !");
}

Annotation annotation = delaredInterface.getDeclaredAnnotation(Contract.class);
Method[] classMethods = contractIntf.getDeclaredMethods();

// contains: @Contract?
boolean isContractType = annotation != null ? true : false;
if (!isContractType) {
throw new IllegalDataException("The specified type is not annotated by @Contract!");
if (classMethods.length == 0) {
throw new IllegalDataException("This interface have not any methods !");
}

// contractIntf contains @Contract and @ContractEvent;
Method[] classMethods = delaredInterface.getDeclaredMethods();
ContractType contractType = new ContractType();
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_)) {
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.
//check param's type is fit for need.
Class<?>[] paramTypes = method.getParameterTypes();
List dataContractList = new ArrayList();
for (Class<?> curParamType : paramTypes) {
throw new IllegalStateException("Not implemented!");
// DataContract dataContract = ContractSerializeUtils.parseDataContract(curParamType);
// dataContractList.add(dataContract);
for(Class<?> currParamType : paramTypes) {
if (!ContractSerializeUtils.support(currParamType)) {
throw new IllegalStateException(String.format("Param Type = %s can not support !!!", currParamType.getName()));
}
}

// 判断返回值是否可序列化
Class<?> returnType = method.getReturnType();
if (!ContractSerializeUtils.support(returnType)) {
throw new IllegalStateException(String.format("Return Type = %s can not support !!!", returnType.getName()));
}
// if(dataContractList.size()>0){
// contractType.dataContractMap.put(method,dataContractList);
// }

contractType.events.put(eventName_, method);
contractType.handleMethods.put(method, eventName_);
contractType.events.put(eventName, method);
contractType.handleMethods.put(method, eventName);
}
}
return contractType;
}

@Override
public String toString() {
return "ContractType{" +
"name='" + name + '\'' +
", events=" + events +
", handleMethods=" + handleMethods +
'}';
}
}

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

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

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

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_BYTES)
public interface WRAP_BYTES {

@DataField(order = 1, primitiveType = PrimitiveType.BYTES)
byte[] getValue();
}

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

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

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_INT)
public interface WRAP_INT {

@DataField(order = 1, primitiveType = PrimitiveType.INT32)
int getValue();
}

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

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

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_LONG)
public interface WRAP_LONG {

@DataField(order = 1, primitiveType = PrimitiveType.INT64)
long getValue();
}

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

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

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_SHORT)
public interface WRAP_SHORT {

@DataField(order = 1, primitiveType = PrimitiveType.INT16)
short getValue();
}

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

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

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_STRING)
public interface WRAP_STRING {

@DataField(order = 1, primitiveType = PrimitiveType.TEXT)
String getValue();
}

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

@@ -44,5 +44,4 @@ public interface ContractEventSendOperation extends Operation {
*/
@DataField(order = 5, primitiveType = PrimitiveType.INT64)
long getTxOpTime();

}

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

@@ -5,13 +5,12 @@ import com.jd.blockchain.binaryproto.DataField;
import com.jd.blockchain.binaryproto.PrimitiveType;
import com.jd.blockchain.consts.DataCodes;

@DataContract(code = DataCodes.CONTRACT_RETURN)
@DataContract(code = DataCodes.TX_OP_RESULT)
public interface OperationResult {

@DataField(order = 1, primitiveType = PrimitiveType.INT32)
int getIndex();

@DataField(order = 2, primitiveType = PrimitiveType.BYTES)
byte[] getResult();
@DataField(order=1, primitiveType = PrimitiveType.INT32)
int getIndex();

@DataField(order=2, primitiveType = PrimitiveType.BYTES)
byte[] getResult();
}

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

@@ -1,26 +1,35 @@
package com.jd.blockchain.ledger;


public class OperationResultData implements OperationResult {

private int index;
private int index;

private byte[] result;

public OperationResultData() {
}

private byte[] result;
public OperationResultData(int index, byte[] result) {
this.index = index;
this.result = result;
}

public OperationResultData() {
}
@Override
public int getIndex() {
return index;
}

public OperationResultData(int operationIndex, byte[] result) {
this.index = operationIndex;
this.result = result;
}
@Override
public byte[] getResult() {
return result;
}

@Override
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}

@Override
public byte[] getResult() {
return result;
}
public void setResult(byte[] result) {
this.result = result;
}
}

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

@@ -49,6 +49,6 @@ public interface Transaction extends NodeRequest, HashObject {
*
* @return
*/
@DataField(order = 4, refContract = true, list = true)
@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 OperationResult[] 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(OperationResult[] 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 OperationResult[] getContractReturn() {
return contractReturn;
public OperationResult[] getOperationResults() {
return operationResults;
}
}

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

@@ -63,6 +63,6 @@ public interface TransactionResponse {
*
* @return
*/
@DataField(order = 6, list = true, refContract = true)
OperationResult[] getContractReturn();
@DataField(order=6, list=true, refContract = true)
OperationResult[] getOperationResults();
}

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

@@ -1,17 +0,0 @@
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.TX_RETURN_MESSAGE)
public interface TransactionReturnMessage {

/**
* 合约返回值列表
*
* @return
*/
@DataField(order=1, list = true, refContract=true)
OperationResult[] getContractReturn();
}

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

@@ -1,26 +0,0 @@
package com.jd.blockchain.ledger;

import java.util.ArrayList;
import java.util.List;

public class TransactionReturnMessageData implements TransactionReturnMessage {

private List<OperationResult> contractReturnMessages = new ArrayList<>();

public void addContractReturnMessage(OperationResult contractReturnMessage) {
contractReturnMessages.add(contractReturnMessage);
}

public boolean isContractReturnEmpty() {
return contractReturnMessages.isEmpty();
}

@Override
public OperationResult[] getContractReturn() {
if (isContractReturnEmpty()) {
return null;
}
OperationResult[] crms = new OperationResult[contractReturnMessages.size()];
return contractReturnMessages.toArray(crms);
}
}

+ 22
- 7
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java View File

@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.ContractEventSendOperation;
@@ -29,7 +30,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
private static final ContractCodeDeployOperationBuilderImpl CONTRACT_CODE_DEPLOY_OP_BUILDER = new ContractCodeDeployOperationBuilderImpl();
private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl();
// private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl();
private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter();
@@ -89,6 +90,11 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder);
}
@Override
public <T> EventResult<T> result(ContractEventExecutor execute) {
return contractInvoProxyBuilder.execute(execute);
}
public Collection<Operation> getOperations() {
// TODO: 合并操作列表中可能的重复操作;
return operationList;
@@ -130,7 +136,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
operationList.add(op);
return op;
}
}
private class DataAccountKVSetOperationBuilderFilter implements DataAccountKVSetOperationBuilder {
@@ -235,25 +240,35 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
operationList.add(op);
return op;
}
}
private class ContractEventSendOperationBuilderFilter implements ContractEventSendOperationBuilder {
@Override
public ContractEventSendOperation send(String address, String event, byte[] args) {
ContractEventSendOperation op = CONTRACT_EVENT_SEND_OP_BUILDER.send(address, event, args);
operationList.add(op);
return op;
return send(Bytes.fromBase58(address), event, args);
}
@Override
public ContractEventSendOperation send(Bytes address, String event, byte[] args) {
ContractEventSendOperation op = CONTRACT_EVENT_SEND_OP_BUILDER.send(address, event, args);
int opIndex = operationList.size();
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args, opIndex);
operationList.add(op);
return op;
}
@Override
public ContractEventSendOperation send(String address) {
return send(Bytes.fromBase58(address));
}
@Override
public ContractEventSendOperation send(Bytes address) {
int opIndex = operationList.size();
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, opIndex);
operationList.add(op);
return op;
}
}
}

+ 6
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventExecutor.java View File

@@ -0,0 +1,6 @@
package com.jd.blockchain.transaction;

public interface ContractEventExecutor<T> {

T execute();
}

+ 40
- 0
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java View File

@@ -5,6 +5,7 @@ import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.utils.Bytes;

public class ContractEventSendOpTemplate implements ContractEventSendOperation {

static {
DataContractRegistry.register(ContractEventSendOperation.class);
}
@@ -14,17 +15,47 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation {
private String event;
//交易操作时间;
private long txOpTime;
// 所属操作Index
private int opIndex;

public ContractEventSendOpTemplate() {
}

public ContractEventSendOpTemplate(Bytes contractAddress) {
this(contractAddress, -1);
}

public ContractEventSendOpTemplate(Bytes contractAddress, int opIndex) {
this.contractAddress = contractAddress;
this.opIndex = opIndex;
this.txOpTime = System.currentTimeMillis();
}

public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args) {
this(contractAddress, event, args, -1);
}

public ContractEventSendOpTemplate(Bytes contractAddress, String event, byte[] args, int opIndex) {
this.contractAddress = contractAddress;
this.event = event;
this.args = args;
this.opIndex = opIndex;
this.txOpTime = System.currentTimeMillis();
}

public void setArgs(byte[] args) {
this.args = args;
}

public void setEvent(String event) {
this.event = event;
}

public void setEventAndArgs(String event, byte[] args) {
this.event = event;
this.args = args;
}

@Override
public Bytes getContractAddress() {
return contractAddress;
@@ -44,4 +75,13 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation {
public long getTxOpTime() {
return txOpTime;
}

/**
* 获取所属交易中的序号,该值不需要序列化
*
* @return
*/
public int getOpIndex() {
return opIndex;
}
}

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

@@ -23,4 +23,17 @@ public interface ContractEventSendOperationBuilder {
@Deprecated
ContractEventSendOperation send(Bytes address, String event, byte[] args);
/**
*
* @param address
* @return
*/
ContractEventSendOperation send(String address);
/**
*
* @param address
* @return
*/
ContractEventSendOperation send(Bytes address);
}

+ 21
- 21
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilderImpl.java View File

@@ -1,21 +1,21 @@
package com.jd.blockchain.transaction;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.utils.Bytes;
@Deprecated
class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder {
@Override
public ContractEventSendOperation send(String address, String event, byte[] args) {
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args);
return op;
}
@Override
public ContractEventSendOperation send(Bytes address, String event, byte[] args) {
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args);
return op;
}
}
//package com.jd.blockchain.transaction;
//
//import com.jd.blockchain.ledger.ContractEventSendOperation;
//import com.jd.blockchain.utils.Bytes;
//
//@Deprecated
//class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder {
//
// @Override
// public ContractEventSendOperation send(String address, String event, byte[] args) {
// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args);
// return op;
// }
//
// @Override
// public ContractEventSendOperation send(Bytes address, String event, byte[] args) {
// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args);
// return op;
// }
//
//}

+ 41
- 18
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java View File

@@ -3,7 +3,9 @@ package com.jd.blockchain.transaction;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.IllegalDataException;

@@ -11,45 +13,66 @@ public class ContractInvocationProxy implements InvocationHandler {

// private String contractMessage;

private Bytes contractAddress;
// private Bytes contractAddress;

private ContractType contractType;

private ContractEventSendOperationBuilder sendOpBuilder;
// private ContractEventSendOperationBuilder sendOpBuilder;

private ContractEventSendOperation sendOperation;

public ContractInvocationProxy(Bytes contractAddress, ContractType contractType,
ContractEventSendOperationBuilder sendOpBuilder) {
this.contractAddress = contractAddress;
// this.contractAddress = contractAddress;
if(contractType == null){
throw new IllegalDataException("contractType == null, no invoke really.");
}
this.contractType = contractType;
this.sendOpBuilder = sendOpBuilder;
// this.sendOpBuilder = sendOpBuilder;
// Send一个地址,但不涉及Event
this.sendOperation = sendOpBuilder.send(contractAddress);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 判断是否是常规方法调用
if (method.getName().equals("hashCode")) {
// 该处需要使用当前代理类的HashCode
return this.hashCode();
}
if (method.getName().equals("toString")) {
// 该处使用当前代理类的toString
return this.toString();
}

if (sendOperation.getEvent() != null) {
throw new IllegalStateException("Contract Object can only execute method one time !!!");
}

String event = contractType.getEvent(method);
if (event == null) {
// 适配 Object 对象的方法;
// toString 方法;
return String.format("[%s]-%s", contractAddress, contractType.toString());

// hashCode 方法;
// 该方法不是合约可执行的方法
throw new IllegalAccessException(String.format("This Method [%s] is not Contract Event Method !!!",
method.getName()));
}
// 合约方法;
byte[] argBytes = serializeArgs(args,method);
sendOpBuilder.send(contractAddress, event, argBytes);

// TODO: 暂时未考虑有返回值的情况;
byte[] argBytes = serializeArgs(args);
if (sendOperation instanceof ContractEventSendOpTemplate) {
((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes);
}
// 代理操作,返回值类型无法创建
return null;
}

private byte[] serializeArgs(Object[] args, Method method) {
if(args == null || args.length==0){
return null;
private byte[] serializeArgs(Object[] args) {
return ContractSerializeUtils.serializeArray(args);
}

public int opIndex() {
if (sendOperation instanceof ContractEventSendOpTemplate) {
return ((ContractEventSendOpTemplate) sendOperation).getOpIndex();
}
throw new IllegalStateException("Not implemented!");
//return ContractSerializeUtils.serializeMethodParam(args,contractType.getDataContractMap().get(method));
return -1;
}
}

+ 29
- 19
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java View File

@@ -1,18 +1,20 @@
package com.jd.blockchain.transaction;
import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.IllegalDataException;
public class ContractInvocationProxyBuilder {
private Map<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>();
private Map<Object, Integer> contractOperations = new ConcurrentHashMap<>();
public <T> T create(String address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) {
return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder);
}
@@ -23,10 +25,31 @@ public class ContractInvocationProxyBuilder {
ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType,
contractEventBuilder);
T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { contractIntf }, proxyHandler);
// 创建关联关系
contractOperations.put(proxy, proxyHandler.opIndex());
return proxy;
}
public <T> EventResult<T> execute(ContractEventExecutor execute) {
Object contractProxy = execute.execute();
if (contractProxy == null) {
// 该方法执行必须要有返回值
throw new IllegalStateException(
String.format("ContractEventExecutor [%s] 's return must be not empty !!!", execute.toString()));
}
if (!(contractProxy instanceof Proxy)) {
throw new IllegalDataException(
String.format("ContractEventExecutor [%s] 's return must from TxTemplate.contract()'s result !!!", execute.toString()));
}
return (T) proxy;
Integer opIndex = contractOperations.get(contractProxy);
if (opIndex != null && opIndex > -1) {
return new EventResult<>(opIndex);
}
return null;
}
private ContractType resolveContractType(Class<?> contractIntf) {
@@ -34,21 +57,8 @@ public class ContractInvocationProxyBuilder {
if (contractType != null) {
return contractType;
}
// TODO 检查返回值类型;
ContractType contractType1 = ContractType.resolve(contractIntf);
contractTypes.put(contractIntf,contractType1);
return contractType1;
}
/**
* is contractType really? identified by @Contract;
* @param contractIntf
* @return
*/
private boolean isContractType(Class<?> contractIntf) {
Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class);
return annotation != null ? true : false;
ContractType ct = ContractType.resolve(contractIntf);
contractTypes.put(contractIntf, ct);
return ct;
}
}

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

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

import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.utils.Bytes;

public interface EventOperator {
@@ -30,4 +31,11 @@ public interface EventOperator {
*/
<T> T contract(Bytes address, Class<T> contractIntf);

/**
* 执行合约异步等待应答结果
*
* @param execute
* @return
*/
<T> EventResult<T> result(ContractEventExecutor execute);
}

+ 26
- 6
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java View File

@@ -1,18 +1,17 @@
package com.jd.blockchain.transaction;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.SignatureDigest;
import com.jd.blockchain.crypto.SignatureFunction;
import com.jd.blockchain.ledger.DigitalSignature;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionRequestBuilder;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.*;

import java.util.Map;

public class PreparedTx implements PreparedTransaction {

@@ -20,9 +19,16 @@ public class PreparedTx implements PreparedTransaction {

private TransactionService txProcessor;

private Map<Integer, EventResult> eventResults;

public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor) {
this(txReqBuilder, txProcessor, null);
}

public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, Map<Integer, EventResult> eventResults) {
this.txReqBuilder = txReqBuilder;
this.txProcessor = txProcessor;
this.eventResults = eventResults;
}

@Override
@@ -56,6 +62,20 @@ public class PreparedTx implements PreparedTransaction {
TransactionRequest txReq = txReqBuilder.buildRequest();
// 发起交易请求;
TransactionResponse txResponse = txProcessor.process(txReq);
// 重新包装操作集合
OperationResult[] operationResults = txResponse.getOperationResults();
if (operationResults != null && operationResults.length > 0 &&
eventResults != null && !eventResults.isEmpty()) {
for (OperationResult operationResult : operationResults) {
int opIndex = operationResult.getIndex();
EventResult eventResult = eventResults.get(opIndex);
if (eventResult != null) {
eventResult.done(ContractSerializeUtils.resolve(operationResult.getResult()));
}
}
}
return txResponse;
}


}

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

@@ -2,6 +2,7 @@ package com.jd.blockchain.transaction;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.TransactionBuilder;
@@ -10,6 +11,9 @@ import com.jd.blockchain.ledger.TransactionContentBody;
import com.jd.blockchain.ledger.TransactionRequestBuilder;
import com.jd.blockchain.utils.Bytes;

import java.util.HashMap;
import java.util.Map;

public class TxBuilder implements TransactionBuilder {

static {
@@ -18,6 +22,8 @@ public class TxBuilder implements TransactionBuilder {

private BlockchainOperationFactory opFactory = new BlockchainOperationFactory();

private Map<Object, Integer> contractProxyMap = new HashMap<>();

private static final String DEFAULT_HASH_ALGORITHM = "SHA256";

private HashDigest ledgerHash;
@@ -88,6 +94,11 @@ public class TxBuilder implements TransactionBuilder {
return opFactory.contract(address, contractIntf);
}

@Override
public <T> EventResult<T> result(ContractEventExecutor execute) {
return opFactory.result(execute);
}

@Override
public <T> T contract(String address, Class<T> contractIntf) {
return opFactory.contract(address, contractIntf);


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

@@ -19,10 +19,19 @@ public class TxResponseMessage implements TransactionResponse {
private TransactionState executionState;
private OperationResult[] contractReturn;
private OperationResult[] operationResults;
public TxResponseMessage() {
}
// 重新包装operationResults
public TxResponseMessage(TransactionResponse transactionResponse, OperationResult[] operationResults) {
this.contentHash = transactionResponse.getContentHash();
this.blockHash = transactionResponse.getBlockHash();
this.blockHeight = transactionResponse.getBlockHeight();
this.executionState = transactionResponse.getExecutionState();
this.operationResults = operationResults;
}
public TxResponseMessage(HashDigest contentHash) {
this.contentHash = contentHash;
@@ -60,8 +69,8 @@ public class TxResponseMessage implements TransactionResponse {
this.blockHeight = blockHeight;
}
public void setContractReturn(OperationResult[] contractReturn) {
this.contractReturn = contractReturn;
public void setOperationResults(OperationResult[] operationResults) {
this.operationResults = operationResults;
}
@Override
@@ -70,8 +79,8 @@ public class TxResponseMessage implements TransactionResponse {
}
@Override
public OperationResult[] getContractReturn() {
return contractReturn;
public OperationResult[] getOperationResults() {
return operationResults;
}
}

+ 18
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java View File

@@ -1,20 +1,27 @@
package com.jd.blockchain.transaction;
import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionRequestBuilder;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.utils.Bytes;
import java.util.HashMap;
import java.util.Map;
public class TxTemplate implements TransactionTemplate {
private TxBuilder txBuilder;
private TransactionService txService;
private Map<Integer, EventResult> eventResults;
public TxTemplate(HashDigest ledgerHash, TransactionService txService) {
this.txBuilder = new TxBuilder(ledgerHash);
this.txService = txService;
this.eventResults = new HashMap<>();
}
@Override
@@ -25,7 +32,7 @@ public class TxTemplate implements TransactionTemplate {
@Override
public PreparedTransaction prepare() {
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();
return new PreparedTx(txReqBuilder, txService);
return new PreparedTx(txReqBuilder, txService, eventResults);
}
@Override
@@ -62,7 +69,16 @@ public class TxTemplate implements TransactionTemplate {
public <T> T contract(Bytes address, Class<T> contractIntf) {
return txBuilder.contract(address, contractIntf);
}
@Override
public <T> EventResult<T> result(ContractEventExecutor execute) {
EventResult<T> eventResult = txBuilder.result(execute);
if (eventResult != null) {
eventResults.put(eventResult.opIndex(), eventResult);
}
return eventResult;
}
@Override
public <T> T contract(String address, Class<T> contractIntf) {
return txBuilder.contract(address, contractIntf);


+ 2
- 2
source/peer/src/main/java/com/jd/blockchain/peer/consensus/ConsensusMessageDispatcher.java View File

@@ -310,8 +310,8 @@ public class ConsensusMessageDispatcher implements MessageHandle {
}

@Override
public OperationResult[] getContractReturn() {
return txResp.getContractReturn();
public OperationResult[] getOperationResults() {
return txResp.getOperationResults();
}
}



+ 93
- 14
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java View File

@@ -24,6 +24,10 @@ import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;

import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.contract.ReadContract;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.transaction.ContractEventExecutor;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.ClassPathResource;

@@ -31,16 +35,6 @@ import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInitOperation;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionState;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.UserRegisterOperation;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
import com.jd.blockchain.sdk.BlockchainService;
@@ -446,9 +440,9 @@ public class IntegrationBase {
// 合约测试使用的初始化数据;
static BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate();
static BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate();
// 保存资产总数的键;
// 第二个参数;
private static String contractZipName = "contract.jar";
// 保存资产总数的键;
// 第二个参数;
private static String contractZipName = "contract-read.jar";
static HashDigest txContentHash;

public static LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash,
@@ -484,7 +478,7 @@ public class IntegrationBase {
// execute the contract;
// testContractExe(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository);
// testContractExe1(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository);
testExeReadContract(adminKey, ledgerHash, blockchainService);
return block;
}

@@ -545,6 +539,91 @@ public class IntegrationBase {
// assertEquals(888L,kvDataEntries[1].getValue());
// }

private static void testExeReadContract(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainService blockchainService) {

// 首先注册一个数据账户
BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate();

TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
txTpl.dataAccounts().register(newDataAccount.getIdentity());

PreparedTransaction ptx = txTpl.prepare();
ptx.sign(adminKey);

// 提交并等待共识返回;
ptx.commit();

// 再提交一个KV写入
String key1 = "JingDong", value1 = "www.jd.com";
String key2 = "JD", value2 = "JingDong";

TransactionTemplate txKv = blockchainService.newTransaction(ledgerHash);
txKv.dataAccount(newDataAccount.getAddress()).setText(key1, value1, -1).setText(key2, value2, -1);
PreparedTransaction kvPtx = txKv.prepare();
kvPtx.sign(adminKey);

// 提交并等待共识返回;
kvPtx.commit();

// 下面才是执行Read交易
// 定义交易;
TransactionTemplate txContract = blockchainService.newTransaction(ledgerHash);

ReadContract readContract1 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class);

EventResult<String> read1 = txContract.result((ContractEventExecutor<ReadContract>) () -> {
readContract1.read(newDataAccount.getAddress().toBase58(), key1);
return readContract1;
});

ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class);

EventResult<String> read2 = txContract.result((ContractEventExecutor<ReadContract>) () -> {
readContract2.read(newDataAccount.getAddress().toBase58(), key2);
return readContract2;
});

ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class);

EventResult<Long> read3 = txContract.result((ContractEventExecutor<ReadContract>) () -> {
readContract3.readVersion(newDataAccount.getAddress().toBase58(), key2);
return readContract3;
});

// 签名;
PreparedTransaction contractPtx = txContract.prepare();
contractPtx.sign(adminKey);

// 提交并等待共识返回;
TransactionResponse readTxResp = contractPtx.commit();

OperationResult[] operationResults = readTxResp.getOperationResults();

// 通过EventResult获取结果
System.out.printf("readContract1.result = %s \r\n", read1.get());
System.out.printf("readContract2.result = %s \r\n", read2.get());
System.out.printf("readContract3.result = %s \r\n", read3.get());


// 打印结果
// for (OperationResult or : operationResults) {
// System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), or.getResult());
// }
//
// // 验证结果
// assertNotNull(contractReturn);
// assertEquals(contractReturn.length, 3);
//
// String returnVal1 = contractReturn[0];
// assertEquals(value1, returnVal1);
//
// String returnVal2 = contractReturn[1];
// assertEquals(value2, returnVal2);
//
// String returnVal3 = contractReturn[2];
// assertEquals("0", returnVal3);
}

/**
* 根据合约构建字节数组;
*


+ 4
- 28
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java View File

@@ -19,32 +19,7 @@ import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm;
import com.jd.blockchain.crypto.service.classic.ClassicCryptoService;
import com.jd.blockchain.crypto.service.sm.SMCryptoService;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.DataAccountRegisterOperation;
import com.jd.blockchain.ledger.EndpointRequest;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.KVInfoVO;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInfo;
import com.jd.blockchain.ledger.LedgerMetadata;
import com.jd.blockchain.ledger.LedgerTransaction;
import com.jd.blockchain.ledger.NodeRequest;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.TransactionContentBody;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionRequestBuilder;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionState;
import com.jd.blockchain.ledger.UserInfo;
import com.jd.blockchain.ledger.UserRegisterOperation;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.CryptoConfig;
import com.jd.blockchain.ledger.core.LedgerDataSet;
import com.jd.blockchain.ledger.core.LedgerEditor;
@@ -427,15 +402,16 @@ public class MockerNodeContext implements BlockchainQueryService {
return reqBuilder.buildRequest();
}

public void txProcess(TransactionRequest txRequest) {
public OperationResult[] txProcess(TransactionRequest txRequest) {
LedgerEditor newEditor = ledgerRepository.createNextBlock();
LedgerBlock latestBlock = ledgerRepository.getLatestBlock();
LedgerDataSet previousDataSet = ledgerRepository.getDataSet(latestBlock);
TransactionBatchProcessor txProc = new TransactionBatchProcessor(newEditor, previousDataSet, opHandler,
ledgerManager);
txProc.schedule(txRequest);
TransactionResponse txResp = txProc.schedule(txRequest);
TransactionBatchResultHandle handle = txProc.prepare();
handle.commit();
return txResp.getOperationResults();
}

private LedgerRepository registerLedger(HashDigest ledgerHash, DBConnectionConfig dbConnConf) {


+ 1
- 1
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java View File

@@ -10,5 +10,5 @@ public interface WriteContract {
void print(String name);

@ContractEvent(name = "writeKv")
void writeKv(String address, String key, String value);
String writeKv(String address, String key, String value);
}

+ 2
- 1
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java View File

@@ -15,8 +15,9 @@ public class WriteContractImpl implements EventProcessingAware, WriteContract {
}

@Override
public void writeKv(String address, String key, String value) {
public String writeKv(String address, String key, String value) {
eventContext.getLedger().dataAccount(address).setText(key, value, -1);
return String.format("address = %s, key = %s, value = %s, version = %s", address, key, value, 0);
}

@Override


+ 32
- 15
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java View File

@@ -1,7 +1,12 @@
package com.jd.blockchain.mocker.handler;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.jd.blockchain.contract.ContractEventContext;
import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.contract.EventProcessingAware;
import com.jd.blockchain.contract.LedgerContext;
import com.jd.blockchain.crypto.HashDigest;
@@ -9,17 +14,16 @@ import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.core.*;
import com.jd.blockchain.ledger.core.LedgerDataSet;
import com.jd.blockchain.ledger.core.LedgerService;
import com.jd.blockchain.ledger.core.OperationHandle;
import com.jd.blockchain.ledger.core.TransactionRequestContext;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
import com.jd.blockchain.ledger.core.impl.LedgerQueryService;
import com.jd.blockchain.ledger.core.impl.OperationHandleContext;
import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext;
import com.jd.blockchain.mocker.proxy.ExecutorProxy;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class MockerContractExeHandle implements OperationHandle {

private Map<HashDigest, ExecutorProxy> executorProxyMap = new ConcurrentHashMap<>();
@@ -37,6 +41,7 @@ public class MockerContractExeHandle implements OperationHandle {

ExecutorProxy executorProxy = executorProxyMap.get(txHash);

Object result = null;
if (executorProxy != null) {
LedgerQueryService queryService = new LedgerQueryService(ledgerManager);
ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext);
@@ -44,26 +49,38 @@ public class MockerContractExeHandle implements OperationHandle {
MockerContractEventContext contractEventContext = new MockerContractEventContext(ledgerHash,
contractOP.getEvent(), requestContext.getRequest(), ledgerContext);

EventProcessingAware eventProcessingAwire = (EventProcessingAware) executorProxy.getInstance();
try {
//
// Before处理过程
eventProcessingAwire.beforeEvent(contractEventContext);
executorProxy.invoke();
Object instance = executorProxy.getInstance();
EventProcessingAware awire = null;

if (instance instanceof EventProcessingAware) {
awire = (EventProcessingAware) instance;
awire.beforeEvent(contractEventContext);
}

// After处理过程
eventProcessingAwire.postEvent(contractEventContext, null);
try {
result = executorProxy.invoke();
if (awire != null) {
// After处理过程
awire.postEvent(contractEventContext, null);
}
} catch (Exception e) {
eventProcessingAwire.postEvent(contractEventContext, new ContractException(e.getMessage()));
if (awire != null) {
awire.postEvent(contractEventContext, new ContractException(e.getMessage()));
}
} finally {
removeExecutorProxy(txHash);
}
}

// No return value;
return null;
return ContractSerializeUtils.serialize(result);
}

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

@Override
public boolean support(Class<?> operationType) {
return ContractEventSendOperation.class.isAssignableFrom(operationType);


+ 11
- 3
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java View File

@@ -2,8 +2,11 @@ package com.jd.blockchain.mocker.proxy;

import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;
import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.OperationResult;
import com.jd.blockchain.ledger.OperationResultData;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.mocker.MockerNodeContext;
import com.jd.blockchain.mocker.handler.MockerContractExeHandle;
@@ -68,9 +71,14 @@ public class ContractProxy<T> implements InvocationHandler {
operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args));

// 提交该请求至整个区块链系统
mockerNodeContext.txProcess(txRequest);
// 不处理返回值
return null;
OperationResult[] operationResults = mockerNodeContext.txProcess(txRequest);
if (operationResults == null || operationResults.length == 0) {
return null;
}
OperationResult opResult = operationResults[0];

// 处理返回值
return ContractSerializeUtils.resolve(opResult.getResult());
}

private boolean isExecuteContractMethod(Method method) {


source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest_.java → source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java View File

@@ -10,7 +10,7 @@ import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class SampleTest_ {
public class SampleTest {

MockerNodeContext mockerNodeContext = null;

@@ -33,7 +33,9 @@ public class SampleTest_ {

writeContract = mockerNodeContext.deployContract(writeContract);

writeContract.writeKv(dataAccountAddress, key, value);
String result = writeContract.writeKv(dataAccountAddress, key, value);

System.out.println(result);

// 查询结果
KVDataEntry[] dataEntries = mockerNodeContext.getDataEntries(ledgerHash, dataAccountAddress, key);

Loading…
Cancel
Save