Browse Source

Completed the processing of the return value of Contract event send operation;

tags/1.0.0
huanghaiquan 5 years ago
parent
commit
0888190efa
39 changed files with 1366 additions and 875 deletions
  1. +2
    -2
      source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
  2. +2
    -4
      source/contract/contract-framework/src/main/java/com/jd/blockchain/contract/engine/ContractCode.java
  3. +4
    -3
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/AbstractContractCode.java
  4. +4
    -3
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java
  5. +2
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java
  6. +2
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java
  7. +2
    -5
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/AbtractContractEventHandle.java
  8. +4
    -8
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java
  9. +1
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java
  10. +4
    -4
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountRegisterOperationHandle.java
  11. +3
    -8
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/UserRegisterOperationHandle.java
  12. +7
    -3
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
  13. +154
    -147
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java
  14. +16
    -16
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractType.java
  15. +11
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BytesValueList.java
  16. +0
    -7
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractEventSendOperation.java
  17. +12
    -11
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataType.java
  18. +4
    -4
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResult.java
  19. +4
    -4
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/OperationResultData.java
  20. +13
    -11
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PreparedTransaction.java
  21. +58
    -32
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java
  22. +8
    -47
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOpTemplate.java
  23. +5
    -21
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractEventSendOperationBuilder.java
  24. +66
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocation.java
  25. +109
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationHandler.java
  26. +0
    -110
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java
  27. +29
    -23
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java
  28. +33
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationStub.java
  29. +418
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractReturns.java
  30. +7
    -16
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java
  31. +11
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationReturnValueHandler.java
  32. +54
    -26
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/PreparedTx.java
  33. +6
    -11
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java
  34. +1
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java
  35. +1
    -21
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java
  36. +149
    -154
      source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java
  37. +138
    -144
      source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test.java
  38. +20
    -15
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java
  39. +2
    -6
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java

+ 2
- 2
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;


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

byte[] processEvent(ContractEventContext eventContext);
BytesValue processEvent(ContractEventContext eventContext);
}

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

@@ -10,6 +10,7 @@ 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.utils.Bytes;

/**
@@ -44,7 +45,7 @@ public abstract class AbstractContractCode implements ContractCode {
}

@Override
public byte[] processEvent(ContractEventContext eventContext) {
public BytesValue processEvent(ContractEventContext eventContext) {
EventProcessingAware evtProcAwire = null;
Object retn = null;
Exception error = null;
@@ -90,13 +91,13 @@ public abstract class AbstractContractCode implements ContractCode {
eventContext.getEvent(), address.toString(), error.getMessage()), error);
}

byte[] retnBytes = resolveResult(retn);
BytesValue retnBytes = resolveResult(retn);
return retnBytes;
}

protected abstract Object getContractInstance();

private byte[] resolveResult(Object retn) {
private BytesValue resolveResult(Object retn) {
if (retn == null) {
return null;
}


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

@@ -9,6 +9,7 @@ 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;

@@ -65,7 +66,7 @@ public class JavaContractCode extends AbstractContractCode {
}

@Override
public byte[] processEvent(ContractEventContext eventContext) {
public BytesValue processEvent(ContractEventContext eventContext) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Start processing event[%s] of contract[%s]...", eventContext.getEvent(), address.toString());
}
@@ -91,7 +92,7 @@ public class JavaContractCode extends AbstractContractCode {
}
}

private class ContractExecution implements Callable<byte[]> {
private class ContractExecution implements Callable<BytesValue> {
private ContractEventContext eventContext;

public ContractExecution(ContractEventContext contractEventContext) {
@@ -99,7 +100,7 @@ public class JavaContractCode extends AbstractContractCode {
}

@Override
public byte[] call() throws Exception {
public BytesValue call() throws Exception {
return JavaContractCode.super.processEvent(eventContext);
}
}


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

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


public interface OperationHandle {
@@ -30,7 +30,7 @@ public interface OperationHandle {
*
* @return 操作执行结果
*/
byte[] process(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext,
BytesValue process(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext,
LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService);

// /**


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

@@ -8,7 +8,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerException;
import com.jd.blockchain.ledger.Operation;
@@ -110,7 +110,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
int opIndex = 0;
for (Operation op : ops) {
opHandle = opHandles.getHandle(op.getClass());
byte[] opResult = 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));
}


+ 2
- 5
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;
@@ -29,7 +26,7 @@ public abstract class AbtractContractEventHandle implements OperationHandle {
}

@Override
public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext,
public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext,
LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) {
ContractEventSendOperation contractOP = (ContractEventSendOperation) op;
// 先从账本校验合约的有效性;


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

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

import com.jd.blockchain.binaryproto.BinaryProtocol;
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;
@@ -9,17 +11,11 @@ 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 {

@Override
public byte[] 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: 校验合约代码的正确性;


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

@@ -1,7 +1,5 @@
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;
@@ -24,7 +22,7 @@ public class DataAccountKVSetOperationHandle implements OperationHandle {
}

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


+ 4
- 4
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,14 +12,11 @@ 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
public class DataAccountRegisterOperationHandle implements OperationHandle {

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


+ 3
- 8
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;
@@ -9,13 +10,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;


public class UserRegisterOperationHandle implements OperationHandle {

@Override
public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext,
public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext,
LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) {


@@ -26,14 +26,9 @@ public class UserRegisterOperationHandle implements OperationHandle {

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

return userAddress.toBytes();
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 UserRegisterOperation.class.isAssignableFrom(operationType);


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

@@ -120,8 +120,9 @@ public class ContractInvokingTest {
assertEquals(1, opResults.length);
assertEquals(0, opResults[0].getIndex());

byte[] retnBytes = BinaryProtocol.encode(BytesValueEntry.fromInt64(issueAmount), BytesValue.class);
assertArrayEquals(retnBytes, opResults[0].getResult());
byte[] expectedRetnBytes = BinaryProtocol.encode(BytesValueEntry.fromInt64(issueAmount), BytesValue.class);
byte[] reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class);
assertArrayEquals(expectedRetnBytes, reallyRetnBytes);

// 提交区块;
TransactionBatchResultHandle txResultHandle = txbatchProcessor.prepare();
@@ -135,7 +136,10 @@ public class ContractInvokingTest {
// 再验证一次结果;
assertEquals(1, opResults.length);
assertEquals(0, opResults[0].getIndex());
assertArrayEquals(retnBytes, opResults[0].getResult());
reallyRetnBytes = BinaryProtocol.encode(opResults[0].getResult(), BytesValue.class);
assertArrayEquals(expectedRetnBytes, reallyRetnBytes);

}

private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) {


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

@@ -1,157 +1,164 @@
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;

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

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

@@ -63,24 +63,24 @@ public class ContractType {
/**
* 解析合约的声明;
*
* @param delaredInterface 声明合约的接口类型
* @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) {
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()));
throw new IllegalDataException(String
.format("%s is not a Contract Type, because there is not @Contract !", contractIntf.getName()));
}
contractIntf = realIntf;
}
@@ -105,22 +105,25 @@ public class ContractType {

if (contractEvent != null) {
String eventName = contractEvent.name();
//if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO!
if(contractType.events.containsKey(eventName)){
// if annoMethodMap has contained the eventName, too many same eventNames exists
// probably, say NO!
if (contractType.events.containsKey(eventName)) {
throw new ContractException("there is repeat definition of contractEvent to @ContractEvent.");
}
//check param's type is fit for need.
// check param's type is fit for need.
Class<?>[] paramTypes = method.getParameterTypes();
for(Class<?> currParamType : paramTypes) {
for (Class<?> currParamType : paramTypes) {
if (!ContractSerializeUtils.support(currParamType)) {
throw new IllegalStateException(String.format("Param Type = %s can not support !!!", currParamType.getName()));
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()));
throw new IllegalStateException(
String.format("Return Type = %s can not support !!!", returnType.getName()));
}

contractType.events.put(eventName, method);
@@ -132,10 +135,7 @@ public class ContractType {

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

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

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

import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.consts.DataCodes;

@DataContract(code = DataCodes.BYTES_VALUE_LIST)
public interface BytesValueList {

BytesValue[] getValues();

}

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

@@ -37,11 +37,4 @@ public interface ContractEventSendOperation extends Operation {
@DataField(order = 4, primitiveType = PrimitiveType.BYTES)
byte[] getArgs();

/**
* 获得交易操作时间;
*
* @return
*/
@DataField(order = 5, primitiveType = PrimitiveType.INT64)
long getTxOpTime();
}

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

@@ -36,24 +36,22 @@ public enum DataType {
INT32(PrimitiveType.INT32.CODE),
INT64(PrimitiveType.INT64.CODE),
/**
* 文本数据;
*/
TEXT(PrimitiveType.TEXT.CODE),
/**
* 二进制数据;
*/
BYTES(PrimitiveType.BYTES.CODE),
/**
* 时间戳;
*/
TIMESTAMP((byte) (BaseType.INTEGER | 0x08)),
/**
* 文本数据;
*/
@@ -64,7 +62,6 @@ public enum DataType {
*/
XML((byte) (BaseType.TEXT | 0x02)),
/**
* 大整数;
*/
@@ -84,28 +81,32 @@ public enum DataType {
* 位置坐标;
*/
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));
ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)),
/**
* DataContract 数据;
*/
DATA_CONTRACT((byte) (BaseType.EXT | 0x01));
@EnumField(type = PrimitiveType.INT8)
public final byte CODE;


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

@@ -8,9 +8,9 @@ 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 = 1, primitiveType = PrimitiveType.INT32)
int getIndex();

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

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

@@ -5,12 +5,12 @@ public class OperationResultData implements OperationResult {

private int index;

private byte[] result;
private BytesValue result;

public OperationResultData() {
}

public OperationResultData(int index, byte[] result) {
public OperationResultData(int index, BytesValue result) {
this.index = index;
this.result = result;
}
@@ -21,7 +21,7 @@ public class OperationResultData implements OperationResult {
}

@Override
public byte[] getResult() {
public BytesValue getResult() {
return result;
}

@@ -29,7 +29,7 @@ public class OperationResultData implements OperationResult {
this.index = index;
}

public void setResult(byte[] result) {
public void setResult(BytesValue result) {
this.result = result;
}
}

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

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

import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.SignatureFunction;

/**
* 已就绪的交易;
@@ -10,7 +9,7 @@ import com.jd.blockchain.crypto.SignatureFunction;
* @author huanghaiquan
*
*/
public interface PreparedTransaction extends HashObject {
public interface PreparedTransaction extends HashObject {

/**
* 交易内容的 Hash;
@@ -33,10 +32,8 @@ public interface PreparedTransaction extends HashObject {
/**
* 对交易进行签名;
*
* @param address
* 签名账户的地址;
* @param privKey
* 签名账户的私钥;
* @param address 签名账户的地址;
* @param privKey 签名账户的私钥;
* @return
*/
DigitalSignature sign(AsymmetricKeypair keyPair);
@@ -44,17 +41,22 @@ public interface PreparedTransaction extends HashObject {
/**
* 加入签名;
*
* @param address
* 签名账户的地址;
* @param digest
* Base64格式的签名摘要;
* @param address 签名账户的地址;
* @param digest Base64格式的签名摘要;
* @return
*/
void addSignature(DigitalSignature signature);

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

/**
* 取消交易;<br>
*/
void cancel();
}

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

@@ -4,8 +4,8 @@ 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.BytesValue;
import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
@@ -44,6 +44,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
private ContractInvocationProxyBuilder contractInvoProxyBuilder = new ContractInvocationProxyBuilder();
// TODO: 暂时只支持单线程情形,未考虑多线程;
private List<Operation> operationList = new ArrayList<>();
@Override
@@ -90,16 +91,43 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder);
}
@Override
public <T> EventResult<T> result(ContractEventExecutor execute) {
return contractInvoProxyBuilder.execute(execute);
}
/**
* 返回已经定义的操作列表;
*
* @return
*/
public Collection<Operation> getOperations() {
// TODO: 合并操作列表中可能的重复操作;
return operationList;
}
/**
* 返回与操作列表对应的返回值处理器;
*
* @return
*/
public Collection<OperationReturnValueHandler> getReturnValuetHandlers() {
List<OperationReturnValueHandler> resultHandlers = new ArrayList<OperationReturnValueHandler>();
int index = 0;
for (Operation op : operationList) {
if (op instanceof ContractEventSendOperation) {
// 操作具有返回值,创建对应的结果处理器;
ContractEventSendOpTemplate opTemp = (ContractEventSendOpTemplate) op;
ContractInvocation invocation = opTemp.getInvocation();
OperationReturnValueHandler retnHandler;
if (invocation == null) {
retnHandler = new NullOperationReturnValueHandler(index);
} else {
invocation.setOperationIndex(index);
retnHandler = invocation;
}
resultHandlers.add(retnHandler);
}
index++;
}
return resultHandlers;
}
public void clear() {
operationList.clear();
}
@@ -160,13 +188,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
}
}
// @Override
// public DataAccountKVSetOperationBuilder set(String key, byte[] value, long expVersion) {
// innerBuilder.set(key, value, expVersion);
// addOperation();
// return this;
// }
@Override
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) {
innerBuilder.setText(key, value, expVersion);
@@ -202,13 +223,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
return this;
}
// @Override
// public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) {
// innerBuilder.setText(key, value, expVersion);
// addOperation();
// return this;
// }
@Override
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) {
innerBuilder.setJSON(key, value, expVersion);
@@ -233,7 +247,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
}
private class ContractCodeDeployOperationBuilderFilter implements ContractCodeDeployOperationBuilder {
@Override
public ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode) {
ContractCodeDeployOperation op = CONTRACT_CODE_DEPLOY_OP_BUILDER.deploy(id, chainCode);
@@ -250,25 +263,38 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
}
@Override
public ContractEventSendOperation send(Bytes address, String event, byte[] args) {
int opIndex = operationList.size();
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args, opIndex);
public synchronized ContractEventSendOperation send(Bytes address, String event, byte[] args) {
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args);
operationList.add(op);
return op;
}
}
/**
* 不做任何操作的返回值处理器;
*
* @author huanghaiquan
*
*/
private static class NullOperationReturnValueHandler implements OperationReturnValueHandler {
private int operationIndex;
public NullOperationReturnValueHandler(int operationIndex) {
this.operationIndex = operationIndex;
}
@Override
public ContractEventSendOperation send(String address) {
return send(Bytes.fromBase58(address));
public int getOperationIndex() {
return operationIndex;
}
@Override
public ContractEventSendOperation send(Bytes address) {
int opIndex = operationList.size();
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, opIndex);
operationList.add(op);
return op;
public Object setReturnValue(BytesValue bytesValue) {
return null;
}
}
}

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

@@ -13,47 +13,13 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation {
private Bytes contractAddress;
private byte[] args;
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();
}
private ContractInvocation invocation;

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
@@ -71,17 +37,12 @@ public class ContractEventSendOpTemplate implements ContractEventSendOperation {
return args;
}

@Override
public long getTxOpTime() {
return txOpTime;
public ContractInvocation getInvocation() {
return invocation;
}

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

}

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

@@ -7,33 +7,17 @@ public interface ContractEventSendOperationBuilder {
/**
* @param address 合约地址;
* @param event 事件名;
* @param args 事件参数;
* @param event 事件名;
* @param args 事件参数;
* @return
*/
@Deprecated
ContractEventSendOperation send(String address, String event, byte[] args);
/**
* @param address 合约地址;
* @param event 事件名;
* @param args 事件参数;
* @param event 事件名;
* @param args 事件参数;
* @return
*/
@Deprecated
ContractEventSendOperation send(Bytes address, String event, byte[] args);
/**
*
* @param address
* @return
*/
ContractEventSendOperation send(String address);
/**
*
* @param address
* @return
*/
ContractEventSendOperation send(Bytes address);
}

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

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

import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.ledger.BytesValue;

/**
* ContractInvocation 包装了客户端发起的一次合约方法调用的相关信息,用于在客户端交易处理上下文进行共享处理状态;
*
* @author huanghaiquan
*
*/
class ContractInvocation implements OperationReturnValueHandler {

private Method method;

private ContractType contractType;

private int operationIndex = -1;

private CompletableFuture<Object> returnValueFuture;

public ContractInvocation(ContractType contractType, Method method) {
this.contractType = contractType;
this.method = method;
this.returnValueFuture = new CompletableFuture<Object>();
}

public ContractType getContractType() {
return contractType;
}

@Override
public int getOperationIndex() {
return operationIndex;
}

public void setOperationIndex(int operationIndex) {
this.operationIndex = operationIndex;
}

public Class<?> getReturnType() {
return method.getReturnType();
}

public Future<Object> getReturnValue() {
return returnValueFuture;
}

@Override
public Object setReturnValue(BytesValue bytesValue) {
// Resolve BytesValue to an value object with the return type;
Object returnValue = resolveValue(bytesValue, method.getReturnType());
returnValueFuture.complete(returnValue);
return returnValue;
}

private Object resolveValue(BytesValue bytesValue, Class<?> returnType) {
// TODO: Resolve BytesValue to an value object with the return type;
throw new IllegalStateException("Not implemented!");
}

}

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

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

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

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

public class ContractInvocationHandler implements InvocationHandler {

private Bytes contractAddress;

private ContractType contractType;

private ContractEventSendOperationBuilder sendOpBuilder;

private int proxyHashCode;

public ContractInvocationHandler(Bytes contractAddress, ContractType contractType,
ContractEventSendOperationBuilder sendOpBuilder) {
this.contractAddress = contractAddress;
if (contractType == null) {
throw new IllegalDataException("contractType == null, no invoke really.");
}
this.contractType = contractType;
this.sendOpBuilder = sendOpBuilder;
this.proxyHashCode = Arrays.deepHashCode(new Object[] { this, contractAddress, contractType, sendOpBuilder });
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断是否是常规方法调用
if (method.getName().equals("hashCode")) {
// 该处需要使用当前代理类的HashCode
return proxyHashCode;
}
if (method.getName().equals("toString")) {
// 该处使用当前代理类的toString
return this.toString();
}

String event = contractType.getEvent(method);
if (event == null) {
// 该方法不是合约可执行的方法
throw new ContractException(
String.format("The invoking method [%s] is not annotated as event handle method by @ContractEvent!",
method.toString()));
}
// 序列化调用参数;
byte[] argBytes = serializeArgs(args);

// 定义合约调用操作;
@SuppressWarnings("deprecation")
ContractEventSendOpTemplate opTemplate = (ContractEventSendOpTemplate) sendOpBuilder.send(contractAddress,
event, argBytes);

// 加入合约调用的额外信息;
ContractInvocation invocation = new ContractInvocation(contractType, method);

// 传递给定义操作的上下文,以便在生成交易时,同步操作在交易中的索引位置;
opTemplate.setInvocation(invocation);

// 传递给通过代理对象调用合约方法的调用者,以便可以同步操作在交易中的索引位置以及操作的返回值;
ContractInvocationStub.set(invocation);

// 返回类型的默认值
return getDefaultValue(method.getReturnType());
}

private byte[] serializeArgs(Object[] args) {
return ContractSerializeUtils.serializeArray(args);
}

private Object getDefaultValue(Class<?> returnType) {
if (returnType == void.class || returnType == Void.class) {
return null;
}

if (!returnType.isPrimitive()) {
// 非基本类型
return null;
} else {
// 基本类型需要处理返回值,目前采用枚举遍历方式
// 八种基本类型:int, double, float, long, short, boolean, byte, char, void
if (returnType.equals(int.class)) {
return 0;
} else if (returnType.equals(double.class)) {
return 0.0D;
} else if (returnType.equals(float.class)) {
return 0F;
} else if (returnType.equals(long.class)) {
return 0L;
} else if (returnType.equals(short.class)) {
return (short) 0;
} else if (returnType.equals(boolean.class)) {
return Boolean.FALSE;
} else if (returnType.equals(byte.class)) {
return (byte) 0;
} else if (returnType.equals(char.class)) {
return (char) 0;
}
return null;
}
}
}

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

@@ -1,110 +0,0 @@
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;

public class ContractInvocationProxy implements InvocationHandler {

// private String contractMessage;

// private Bytes contractAddress;

private ContractType contractType;

// private ContractEventSendOperationBuilder sendOpBuilder;

private ContractEventSendOperation sendOperation;

public ContractInvocationProxy(Bytes contractAddress, ContractType contractType,
ContractEventSendOperationBuilder sendOpBuilder) {
// this.contractAddress = contractAddress;
if(contractType == null){
throw new IllegalDataException("contractType == null, no invoke really.");
}
this.contractType = contractType;
// this.sendOpBuilder = sendOpBuilder;
// 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) {
// 该方法不是合约可执行的方法
throw new IllegalAccessException(String.format("This Method [%s] is not Contract Event Method !!!",
method.getName()));
}
// 合约方法;
byte[] argBytes = serializeArgs(args);
if (sendOperation instanceof ContractEventSendOpTemplate) {
((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes);
}
// 代理操作,返回值类型无法创建
return returnResult(method.getReturnType());
}

private byte[] serializeArgs(Object[] args) {
return ContractSerializeUtils.serializeArray(args);
}

public int opIndex() {
if (sendOperation instanceof ContractEventSendOpTemplate) {
return ((ContractEventSendOpTemplate) sendOperation).getOpIndex();
}
return -1;
}

private Object returnResult(Class<?> clazz) {
if (clazz.equals(Void.TYPE)) {
return null;
}

if (!clazz.isPrimitive()) {
// 非基本类型
return null;
} else {
// 基本类型需要处理返回值,目前采用枚举遍历方式
// 八种基本类型:int, double, float, long, short, boolean, byte, char, void
if (clazz.equals(int.class)) {
return 0;
} else if (clazz.equals(double.class)) {
return 0.0D;
} else if (clazz.equals(float.class)) {
return 0F;
} else if (clazz.equals(long.class)) {
return 0L;
} else if (clazz.equals(short.class)) {
return (short)0;
} else if (clazz.equals(boolean.class)) {
return Boolean.FALSE;
} else if (clazz.equals(byte.class)) {
return (byte)0;
} else if (clazz.equals(char.class)) {
return (char)0;
}
return null;
}
}
}

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

@@ -9,11 +9,17 @@ import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.IllegalDataException;
/**
* 合约调用代理的构建器;
*
* @author huanghaiquan
*
*/
public class ContractInvocationProxyBuilder {
private Map<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>();
private Map<Object, Integer> contractOperations = 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,34 +29,34 @@ public class ContractInvocationProxyBuilder {
public <T> T create(Bytes address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) {
ContractType contractType = resolveContractType(contractIntf);
ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType,
contractEventBuilder);
ContractInvocationHandler proxyHandler = new ContractInvocationHandler(address, contractType, contractEventBuilder);
T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { contractIntf }, proxyHandler);
// 创建关联关系
contractOperations.put(proxy, proxyHandler.opIndex());
// // 创建关联关系
// 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()));
}
Integer opIndex = contractOperations.get(contractProxy);
if (opIndex != null && opIndex > -1) {
return new EventResult<>(opIndex);
}
return null;
}
// 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()));
// }
//
// Integer opIndex = contractOperations.get(contractProxy);
// if (opIndex != null && opIndex > -1) {
// return new EventResult<>(opIndex);
// }
// return null;
// }
private ContractType resolveContractType(Class<?> contractIntf) {
ContractType contractType = contractTypes.get(contractIntf);


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

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

/**
* 用于在上下文中传递合约调用返回值的工具类;
*
* @author huanghaiquan
*
*/
class ContractInvocationStub {

private static ThreadLocal<ContractInvocation> stub = new ThreadLocal<ContractInvocation>();

private ContractInvocationStub() {
}

public static void set(ContractInvocation invocation) {
if (invocation == null) {
throw new IllegalArgumentException("Null stub value!");
}
stub.set(invocation);
}

public static ContractInvocation take() {
ContractInvocation subValue = stub.get();
if (subValue == null) {
throw new IllegalStateException(
"The latest invocation of contract has not been stubbed! It may be caused by the wrong call sequence from the upper layer!");
}
stub.remove();
return subValue;
}

}

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

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

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class ContractReturns {

/**
* 解析合约方法调用的返回值;
* <p>
* 用法示例:<br>
* <code>
* ReturnValue<String> retnHolder = decode(contract.issue(assetKey, amount));
*
* PreparedTransaction prepTx = tx.prepare();
* prepTx.sign(userKey);
* prepTx.commit()
*
* String retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
* </code>
*
* @param <T>
* @param call
* @return
*/
public static <T> ReturnValue<T> decode(T call) {
ContractInvocation invocation = ContractInvocationStub.take();
return new ReturnValue<T>(invocation);
}

/**
* 解析合约方法调用的返回值;
* <p>
* 用法示例:<br>
* <code>
* ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount));
*
* PreparedTransaction prepTx = tx.prepare();
* prepTx.sign(userKey);
* prepTx.commit()
*
* long retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
* </code>
*
* @param call
* @return
*/
public static ReturnLongValue decode(long call) {
ContractInvocation invocation = ContractInvocationStub.take();
return new ReturnLongValue(invocation);
}

/**
* 解析合约方法调用的返回值;
* <p>
* 用法示例:<br>
* <code>
* ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount));
*
* PreparedTransaction prepTx = tx.prepare();
* prepTx.sign(userKey);
* prepTx.commit()
*
* int retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
* </code>
*
* @param call
* @return
*/
public static ReturnIntValue decode(int call) {
ContractInvocation invocation = ContractInvocationStub.take();
return new ReturnIntValue(invocation);
}

/**
* 解析合约方法调用的返回值;
* <p>
* 用法示例:<br>
* <code>
* ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount));
*
* PreparedTransaction prepTx = tx.prepare();
* prepTx.sign(userKey);
* prepTx.commit()
*
* short retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
* </code>
*
* @param call
* @return
*/
public static ReturnShortValue decode(short call) {
ContractInvocation invocation = ContractInvocationStub.take();
return new ReturnShortValue(invocation);
}

/**
* 解析合约方法调用的返回值;
* <p>
* 用法示例:<br>
* <code>
* ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount));
*
* PreparedTransaction prepTx = tx.prepare();
* prepTx.sign(userKey);
* prepTx.commit()
*
* byte retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
* </code>
*
* @param call
* @return
*/
public static ReturnByteValue decode(byte call) {
ContractInvocation invocation = ContractInvocationStub.take();
return new ReturnByteValue(invocation);
}
/**
* 解析合约方法调用的返回值;
* <p>
* 用法示例:<br>
* <code>
* ReturnLongValue retnHolder = decode(contract.issue(assetKey, amount));
*
* PreparedTransaction prepTx = tx.prepare();
* prepTx.sign(userKey);
* prepTx.commit()
*
* boolean retnValue = retnHolder.get(); //这是同步方法,会阻塞当前线程等待交易提交后返回结果;
* </code>
*
* @param call
* @return
*/
public static ReturnBooleanValue decode(boolean call) {
ContractInvocation invocation = ContractInvocationStub.take();
return new ReturnBooleanValue(invocation);
}

//----------------------- 内部类型 -----------------------
private static class ReturnValueBase {
private ContractInvocation invocation;

private ReturnValueBase(ContractInvocation invocation) {
this.invocation = invocation;
}

/**
* 等待结果合约调用的结果返回;
*
* @return
*/
private Object get() {
try {
return invocation.getReturnValue().get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @param unit
* @return
* @throws TimeoutException
*/
private Object get(long timeout, TimeUnit unit) throws TimeoutException {
try {
return invocation.getReturnValue().get(timeout, unit);
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}

public static class ReturnValue<T> extends ReturnValueBase {

private ReturnValue(ContractInvocation invocation) {
super(invocation);
}

/**
* 等待结果合约调用的结果返回;
*
* @return
*/
@SuppressWarnings("unchecked")
public T get() {
return (T) super.get();
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @return
* @throws TimeoutException
*/
public T get(long timeout) throws TimeoutException {
return get(timeout, TimeUnit.MILLISECONDS);
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @param unit
* @return
* @throws TimeoutException
*/
@SuppressWarnings("unchecked")
public T get(long timeout, TimeUnit unit) throws TimeoutException {
return (T) super.get(timeout, unit);
}
}

public static class ReturnLongValue extends ReturnValueBase {

private ReturnLongValue(ContractInvocation invocation) {
super(invocation);
}

/**
* 等待结果合约调用的结果返回;
*
* @return
*/
public long get() {
return (long) super.get();
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @return
* @throws TimeoutException
*/
public long get(long timeout) throws TimeoutException {
return get(timeout, TimeUnit.MILLISECONDS);
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @param unit
* @return
* @throws TimeoutException
*/
public long get(long timeout, TimeUnit unit) throws TimeoutException {
return (long) super.get(timeout, unit);
}
}

public static class ReturnIntValue extends ReturnValueBase {

private ReturnIntValue(ContractInvocation invocation) {
super(invocation);
}

/**
* 等待结果合约调用的结果返回;
*
* @return
*/
public int get() {
return (int) super.get();
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @return
* @throws TimeoutException
*/
public int get(long timeout) throws TimeoutException {
return get(timeout, TimeUnit.MILLISECONDS);
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @param unit
* @return
* @throws TimeoutException
*/
public int get(long timeout, TimeUnit unit) throws TimeoutException {
return (int) super.get(timeout, unit);
}
}

public static class ReturnShortValue extends ReturnValueBase {

private ReturnShortValue(ContractInvocation invocation) {
super(invocation);
}

/**
* 等待结果合约调用的结果返回;
*
* @return
*/
public short get() {
return (short) super.get();
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @return
* @throws TimeoutException
*/
public short get(long timeout) throws TimeoutException {
return get(timeout, TimeUnit.MILLISECONDS);
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @param unit
* @return
* @throws TimeoutException
*/
public short get(long timeout, TimeUnit unit) throws TimeoutException {
return (short) super.get(timeout, unit);
}
}

public static class ReturnByteValue extends ReturnValueBase {

private ReturnByteValue(ContractInvocation invocation) {
super(invocation);
}

/**
* 等待结果合约调用的结果返回;
*
* @return
*/
public byte get() {
return (byte) super.get();
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @return
* @throws TimeoutException
*/
public byte get(long timeout) throws TimeoutException {
return get(timeout, TimeUnit.MILLISECONDS);
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @param unit
* @return
* @throws TimeoutException
*/
public byte get(long timeout, TimeUnit unit) throws TimeoutException {
return (byte) super.get(timeout, unit);
}
}

public static class ReturnBooleanValue extends ReturnValueBase {

private ReturnBooleanValue(ContractInvocation invocation) {
super(invocation);
}

/**
* 等待结果合约调用的结果返回;
*
* @return
*/
public boolean get() {
return (boolean) super.get();
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @return
* @throws TimeoutException
*/
public boolean get(long timeout) throws TimeoutException {
return get(timeout, TimeUnit.MILLISECONDS);
}

/**
* 等待结果合约调用的结果返回;
*
* @param timeout
* @param unit
* @return
* @throws TimeoutException
*/
public boolean get(long timeout, TimeUnit unit) throws TimeoutException {
return (boolean) super.get(timeout, unit);
}
}
}

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

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

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

public interface EventOperator {

// /**
// * 合约事件;
// *
// * @return
// */
// @Deprecated
// ContractEventSendOperationBuilder contractEvents();

/**
* 创建调用合约的代理实例;
*
@@ -31,11 +22,11 @@ public interface EventOperator {
*/
<T> T contract(Bytes address, Class<T> contractIntf);

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

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

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

import com.jd.blockchain.ledger.BytesValue;

interface OperationReturnValueHandler {

int getOperationIndex();

Object setReturnValue(BytesValue bytesValue);

}

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

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

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;

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.*;

import java.util.Map;
import com.jd.blockchain.ledger.DigitalSignature;
import com.jd.blockchain.ledger.OperationResult;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionRequestBuilder;
import com.jd.blockchain.ledger.TransactionResponse;

public class PreparedTx implements PreparedTransaction {

@@ -19,16 +25,29 @@ public class PreparedTx implements PreparedTransaction {

private TransactionService txProcessor;

private Map<Integer, EventResult> eventResults;
private OperationReturnValueHandler[] opReturnValueHandlers;

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

public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor, Map<Integer, EventResult> eventResults) {
/**
* 创建一个“就绪交易”对象;
*
* @param txReqBuilder 交易请求构建器;
* @param txProcessor 交易处理服务;
* @param opReturnValueHandlerList 操作返回值处理器列表;
*/
public PreparedTx(TransactionRequestBuilder txReqBuilder, TransactionService txProcessor,
Collection<OperationReturnValueHandler> opReturnValueHandlerList) {
this.txReqBuilder = txReqBuilder;
this.txProcessor = txProcessor;
this.eventResults = eventResults;

this.opReturnValueHandlers = opReturnValueHandlerList
.toArray(new OperationReturnValueHandler[opReturnValueHandlerList.size()]);
// 按照操作索引升序排列;
Arrays.sort(opReturnValueHandlers, new Comparator<OperationReturnValueHandler>() {
@Override
public int compare(OperationReturnValueHandler o1, OperationReturnValueHandler o2) {
return o1.getOperationIndex() - o2.getOperationIndex();
}
});
}

@Override
@@ -59,23 +78,32 @@ public class PreparedTx implements PreparedTransaction {

@Override
public TransactionResponse commit() {
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()));
try {
TransactionRequest txReq = txReqBuilder.buildRequest();
// 发起交易请求;
TransactionResponse txResponse = txProcessor.process(txReq);

// 解析返回值;正常的情况下,返回结果列表与结果处理器列表中元素对应的操作索引是一致的;
OperationResult[] opResults = txResponse.getOperationResults();
if (opResults != null && opResults.length > 0) {
if (opResults.length != opReturnValueHandlers.length) {
throw new IllegalStateException(String.format(
"The operation result list of tx doesn't match it's return value handler list! --[TX.Content.Hash=%s][NumOfResults=%s][NumOfHandlers=%s]",
txReq.getTransactionContent().getHash(), opResults.length, opReturnValueHandlers.length));
}
for (int i = 0; i < opResults.length; i++) {
if (opResults[i].getIndex() != opReturnValueHandlers[i].getOperationIndex()) {
throw new IllegalStateException(
"The operation indexes of the items in the result list and in the handler list don't match!");
}
opReturnValueHandlers[i].setReturnValue(opResults[i].getResult());
}
}
return txResponse;
} catch (Exception e) {
//TODO: 出错时清理交易上下文,释放与交易关联对异步等待资源,避免当前线程死锁;
}
return txResponse;
}


}

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

@@ -1,8 +1,9 @@
package com.jd.blockchain.transaction;

import java.util.Collection;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.TransactionBuilder;
@@ -11,9 +12,6 @@ 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 {
@@ -22,8 +20,6 @@ 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;
@@ -55,6 +51,10 @@ public class TxBuilder implements TransactionBuilder {
return txContent;
}

public Collection<OperationReturnValueHandler> getReturnValuehandlers() {
return opFactory.getReturnValuetHandlers();
}

@Override
public LedgerInitOperationBuilder ledgers() {
return opFactory.ledgers();
@@ -94,11 +94,6 @@ 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);


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

@@ -71,8 +71,7 @@ public class TxRequestBuilder implements TransactionRequestBuilder {
}
public static SignatureDigest sign(TransactionContent txContent, PrivKey privKey) {
return Crypto.getSignatureFunction(privKey.getAlgorithm()).sign(privKey,
txContent.getHash().toBytes());
return Crypto.getSignatureFunction(privKey.getAlgorithm()).sign(privKey, txContent.getHash().toBytes());
}
public static boolean verifySignature(TransactionContent txContent, SignatureDigest signDigest, PubKey pubKey) {


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

@@ -1,27 +1,21 @@
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
@@ -32,7 +26,7 @@ public class TxTemplate implements TransactionTemplate {
@Override
public PreparedTransaction prepare() {
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest();
return new PreparedTx(txReqBuilder, txService, eventResults);
return new PreparedTx(txReqBuilder, txService, txBuilder.getReturnValuehandlers());
}
@Override
@@ -60,25 +54,11 @@ public class TxTemplate implements TransactionTemplate {
return txBuilder.contracts();
}
// @Override
// public ContractEventSendOperationBuilder contractEvents() {
// return txBuilder.contractEvents();
// }
@Override
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);


+ 149
- 154
source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDK_Contract_Demo.java View File

@@ -1,164 +1,159 @@
package com.jd.blockchain.sdk.samples;

import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes;
import static com.jd.blockchain.transaction.ContractReturns.decode;

import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.contract.TransferContract;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.transaction.ContractEventExecutor;
import com.jd.blockchain.transaction.ContractReturns.ReturnLongValue;
import com.jd.blockchain.transaction.ContractReturns.ReturnValue;
import com.jd.blockchain.utils.Bytes;

import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes;

public class SDK_Contract_Demo extends SDK_Base_Demo {

public static void main(String[] args) {
SDK_Contract_Demo demo = new SDK_Contract_Demo();
demo.executeContract();
}

public void executeContract() {

// 发布jar包
// 定义交易模板
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);

// 将jar包转换为二进制数据
byte[] contractCode = readChainCodes("transfer.jar");

// 生成一个合约账号
BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate();

// 生成发布合约操作
txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode);

// 生成预发布交易;
PreparedTransaction ptx = txTpl.prepare();

// 对交易进行签名
ptx.sign(adminKey);

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

// 获取合约地址
Bytes contractAddress = contractDeployKey.getAddress();

// 打印交易返回信息
System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n",
txResp.getContentHash().toBase58(), txResp.getBlockHeight(),
txResp.getBlockHash().toBase58(), txResp.isSuccess(),
txResp.getExecutionState());

// 打印合约地址
System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58());

// 注册一个数据账户
BlockchainKeypair dataAccount = createDataAccount();
// 获取数据账户地址
String dataAddress = dataAccount.getAddress().toBase58();
// 打印数据账户地址
System.out.printf("DataAccountAddress = %s \r\n", dataAddress);

// 创建两个账号:
String account0 = "jd_zhangsan", account1 = "jd_lisi";
long account0Money = 3000L, account1Money = 2000L;
// 创建两个账户
// 使用KV操作创建一个账户
System.out.println(create(dataAddress, account0, account0Money, false, null));
// 使用合约创建一个账户
System.out.println(create(dataAddress, account1, account1Money, true, contractAddress));

// 转账,使得双方钱达到一致
System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress));

// 通过合约读取account0的当前信息
System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By Contract)\r\n",
dataAddress, account0, readByContract(dataAddress, account0, contractAddress));
// 通过KV读取account1的当前信息
System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By KV Operation)\r\n",
dataAddress, account1, readByKvOperation(dataAddress, account1));

// 通过合约读取account0的历史信息
System.out.println(readAll(dataAddress, account0, contractAddress));
// 通过合约读取account1的历史信息
System.out.println(readAll(dataAddress, account1, contractAddress));
}

private String readAll(String address, String account, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> {
transferContract.readAll(address, account);
return transferContract;
});
commit(txTpl);
return eventResult.get();
}

private long readByContract(String address, String account, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
EventResult<Long> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> {
transferContract.read(address, account);
return transferContract;
});
commit(txTpl);
return eventResult.get();
}

private long readByKvOperation(String address, String account) {
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account);
if (kvDataEntries == null || kvDataEntries.length == 0) {
throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58()));
}
KVDataEntry kvDataEntry = kvDataEntries[0];
if (kvDataEntry.getVersion() == -1) {
return 0L;
}
return (long) (kvDataEntry.getValue());
}


private String transfer(String address, String from, String to, long money, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> {
transferContract.transfer(address, from, to, money);
return transferContract;
});
commit(txTpl);
return eventResult.get();
}

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

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

private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
if (useContract) {
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> {
transferContract.create(address, account, money);
return transferContract;
});
commit(txTpl);
return eventResult.get();
} else {
// 通过KV创建
txTpl.dataAccount(address).setInt64(account, money, -1);
TransactionResponse txResp = commit(txTpl);
return String.format("DataAccountAddress[%s] -> Create(By KV Operation) Account = %s and Money = %s Success!!! \r\n",
address, account, money);
}
}
public static void main(String[] args) {
SDK_Contract_Demo demo = new SDK_Contract_Demo();
demo.executeContract();
}

public void executeContract() {

// 发布jar包
// 定义交易模板
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);

// 将jar包转换为二进制数据
byte[] contractCode = readChainCodes("transfer.jar");

// 生成一个合约账号
BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate();

// 生成发布合约操作
txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode);

// 生成预发布交易;
PreparedTransaction ptx = txTpl.prepare();

// 对交易进行签名
ptx.sign(adminKey);

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

// 获取合约地址
Bytes contractAddress = contractDeployKey.getAddress();

// 打印交易返回信息
System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n",
txResp.getContentHash().toBase58(), txResp.getBlockHeight(), txResp.getBlockHash().toBase58(),
txResp.isSuccess(), txResp.getExecutionState());

// 打印合约地址
System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58());

// 注册一个数据账户
BlockchainKeypair dataAccount = createDataAccount();
// 获取数据账户地址
String dataAddress = dataAccount.getAddress().toBase58();
// 打印数据账户地址
System.out.printf("DataAccountAddress = %s \r\n", dataAddress);

// 创建两个账号:
String account0 = "jd_zhangsan", account1 = "jd_lisi";
long account0Money = 3000L, account1Money = 2000L;
// 创建两个账户
// 使用KV操作创建一个账户
System.out.println(create(dataAddress, account0, account0Money, false, null));
// 使用合约创建一个账户
System.out.println(create(dataAddress, account1, account1Money, true, contractAddress));

// 转账,使得双方钱达到一致
System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress));

// 通过合约读取account0的当前信息
System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By Contract)\r\n", dataAddress,
account0, readByContract(dataAddress, account0, contractAddress));
// 通过KV读取account1的当前信息
System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By KV Operation)\r\n", dataAddress,
account1, readByKvOperation(dataAddress, account1));

// 通过合约读取account0的历史信息
System.out.println(readAll(dataAddress, account0, contractAddress));
// 通过合约读取account1的历史信息
System.out.println(readAll(dataAddress, account1, contractAddress));
}

private String readAll(String address, String account, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
ReturnValue<String> result = decode(transferContract.readAll(address, account));
commit(txTpl);
return result.get();
}

private long readByContract(String address, String account, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
ReturnLongValue result = decode(transferContract.read(address, account));
commit(txTpl);
return result.get();
}

private long readByKvOperation(String address, String account) {
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account);
if (kvDataEntries == null || kvDataEntries.length == 0) {
throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58()));
}
KVDataEntry kvDataEntry = kvDataEntries[0];
if (kvDataEntry.getVersion() == -1) {
return 0L;
}
return (long) (kvDataEntry.getValue());
}

private String transfer(String address, String from, String to, long money, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
ReturnValue<String> result = decode(transferContract.transfer(address, from, to, money));
commit(txTpl);
return result.get();
}

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

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

private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
if (useContract) {
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
ReturnValue<String> result = decode(transferContract.create(address, account, money));
commit(txTpl);
return result.get();
} else {
// 通过KV创建
txTpl.dataAccount(address).setInt64(account, money, -1);
TransactionResponse txResp = commit(txTpl);
return String.format(
"DataAccountAddress[%s] -> Create(By KV Operation) Account = %s and Money = %s Success!!! \r\n",
address, account, money);
}
}
}

+ 138
- 144
source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDKDemo_Contract_Test.java View File

@@ -1,171 +1,165 @@
package test.com.jd.blockchain.sdk.test;

import com.jd.blockchain.contract.EventResult;
import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes;
import static com.jd.blockchain.transaction.ContractReturns.decode;

import org.junit.Before;
import org.junit.Test;

import com.jd.blockchain.contract.TransferContract;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.sdk.client.GatewayServiceFactory;
import com.jd.blockchain.sdk.samples.SDKDemo_Constant;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.transaction.ContractEventExecutor;
import com.jd.blockchain.transaction.ContractReturns.ReturnLongValue;
import com.jd.blockchain.transaction.ContractReturns.ReturnValue;
import com.jd.blockchain.utils.Bytes;
import org.junit.Before;
import org.junit.Test;

import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes;

public class SDKDemo_Contract_Test {

private BlockchainKeypair adminKey;
private BlockchainKeypair adminKey;

private HashDigest ledgerHash;
private HashDigest ledgerHash;

private BlockchainService blockchainService;
private BlockchainService blockchainService;

@Before
public void init() {
// 生成连接网关的账号
PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], SDKDemo_Constant.PASSWORD);
@Before
public void init() {
// 生成连接网关的账号
PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0],
SDKDemo_Constant.PASSWORD);

PubKey pubKey = KeyGenCommand.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]);
PubKey pubKey = KeyGenCommand.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]);

adminKey = new BlockchainKeypair(pubKey, privKey);
adminKey = new BlockchainKeypair(pubKey, privKey);

// 连接网关
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR,
SDKDemo_Constant.GW_PORT, false, adminKey);
// 连接网关
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR,
SDKDemo_Constant.GW_PORT, false, adminKey);

blockchainService = serviceFactory.getBlockchainService();
blockchainService = serviceFactory.getBlockchainService();

HashDigest[] ledgerHashs = blockchainService.getLedgerHashs();
HashDigest[] ledgerHashs = blockchainService.getLedgerHashs();

ledgerHash = ledgerHashs[0];
}
ledgerHash = ledgerHashs[0];
}

@Test
public void testContract() {
@Test
public void testContract() {

// 发布jar包
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 发布jar包
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);

byte[] contractCode = readChainCodes("transfer.jar");

// 生成一个合约账号
BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate();

txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode);

// 签名;
PreparedTransaction ptx = txTpl.prepare();

ptx.sign(adminKey);

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

System.out.println(txResp.isSuccess());

// 首先注册一个数据账户
BlockchainKeypair dataAccount = createDataAccount();

String dataAddress = dataAccount.getAddress().toBase58();

Bytes contractAddress = contractDeployKey.getAddress();

// 创建两个账号:
String account0 = "jd_zhangsan", account1 = "jd_lisi";
long account0Money = 3000L, account1Money = 2000L;
// 创建两个账户
// 使用KV创建一个账户
System.out.println(create(dataAddress, account0, account0Money, false, null));
// 使用合约创建一个账户
System.out.println(create(dataAddress, account1, account1Money, true, contractAddress));

// 转账,使得双方钱达到一致
System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress));

// 读取当前结果
System.out.println(read(dataAddress, account0, contractAddress));
System.out.println(read(dataAddress, account1, contractAddress));

// 读取账号历史信息
System.out.println(readAll(dataAddress, account0, contractAddress));
System.out.println(readAll(dataAddress, account1, contractAddress));
}

private String readAll(String address, String account, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> {
transferContract.readAll(address, account);
return transferContract;
});
commit(txTpl);
return eventResult.get();
}

private long read(String address, String account, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
EventResult<Long> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> {
transferContract.read(address, account);
return transferContract;
});
commit(txTpl);
return eventResult.get();
}

private String transfer(String address, String from, String to, long money, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> {
transferContract.transfer(address, from, to, money);
return transferContract;
});
commit(txTpl);
return eventResult.get();
}


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

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

private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
if (useContract) {
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> {
transferContract.create(address, account, money);
return transferContract;
});
commit(txTpl);
return eventResult.get();
} else {
// 通过KV创建
txTpl.dataAccount(address).setInt64(account, money, -1);
TransactionResponse txResp = commit(txTpl);
return account + money;
}
}

private TransactionResponse commit(TransactionTemplate txTpl) {
PreparedTransaction ptx = txTpl.prepare();
ptx.sign(adminKey);
return ptx.commit();
}
byte[] contractCode = readChainCodes("transfer.jar");

// 生成一个合约账号
BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate();

txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode);

// 签名;
PreparedTransaction ptx = txTpl.prepare();

ptx.sign(adminKey);

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

System.out.println(txResp.isSuccess());

// 首先注册一个数据账户
BlockchainKeypair dataAccount = createDataAccount();

String dataAddress = dataAccount.getAddress().toBase58();

Bytes contractAddress = contractDeployKey.getAddress();

// 创建两个账号:
String account0 = "jd_zhangsan", account1 = "jd_lisi";
long account0Money = 3000L, account1Money = 2000L;
// 创建两个账户
// 使用KV创建一个账户
System.out.println(create(dataAddress, account0, account0Money, false, null));
// 使用合约创建一个账户
System.out.println(create(dataAddress, account1, account1Money, true, contractAddress));

// 转账,使得双方钱达到一致
System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress));

// 读取当前结果
System.out.println(read(dataAddress, account0, contractAddress));
System.out.println(read(dataAddress, account1, contractAddress));

// 读取账号历史信息
System.out.println(readAll(dataAddress, account0, contractAddress));
System.out.println(readAll(dataAddress, account1, contractAddress));
}

private String readAll(String address, String account, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
ReturnValue<String> result = decode(transferContract.readAll(address, account));
commit(txTpl);
return result.get();
}

private long read(String address, String account, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
ReturnLongValue result = decode(transferContract.read(address, account));
commit(txTpl);
return result.get();
}

private String transfer(String address, String from, String to, long money, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
ReturnValue<String> result = decode(transferContract.transfer(address, from, to, money));
commit(txTpl);
return result.get();
}

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

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

private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) {
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
if (useContract) {
// 使用合约创建
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class);
ReturnValue<String> result = decode(transferContract.create(address, account, money));
commit(txTpl);
return result.get();
} else {
// 通过KV创建
txTpl.dataAccount(address).setInt64(account, money, -1);
TransactionResponse txResp = commit(txTpl);
return account + money;
}
}

private TransactionResponse commit(TransactionTemplate txTpl) {
PreparedTransaction ptx = txTpl.prepare();
ptx.sign(adminKey);
return ptx.commit();
}
}

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

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

import com.jd.blockchain.contract.ContractSerializeUtils;
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;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.contract.EventResult;
import com.jd.blockchain.contract.ReadContract;
import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInitOperation;
import com.jd.blockchain.ledger.OperationResult;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionState;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.UserRegisterOperation;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.storage.service.DbConnection;
import com.jd.blockchain.storage.service.DbConnectionFactory;
import com.jd.blockchain.tools.initializer.LedgerBindingConfig;
import com.jd.blockchain.transaction.ContractEventExecutor;
import static com.jd.blockchain.transaction.ContractReturns.*;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.concurrent.ThreadInvoker;
import com.jd.blockchain.utils.net.NetworkAddress;
@@ -576,10 +587,7 @@ public class IntegrationBase {

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

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

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

@@ -587,10 +595,7 @@ public class IntegrationBase {

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

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

// 签名;
PreparedTransaction contractPtx = txContract.prepare();
@@ -602,8 +607,8 @@ public class IntegrationBase {
OperationResult[] operationResults = readTxResp.getOperationResults();

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


// 打印结果


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

@@ -11,6 +11,7 @@ import com.jd.blockchain.contract.EventProcessingAware;
import com.jd.blockchain.contract.LedgerContext;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.TransactionRequest;
@@ -33,7 +34,7 @@ public class MockerContractExeHandle implements OperationHandle {
private HashDigest ledgerHash;

@Override
public byte[] process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext,
public BytesValue process(Operation op, LedgerDataSet dataset, TransactionRequestContext requestContext,
LedgerDataSet previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) {
ContractEventSendOperation contractOP = (ContractEventSendOperation) op;

@@ -76,11 +77,6 @@ public class MockerContractExeHandle implements OperationHandle {
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);


Loading…
Cancel
Save