Browse Source

Merge commit '845e7a4537adee26cbf870096a0f22ec7b7c9e77' into feature/crypto-spi

tags/1.0.0
zhanglin33 5 years ago
parent
commit
e832bae1d7
81 changed files with 4883 additions and 372 deletions
  1. +10
    -0
      source/base/src/main/java/com/jd/blockchain/consts/DataCodes.java
  2. +1
    -1
      source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataContract.java
  3. +53
    -64
      source/contract/contract-jvm/src/main/java/com/jd/blockchain/contract/jvm/JavaContractCode.java
  4. +3
    -3
      source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM2Utils.java
  5. +2
    -1
      source/deployment/deployment-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java
  6. +2
    -1
      source/deployment/deployment-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java
  7. +1
    -8
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantCertData.java
  8. +5
    -4
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java
  9. +16
    -16
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java
  10. +3
    -6
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java
  11. +196
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/contract/ContractSerializeUtils.java
  12. +20
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BIG_INT.java
  13. +19
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_BINARY.java
  14. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT16.java
  15. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT32.java
  16. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT64.java
  17. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_INT8.java
  18. +18
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/CONTRACT_TEXT.java
  19. +20
    -0
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractBizContent.java
  20. +12
    -5
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java
  21. +11
    -10
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java
  22. +53
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxyBuilder.java
  23. +70
    -17
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java
  24. +15
    -4
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/EventOperator.java
  25. +13
    -10
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java
  26. +7
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxTemplate.java
  27. +1
    -1
      source/peer/src/test/java/test/com/jd/blockchain/peer/web/ControllerTestConfiguration.java
  28. +2
    -2
      source/peer/src/test/java/test/com/jd/blockchain/peer/web/LedgerInitializingTest.java
  29. +2
    -2
      source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java
  30. +281
    -0
      source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java
  31. +8
    -0
      source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java
  32. +93
    -0
      source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java
  33. +53
    -0
      source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java
  34. +20
    -13
      source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java
  35. +354
    -0
      source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java
  36. +8
    -8
      source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java
  37. BIN
      source/sdk/sdk-samples/src/test/resources/contract.jar
  38. +13
    -0
      source/sdk/sdk-samples/src/test/resources/sys-contract.properties
  39. +91
    -108
      source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java
  40. +57
    -18
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBase.java
  41. +15
    -26
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest2.java
  42. +106
    -0
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest4Contract.java
  43. +14
    -35
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTestAll4Redis.java
  44. +39
    -0
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract.java
  45. +44
    -0
      source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java
  46. BIN
      source/test/test-integration/src/test/resources/contract.jar
  47. +0
    -1
      source/test/test-integration/src/test/resources/ledger_init_test_web2.init
  48. +2
    -1
      source/tools/pom.xml
  49. +1
    -1
      source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java
  50. +1
    -1
      source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LocalConfig.java
  51. +44
    -0
      source/tools/tools-mocker/pom.xml
  52. +342
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java
  53. +461
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java
  54. +22
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/LedgerInitWebConfiguration.java
  55. +67
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/MockerConstant.java
  56. +32
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/PresetAnswerPrompter.java
  57. +17
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContract.java
  58. +81
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java
  59. +14
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java
  60. +41
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java
  61. +54
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/KvData.java
  62. +38
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/ResponseData.java
  63. +136
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java
  64. +189
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerNodeHandler.java
  65. +51
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerOperationHandleRegister.java
  66. +216
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerServiceHandler.java
  67. +75
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/GatewayNodeRunner.java
  68. +106
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/NodeWebContext.java
  69. +62
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/PeerNodeRunner.java
  70. +80
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java
  71. +34
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ExecutorProxy.java
  72. +167
    -0
      source/tools/tools-mocker/src/main/resources/bftsmart.config
  73. +167
    -0
      source/tools/tools-mocker/src/main/resources/bftsmart4.config
  74. +208
    -0
      source/tools/tools-mocker/src/main/resources/bftsmart8.config
  75. +72
    -0
      source/tools/tools-mocker/src/main/resources/ledger4.init
  76. +125
    -0
      source/tools/tools-mocker/src/main/resources/ledger8.init
  77. +50
    -0
      source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java
  78. +54
    -0
      source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/MockTest.java
  79. +47
    -0
      source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java
  80. +1
    -1
      source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java
  81. +3
    -1
      source/utils/utils-common/src/main/java/com/jd/blockchain/utils/security/DESUtils.java

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

@@ -79,7 +79,17 @@ public interface DataCodes {

public static final int DATA = 0x900;

//contract related;
public static final int CONTRACT = 0xA00;
public static final int CONTRACT_INT8 = 0xA01;
public static final int CONTRACT_INT16 = 0xA02;
public static final int CONTRACT_INT32 = 0xA03;
public static final int CONTRACT_INT64 = 0xA04;
public static final int CONTRACT_TEXT = 0xA05;
public static final int CONTRACT_BINARY = 0xA06;
public static final int CONTRACT_BIG_INT = 0xA07;
//...0xA19
public static final int CONTRACT_BIZ_CONTENT = 0xA20;

public static final int HASH = 0xB00;



+ 1
- 1
source/binary-proto/src/main/java/com/jd/blockchain/binaryproto/DataContract.java View File

@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
* @author huanghaiquan
*
*/
@Target({ ElementType.TYPE })
@Target({ ElementType.TYPE, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface DataContract {



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

@@ -1,24 +1,24 @@
package com.jd.blockchain.contract.jvm;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import com.jd.blockchain.contract.ContractEvent;
import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.contract.ContractEventContext;
import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.contract.engine.ContractCode;
import com.jd.blockchain.runtime.Module;
import com.jd.blockchain.utils.BaseConstant;
import com.jd.blockchain.transaction.ContractType;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.IllegalDataException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.List;

/**
* contract code based jvm
* @author zhaogw
*
* @author zhaogw
*/
public class JavaContractCode implements ContractCode {
private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class);
@@ -26,7 +26,9 @@ public class JavaContractCode implements ContractCode {
private Bytes address;
private long version;
private ContractEventContext contractEventContext;

private ContractType contractType;

public JavaContractCode(Bytes address, long version, Module codeModule) {
this.address = address;
this.version = version;
@@ -37,7 +39,7 @@ public class JavaContractCode implements ContractCode {
public Bytes getAddress() {
return address;
}
@Override
public long getVersion() {
return version;
@@ -46,75 +48,62 @@ public class JavaContractCode implements ContractCode {
@Override
public void processEvent(ContractEventContext eventContext) {
this.contractEventContext = eventContext;
codeModule.execute(new ContractThread());
codeModule.execute(new ContractExecution());
}

class ContractThread implements Runnable{
public void run(){
private Object resolveArgs(byte[] args, List<DataContract> dataContractList) {
if(args == null || args.length == 0){
return null;
}
return ContractSerializeUtils.deserializeMethodParam(args,dataContractList);
}

class ContractExecution implements Runnable {
public void run() {
LOGGER.info("ContractThread execute().");
try {
//执行预处理;
// 执行预处理;
long startTime = System.currentTimeMillis();

String contractClassName = codeModule.getMainClass();
Class myClass = codeModule.loadClass(contractClassName);
Object contractMainClassObj = myClass.newInstance();//合约主类生成的类实例;
Object contractMainClassObj = myClass.newInstance();// 合约主类生成的类实例;

Method beforeMth_ = myClass.getMethod("beforeEvent",codeModule.loadClass(ContractEventContext.class.getName()));
ReflectionUtils.invokeMethod(beforeMth_,contractMainClassObj,contractEventContext);
LOGGER.info("beforeEvent,耗时:"+(System.currentTimeMillis()-startTime));
Method beforeMth_ = myClass.getMethod("beforeEvent",
codeModule.loadClass(ContractEventContext.class.getName()));
ReflectionUtils.invokeMethod(beforeMth_, contractMainClassObj, contractEventContext);
LOGGER.info("beforeEvent,耗时:" + (System.currentTimeMillis() - startTime));

Method eventMethod = this.getMethodByAnno(contractMainClassObj,contractEventContext.getEvent());
// Method eventMethod = this.getMethodByAnno(contractMainClassObj, contractEventContext.getEvent());
startTime = System.currentTimeMillis();

ReflectionUtils.invokeMethod(eventMethod,contractMainClassObj,contractEventContext);
// 反序列化参数;
contractType = ContractType.resolve(myClass);
Method handleMethod = contractType.getHandleMethod(contractEventContext.getEvent());
if (handleMethod == null){
throw new IllegalDataException("don't get this method by it's @ContractEvent.");
}
Object args = resolveArgs(contractEventContext.getArgs(),
contractType.getDataContractMap().get(handleMethod));

LOGGER.info("合约执行,耗时:"+(System.currentTimeMillis()-startTime));
Object[] params = null;
if(args.getClass().isArray()){
params = (Object[])args;
}
ReflectionUtils.invokeMethod(handleMethod, contractMainClassObj, params);

LOGGER.info("合约执行,耗时:" + (System.currentTimeMillis() - startTime));

Method mth2 = myClass.getMethod("postEvent");
startTime = System.currentTimeMillis();
ReflectionUtils.invokeMethod(mth2,contractMainClassObj);
LOGGER.info("postEvent,耗时:"+(System.currentTimeMillis()-startTime));
ReflectionUtils.invokeMethod(mth2, contractMainClassObj);
LOGGER.info("postEvent,耗时:" + (System.currentTimeMillis() - startTime));
} catch (NoSuchMethodException e) {
e.printStackTrace();
throw new IllegalArgumentException(e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}

//得到当前类中相关方法和注解对应关系;
Method getMethodByAnno(Object classObj, String eventName){
Class<?> c = classObj.getClass();
Class <ContractEvent> contractEventClass = null;
try {
contractEventClass = (Class <ContractEvent>)c.getClassLoader().loadClass(ContractEvent.class.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method[] classMethods = c.getMethods();
Map<Method, Annotation[]> methodAnnoMap = new HashMap<Method, Annotation[]>();
Map<String,Method> annoMethodMap = new HashMap<String,Method>();
for(int i = 0;i<classMethods.length;i++){
Annotation[] a = classMethods[i].getDeclaredAnnotations();
methodAnnoMap.put(classMethods[i], a);
//如果当前方法中包含@ContractEvent注解,则将其放入Map;
for(Annotation annotation_ : a){
//如果是合同事件类型,则放入map;
if(classMethods[i].isAnnotationPresent(contractEventClass)){
Object obj = classMethods[i].getAnnotation(contractEventClass);
String annoAllName = obj.toString();
//format:@com.jd.blockchain.contract.model.ContractEvent(name=transfer-asset)
String eventName_ = obj.toString().substring(BaseConstant.CONTRACT_EVENT_PREFIX.length(),annoAllName.length()-1);
annoMethodMap.put(eventName_,classMethods[i]);
break;
}
}
}
if(annoMethodMap.containsKey(eventName)){
return annoMethodMap.get(eventName);
}else {
return null;
throw new IllegalDataException(e.getMessage());
}
}
}

}

+ 3
- 3
source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM2Utils.java View File

@@ -1,5 +1,6 @@
package com.jd.blockchain.crypto.utils.sm;

import com.jd.blockchain.utils.io.BytesUtils;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
@@ -98,7 +99,7 @@ public class SM2Utils {
public static byte[] sign(byte[] data, byte[] privateKey, SecureRandom random, String ID){

ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(new BigInteger(1,privateKey), DOMAIN_PARAMS);
CipherParameters params = new ParametersWithID(new ParametersWithRandom(privKey,random),ID.getBytes());
CipherParameters params = new ParametersWithID(new ParametersWithRandom(privKey,random), BytesUtils.toBytes(ID));

return sign(data,params);
}
@@ -152,8 +153,7 @@ public class SM2Utils {

ECPoint pubKeyPoint = resolvePubKeyBytes(publicKey);
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(pubKeyPoint, DOMAIN_PARAMS);
ParametersWithID params = new ParametersWithID(pubKey,ID.getBytes());

ParametersWithID params = new ParametersWithID(pubKey, BytesUtils.toBytes(ID));
return verify(data,params,signature);
}



+ 2
- 1
source/deployment/deployment-gateway/src/main/java/com/jd/blockchain/gateway/boot/GatewayBooter.java View File

@@ -6,6 +6,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -49,7 +50,7 @@ public class GatewayBooter {
bootInfos.add(String.format("GW_BOOT_PID = [%s] \r\n", pid));
try (FileOutputStream outputStream = new FileOutputStream(pidFile)) {
for (String bootInfo : bootInfos) {
outputStream.write(bootInfo.getBytes());
outputStream.write(bootInfo.getBytes(StandardCharsets.UTF_8));
}
outputStream.flush();
}


+ 2
- 1
source/deployment/deployment-peer/src/main/java/com/jd/blockchain/boot/peer/PeerBooter.java View File

@@ -6,6 +6,7 @@ import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -70,7 +71,7 @@ public class PeerBooter {
bootInfos.add(String.format("PEER_BOOT_PID = [%s] \r\n", pid));
try (FileOutputStream outputStream = new FileOutputStream(pidFile)) {
for (String bootInfo : bootInfos) {
outputStream.write(bootInfo.getBytes());
outputStream.write(bootInfo.getBytes(StandardCharsets.UTF_8));
}
outputStream.flush();
}


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

@@ -12,7 +12,6 @@ import com.jd.blockchain.ledger.ParticipantNode;
public class ParticipantCertData implements ParticipantNode {
private int id;
private String address;
private String name;
private PubKey pubKey;
@@ -21,6 +20,7 @@ public class ParticipantCertData implements ParticipantNode {
}
public ParticipantCertData(ParticipantNode participantNode) {
this.id = participantNode.getId();
this.address = participantNode.getAddress();
this.name = participantNode.getName();
this.pubKey = participantNode.getPubKey();
@@ -31,8 +31,6 @@ public class ParticipantCertData implements ParticipantNode {
this.name = name;
this.pubKey = pubKey;
}
@Override
public String getAddress() {
@@ -49,16 +47,11 @@ public class ParticipantCertData implements ParticipantNode {
return pubKey;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}

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

@@ -253,10 +253,10 @@ public class ContractLedgerContext implements LedgerContext {
public boolean isJson(String str) {
boolean result = false;
try {
Object obj=JSON.parse(str);
Object obj = JSON.parse(str);
result = true;
} catch (Exception e) {
result=false;
result = false;
}
return result;
}
@@ -278,10 +278,11 @@ public class ContractLedgerContext implements LedgerContext {
public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) {
BytesValue bytesValue;
if (isJson(value)) {
bytesValue = new BytesValueEntry(BytesValueType.JSON, value.getBytes());

bytesValue = new BytesValueEntry(BytesValueType.JSON, BytesUtils.toBytes(value));
}
else {
bytesValue = new BytesValueEntry(BytesValueType.TEXT, value.getBytes());
bytesValue = new BytesValueEntry(BytesValueType.TEXT, BytesUtils.toBytes(value));
}
this.op = new SingleKVSetOpTemplate(key, bytesValue, expVersion);
generatedOpList.add(op);


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

@@ -49,22 +49,22 @@ public class LedgerTestUtils {
return txHandle.txRequest;
}

public static TransactionRequest createContractEventTxRequest(HashDigest ledgerHash,
SignatureFunction signatureFunction, String contractAddress, String event, byte[] args) {
TxHandle txHandle = new TxHandle();
TxTemplate txTemp = new TxTemplate(ledgerHash, txHandle);
txTemp.contractEvents().send(contractAddress, event, args);
AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair();
PubKey pubKey = cryptoKeyPair.getPubKey();
txTemp.users().register(new BlockchainIdentityData(pubKey));
PreparedTransaction ptx = txTemp.prepare();
ptx.sign(cryptoKeyPair);
ptx.commit();
return txHandle.txRequest;
}
// public static TransactionRequest createContractEventTxRequest(HashDigest ledgerHash,
// SignatureFunction signatureFunction, String contractAddress, String event, byte[] args) {
// TxHandle txHandle = new TxHandle();
//
// TxTemplate txTemp = new TxTemplate(ledgerHash, txHandle);
//
// txTemp.contractEvents().send(contractAddress, event, args);
//
// AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair();
// PubKey pubKey = cryptoKeyPair.getPubKey();
// txTemp.users().register(new BlockchainIdentityData(pubKey));
// PreparedTransaction ptx = txTemp.prepare();
// ptx.sign(cryptoKeyPair);
// ptx.commit();
// return txHandle.txRequest;
// }

public static TransactionStagedSnapshot generateRandomSnapshot() {
TransactionStagedSnapshot txDataSnapshot = new TransactionStagedSnapshot();


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

@@ -6,14 +6,12 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.security.KeyFactory;
import java.util.Random;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.HashDigest;

import org.junit.Test;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.ContractCodeDeployOperation;
@@ -25,7 +23,6 @@ import com.jd.blockchain.ledger.DataAccountRegisterOperation;
import com.jd.blockchain.ledger.DigitalSignature;
import com.jd.blockchain.ledger.LedgerTransaction;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.TransactionBuilder;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.TransactionRequestBuilder;
import com.jd.blockchain.ledger.TransactionState;
@@ -62,7 +59,7 @@ public class TransactionSetTest {

// Build transaction request;
HashDigest ledgerHash = LedgerTestUtils.generateRandomHash();
TransactionBuilder txBuilder = new TxBuilder(ledgerHash);
TxBuilder txBuilder = new TxBuilder(ledgerHash);

BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate();
UserRegisterOperation userRegOp = txBuilder.users().register(userKey.getIdentity());


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

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

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.consts.DataCodes;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.IllegalDataException;
import org.springframework.util.ReflectionUtils;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author zhaogw
* date 2019/5/16 18:05
*/
public class ContractSerializeUtils {
public static Map<Integer, Class<?>> DATA_CONTRACT_MAP = new HashMap<>();
public static final Integer[] PRIMITIVE_DATA_CODES = {DataCodes.CONTRACT_INT8, DataCodes.CONTRACT_INT16, DataCodes.CONTRACT_INT32,
DataCodes.CONTRACT_INT64, DataCodes.CONTRACT_BIG_INT,DataCodes.CONTRACT_TEXT, DataCodes.CONTRACT_BINARY };

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

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

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

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

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

return result;
}


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

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

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

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

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

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

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

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

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

import java.math.BigDecimal;

/**
* contract args for BIG_INT;
* @author zhaogw
* date 2019-05-17 15:32
*/
@DataContract(code = DataCodes.CONTRACT_BIG_INT)
public interface CONTRACT_BIG_INT {

@DataField(order=2, primitiveType= PrimitiveType.BIG_INT)
BigDecimal getValue();
}

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

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

import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.binaryproto.DataField;
import com.jd.blockchain.binaryproto.PrimitiveType;
import com.jd.blockchain.consts.DataCodes;
import com.jd.blockchain.utils.Bytes;

/**
* contract args for Binary;
* @author zhaogw
* date 2019-05-17 15:32
*/
@DataContract(code = DataCodes.CONTRACT_BINARY)
public interface CONTRACT_BINARY {

@DataField(order=2, primitiveType= PrimitiveType.BYTES)
Bytes getValue();
}

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

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

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

/**
* contract args for int16;
* @author zhaogw
* date 2019-05-17 15:32
*/
@DataContract(code = DataCodes.CONTRACT_INT16)
public interface CONTRACT_INT16 {

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

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

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

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

/**
* contract args for int32;
* @author zhaogw
* date 2019-05-17 15:32
*/
@DataContract(code = DataCodes.CONTRACT_INT32)
public interface CONTRACT_INT32 {

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

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

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

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

/**
* contract args for int64;
* @author zhaogw
* date 2019-05-17 15:32
*/
@DataContract(code = DataCodes.CONTRACT_INT64)
public interface CONTRACT_INT64 {

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

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

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

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

/**
* contract args for int8;
* @author zhaogw
* date 2019-05-17 15:32
*/
@DataContract(code = DataCodes.CONTRACT_INT8)
public interface CONTRACT_INT8 {

@DataField(order=2, primitiveType= PrimitiveType.INT8)
Byte getValue();
}

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

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

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

/**
* contract args for String;
* @author zhaogw
* date 2019-05-17 15:32
*/
@DataContract(code = DataCodes.CONTRACT_TEXT)
public interface CONTRACT_TEXT {

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

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

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

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

/**
* build complex param Object, provide more String attributes;
*/
@DataContract(code = DataCodes.CONTRACT_BIZ_CONTENT)
public interface ContractBizContent {
/**
* param lists;
* @return
*/
@DataField(order = 1, list = true, primitiveType = PrimitiveType.TEXT, genericContract = true)
String[] getAttrs();

}

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

@@ -31,7 +31,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl();
private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter();
private UserRegisterOperationBuilder userRegOpBuilder = new UserRegisterOperationBuilderFilter();
@@ -42,6 +41,8 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
private ContractEventSendOperationBuilder contractEventSendOpBuilder = new ContractEventSendOperationBuilderFilter();
private ContractInvocationProxyBuilder contractInvoProxyBuilder = new ContractInvocationProxyBuilder();
private List<Operation> operationList = new ArrayList<>();
@Override
@@ -74,15 +75,18 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
return contractCodeDeployOpBuilder;
}
@Override
public ContractEventSendOperationBuilder contractEvents() {
return contractEventSendOpBuilder;
}
@Override
public <T> T contract(String address, Class<T> contractIntf) {
// TODO Auto-generated method stub
return null;
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder);
}
@Override
public <T> T contract(Bytes address, Class<T> contractIntf) {
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder);
}
public Collection<Operation> getOperations() {
@@ -153,6 +157,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
}
return this;
}
@Override
public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) {
innerBuilder.set(key, value, expVersion);
@@ -162,6 +167,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
}
return this;
}
@Override
public DataAccountKVSetOperationBuilder set(String key, long value, long expVersion) {
innerBuilder.set(key, value, expVersion);
@@ -171,6 +177,7 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
}
return this;
}
@Override
public DataAccountKVSetOperationBuilder set(String key, Bytes value, long expVersion) {
innerBuilder.set(key, value, expVersion);


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

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

import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils;
import com.jd.blockchain.utils.IllegalDataException;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
@@ -19,17 +20,15 @@ public class ContractInvocationProxy implements InvocationHandler {
public ContractInvocationProxy(Bytes contractAddress, ContractType contractType,
ContractEventSendOperationBuilder sendOpBuilder) {
this.contractAddress = contractAddress;
if(contractType == null){
throw new IllegalDataException("contractType == null, no invoke really.");
}
this.contractType = contractType;
this.sendOpBuilder = sendOpBuilder;
}

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

if(contractType == null){
return "contractType == null, no invoke really.";
}

String event = contractType.getEvent(method);
if (event == null) {
// 适配 Object 对象的方法;
@@ -39,15 +38,17 @@ public class ContractInvocationProxy implements InvocationHandler {
// hashCode 方法;
}
// 合约方法;
byte[] argBytes = serializeArgs(args);
byte[] argBytes = serializeArgs(args,method);
sendOpBuilder.send(contractAddress, event, argBytes);

// TODO: 暂时未考虑有返回值的情况;
return null;
}

private byte[] serializeArgs(Object[] args) {
// TODO 根据方法参数的定义序列化参数;
return BinarySerializeUtils.serialize(args);
private byte[] serializeArgs(Object[] args, Method method) {
if(args == null || args.length==0){
return null;
}
return ContractSerializeUtils.serializeMethodParam(args,contractType.getDataContractMap().get(method));
}
}

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

@@ -1,6 +1,58 @@
package com.jd.blockchain.transaction;
class ContractInvocationProxyBuilder {
import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;
import com.jd.blockchain.utils.BaseConstant;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.IllegalDataException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ContractInvocationProxyBuilder {
private Map<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>();
public <T> T create(String address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) {
return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder);
}
@SuppressWarnings("unchecked")
public <T> T create(Bytes address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) {
ContractType contractType = resolveContractType(contractIntf);
ContractInvocationProxy proxyHandler = new ContractInvocationProxy(address, contractType,
contractEventBuilder);
T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { contractIntf }, proxyHandler);
return (T) proxy;
}
private ContractType resolveContractType(Class<?> contractIntf) {
ContractType contractType = contractTypes.get(contractIntf);
if (contractType != null) {
return contractType;
}
// TODO 检查返回值类型;
ContractType contractType1 = ContractType.resolve(contractIntf);
contractTypes.put(contractIntf,contractType1);
return contractType1;
}
/**
* is contractType really? identified by @Contract;
* @param contractIntf
* @return
*/
private boolean isContractType(Class<?> contractIntf) {
Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class);
return annotation != null ? true : false;
}
}

+ 70
- 17
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractType.java View File

@@ -1,26 +1,36 @@
package com.jd.blockchain.transaction;

import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;
import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.contract.ContractSerializeUtils;
import com.jd.blockchain.utils.IllegalDataException;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.SortedMap;
import java.util.*;

public class ContractType {

class ContractType {
private String name;
private SortedMap<String, Method> events;
private SortedMap<Method, String> handleMethods;
private Map<String, Method> events = new HashMap<>();
private Map<Method, String> handleMethods = new HashMap<>();
private Map<Method, List<DataContract>> dataContractMap = new HashMap<>();

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

public Map<Method, List<DataContract>> getDataContractMap() {
return dataContractMap;
}

/**
* 返回指定方法声明的事件;<br>
*
@@ -29,7 +39,7 @@ class ContractType {
* @param method
* @return
*/
String getEvent(Method method) {
public String getEvent(Method method) {
return handleMethods.get(method);
}

@@ -41,16 +51,59 @@ class ContractType {
* @param event
* @return
*/
Method getHandleMethod(String event) {
public Method getHandleMethod(String event) {
return events.get(event);
}
private ContractType() {
}
// public static ContractType resolve(Class<?> contractIntf) {
//
// }

public static ContractType resolve(Class<?> contractIntf){
ContractType contractType = new ContractType();

Annotation annotation = contractIntf.getDeclaredAnnotation(Contract.class);

//contains: @Contract?
boolean isContractType = annotation != null ? true : false;
if(!isContractType){
throw new IllegalDataException("is not Contract Type, becaust there is not @Contract.");
}

//contractIntf contains @Contract and @ContractEvent;
Method[] classMethods = contractIntf.getDeclaredMethods();
for (Method method : classMethods) {
// if current method contains @ContractEvent,then put it in this map;
ContractEvent contractEvent = method.getAnnotation(ContractEvent.class);
if (contractEvent != null) {
String eventName_ = contractEvent.name();
//if annoMethodMap has contained the eventName, too many same eventNames exists probably, say NO!
if(contractType.events.containsKey(eventName_)){
throw new ContractException("there is repeat definition of contractEvent to @ContractEvent.");
}
//check param's type is fit for need.
Class<?>[] paramTypes = method.getParameterTypes();
List dataContractList = new ArrayList();
for(Class<?> curParamType : paramTypes){
DataContract dataContract = ContractSerializeUtils.parseDataContract(curParamType);
dataContractList.add(dataContract);
}
if(dataContractList.size()>0){
contractType.dataContractMap.put(method,dataContractList);
}

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

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

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

@@ -1,14 +1,25 @@
package com.jd.blockchain.transaction;

import com.jd.blockchain.utils.Bytes;

public interface EventOperator {

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

/**
* 部署合约;
* 创建调用合约的代理实例
*
* @param address
* @param contractIntf
* @return
*/
@Deprecated
ContractEventSendOperationBuilder contractEvents();
<T> T contract(String address, Class<T> contractIntf);
/**
* 创建调用合约的代理实例;
@@ -17,6 +28,6 @@ public interface EventOperator {
* @param contractIntf
* @return
*/
<T> T contract(String address, Class<T> contractIntf);
<T> T contract(Bytes address, Class<T> contractIntf);

}

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

@@ -19,7 +19,7 @@ public class TxBuilder implements TransactionBuilder {
private BlockchainOperationFactory opFactory = new BlockchainOperationFactory();

private static final String DEFAULT_HASH_ALGORITHM = "SHA256";
private HashDigest ledgerHash;

public TxBuilder(HashDigest ledgerHash) {
@@ -36,16 +36,16 @@ public class TxBuilder implements TransactionBuilder {
TransactionContent txContent = prepareContent();
return new TxRequestBuilder(txContent);
}
@Override
public TransactionContent prepareContent() {
TxContentBlob txContent = new TxContentBlob(ledgerHash);
txContent.addOperations(opFactory.getOperations());
byte[] contentBodyBytes = BinaryProtocol.encode(txContent, TransactionContentBody.class);
HashDigest contentHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(contentBodyBytes);
txContent.setHash(contentHash);
return txContent;
}

@@ -53,7 +53,7 @@ public class TxBuilder implements TransactionBuilder {
public LedgerInitOperationBuilder ledgers() {
return opFactory.ledgers();
}
@Override
public UserRegisterOperationBuilder users() {
return opFactory.users();
@@ -63,7 +63,7 @@ public class TxBuilder implements TransactionBuilder {
public DataAccountRegisterOperationBuilder dataAccounts() {
return opFactory.dataAccounts();
}
@Override
public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) {
return opFactory.dataAccount(accountAddress);
@@ -79,15 +79,18 @@ public class TxBuilder implements TransactionBuilder {
return opFactory.contracts();
}

@Override
public ContractEventSendOperationBuilder contractEvents() {
return opFactory.contractEvents();
}

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

@Override
public <T> T contract(String address, Class<T> contractIntf) {
// TODO Auto-generated method stub
throw new IllegalStateException("Not implemented.");
return opFactory.contract(address, contractIntf);
}

}

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

@@ -53,9 +53,14 @@ public class TxTemplate implements TransactionTemplate {
return txBuilder.contracts();
}
// @Override
// public ContractEventSendOperationBuilder contractEvents() {
// return txBuilder.contractEvents();
// }
@Override
public ContractEventSendOperationBuilder contractEvents() {
return txBuilder.contractEvents();
public <T> T contract(Bytes address, Class<T> contractIntf) {
return txBuilder.contract(address, contractIntf);
}
@Override


+ 1
- 1
source/peer/src/test/java/test/com/jd/blockchain/peer/web/ControllerTestConfiguration.java View File

@@ -1,6 +1,6 @@
//package test.com.jd.blockchain.peer.web;
//
//import org.springframework.boot.test.mock.mockito.MockBean;
//import org.springframework.boot.test.mocker.mockito.MockBean;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//


+ 2
- 2
source/peer/src/test/java/test/com/jd/blockchain/peer/web/LedgerInitializingTest.java View File

@@ -2,7 +2,7 @@
//
//import static org.mockito.Matchers.any;
//import static org.mockito.Matchers.anyInt;
//import static org.mockito.Mockito.mock;
//import static org.mockito.Mockito.mocker;
//import static org.mockito.Mockito.spy;
//import static org.mockito.Mockito.when;
//
@@ -211,7 +211,7 @@
// //when(keystoreService.getBlockchainKey(key.getAddress())).thenReturn(keyInfo);
// //when(keystoreService.sign(any(), key.getAddress())).then(answerSignature(key));
//
// msgBroadcaster = mock(MessageBroadcaster.class);
// msgBroadcaster = mocker(MessageBroadcaster.class);
//
// LedgerInitializingController ctrl = new LedgerInitializingController(peerSettings, keystoreService,
// ledgerService, msgBroadcaster);


+ 2
- 2
source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java View File

@@ -35,8 +35,8 @@ public class BlockchainServiceProxyTest {
//
// ArgCaptorMatcher<TransactionRequest> txReqCaptor = new ArgCaptorMatcher<>();
//
// TransactionService consensusService = Mockito.mock(TransactionService.class);
// BlockchainQueryService queryService = Mockito.mock(BlockchainQueryService.class);
// TransactionService consensusService = Mockito.mocker(TransactionService.class);
// BlockchainQueryService queryService = Mockito.mocker(BlockchainQueryService.class);
//
// HashDigest txContentHash =CryptoUtils.hash(CryptoAlgorithm.SHA_256).hash(UUID.randomUUID().toString().getBytes("UTF-8"));
// TxResponseMessage expectedResponse = new TxResponseMessage(txContentHash);


+ 281
- 0
source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java View File

@@ -0,0 +1,281 @@
/**
* Copyright: Copyright 2016-2020 JD.COM All Right Reserved
* FileName: com.jd.blockchain.sdk.client.ClientOperationUtil
* Author: shaozhuguang
* Department: Y事业部
* Date: 2019/3/27 下午4:12
* Description:
*/
package com.jd.blockchain.sdk.client;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jd.blockchain.crypto.CryptoProvider;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.transaction.*;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.codec.HexUtils;
import com.jd.blockchain.utils.io.BytesSlice;
import com.jd.blockchain.utils.io.BytesUtils;
import org.apache.commons.codec.binary.Base64;

import java.lang.reflect.Field;

/**
*
* @author shaozhuguang
* @create 2019/3/27
* @since 1.0.0
*/

public class ClientOperationUtil {

public static Operation read(Operation operation) {

try {
// Class
Class<?> clazz = operation.getClass();
Field field = clazz.getSuperclass().getDeclaredField("h");
field.setAccessible(true);
Object object = field.get(operation);
if (object instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) object;
if (jsonObject.containsKey("accountID")) {
return convertDataAccountRegisterOperation(jsonObject);
} else if (jsonObject.containsKey("userID")) {
return convertUserRegisterOperation(jsonObject);
} else if (jsonObject.containsKey("contractID")) {
return convertContractCodeDeployOperation(jsonObject);
} else if (jsonObject.containsKey("writeSet")) {
return convertDataAccountKVSetOperation(jsonObject);
} else if (jsonObject.containsKey("initSetting")) {
return convertLedgerInitOperation(jsonObject);
} else if (jsonObject.containsKey("contractAddress")) {
return convertContractEventSendOperation(jsonObject);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}

return null;
}

public static Object readValueByBytesValue(BytesValue bytesValue) {
BytesValueType dataType = bytesValue.getType();
BytesSlice saveVal = bytesValue.getValue();
Object showVal;
switch (dataType) {
case BYTES:
// return hex
showVal = HexUtils.encode(saveVal.getBytesCopy());
break;
case TEXT:
case JSON:
showVal = saveVal.getString();
break;
case INT64:
showVal = saveVal.getLong();
break;
default:
showVal = HexUtils.encode(saveVal.getBytesCopy());
break;
}
return showVal;
}

public static DataAccountRegisterOperation convertDataAccountRegisterOperation(JSONObject jsonObject) {
JSONObject account = jsonObject.getJSONObject("accountID");
return new DataAccountRegisterOpTemplate(blockchainIdentity(account));
}

public static DataAccountKVSetOperation convertDataAccountKVSetOperation(JSONObject jsonObject) {
// 写入集合处理
JSONArray writeSetObj = jsonObject.getJSONArray("writeSet");
JSONObject accountAddrObj = jsonObject.getJSONObject("accountAddress");
String addressBase58 = accountAddrObj.getString("value");
Bytes address = Bytes.fromBase58(addressBase58);

DataAccountKVSetOpTemplate kvOperation = new DataAccountKVSetOpTemplate(address);
for (int i = 0; i <writeSetObj.size(); i++) {
JSONObject currWriteSetObj = writeSetObj.getJSONObject(i);
long expectedVersion = currWriteSetObj.getLong("expectedVersion");
JSONObject valueObj = currWriteSetObj.getJSONObject("value");
String typeStr = valueObj.getString("type");
String realValBase58 = valueObj.getString("value");
String key = currWriteSetObj.getString("key");
BytesValueType dataType = BytesValueType.valueOf(typeStr);
BytesValue bytesValue = new BytesValueEntry(dataType, Base58Utils.decode(realValBase58));
KVData kvData = new KVData(key, bytesValue, expectedVersion);
kvOperation.set(kvData);
}

return kvOperation;
}

public static LedgerInitOperation convertLedgerInitOperation(JSONObject jsonObject) {
JSONObject legerInitObj = jsonObject.getJSONObject("initSetting");
LedgerInitSettingData ledgerInitSettingData = new LedgerInitSettingData();
String ledgerSeedStr = legerInitObj.getString("ledgerSeed");

// 种子需要做Base64转换
ledgerInitSettingData.setLedgerSeed(Base64.decodeBase64(BytesUtils.toBytes(ledgerSeedStr)));

String consensusProvider = legerInitObj.getString("consensusProvider");

ledgerInitSettingData.setConsensusProvider(consensusProvider);

JSONObject cryptoSettingObj = legerInitObj.getJSONObject("cryptoSetting");
boolean autoVerifyHash = cryptoSettingObj.getBoolean("autoVerifyHash");
short hashAlgorithm = cryptoSettingObj.getShort("hashAlgorithm");

CryptoConfig cryptoConfig = new CryptoConfig();

cryptoConfig.setAutoVerifyHash(autoVerifyHash);

cryptoConfig.setHashAlgorithm(hashAlgorithm);

ledgerInitSettingData.setCryptoSetting(cryptoConfig);


JSONObject consensusSettingsObj = legerInitObj.getJSONObject("consensusSettings");
Bytes consensusSettings = Bytes.fromBase58(consensusSettingsObj.getString("value"));

ledgerInitSettingData.setConsensusSettings(consensusSettings);

JSONArray consensusParticipantsArray = legerInitObj.getJSONArray("consensusParticipants");

if (!consensusParticipantsArray.isEmpty()) {
ParticipantNode[] participantNodes = new ParticipantNode[consensusParticipantsArray.size()];
for (int i = 0; i < consensusParticipantsArray.size(); i++) {
JSONObject currConsensusParticipant = consensusParticipantsArray.getJSONObject(i);
String addressBase58 = currConsensusParticipant.getString("address");
String name = currConsensusParticipant.getString("name");
int id = currConsensusParticipant.getInteger("id");
JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey");
String pubKeyBase58 = pubKeyObj.getString("value");
// 生成ParticipantNode对象
ParticipantCertData participantCertData = new ParticipantCertData(id, addressBase58, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()));
participantNodes[i] = participantCertData;
}
ledgerInitSettingData.setConsensusParticipants(participantNodes);
}

return new LedgerInitOpTemplate(ledgerInitSettingData);
}

public static UserRegisterOperation convertUserRegisterOperation(JSONObject jsonObject) {
JSONObject user = jsonObject.getJSONObject("userID");
return new UserRegisterOpTemplate(blockchainIdentity(user));
}

public static ContractCodeDeployOperation convertContractCodeDeployOperation(JSONObject jsonObject) {
JSONObject contract = jsonObject.getJSONObject("contractID");
BlockchainIdentityData blockchainIdentity = blockchainIdentity(contract);

String chainCodeStr = jsonObject.getString("chainCode");
ContractCodeDeployOpTemplate contractCodeDeployOpTemplate = new ContractCodeDeployOpTemplate(blockchainIdentity, BytesUtils.toBytes(chainCodeStr));
return contractCodeDeployOpTemplate;
}

public static ContractEventSendOperation convertContractEventSendOperation(JSONObject jsonObject) {
JSONObject contractAddressObj = jsonObject.getJSONObject("contractAddress");
String contractAddress = contractAddressObj.getString("value");
String argsStr = jsonObject.getString("args");
String event = jsonObject.getString("event");
return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, BytesUtils.toBytes(argsStr));
}

private static BlockchainIdentityData blockchainIdentity(JSONObject jsonObject) {
JSONObject addressObj = jsonObject.getJSONObject("address");
// base58值
String addressBase58 = addressObj.getString("value");
Bytes address = Bytes.fromBase58(addressBase58);

JSONObject pubKeyObj = jsonObject.getJSONObject("pubKey");
// base58值
String pubKeyBase58 = pubKeyObj.getString("value");
PubKey pubKey = new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes());

// 生成对应的对象
return new BlockchainIdentityData(address, pubKey);
}

public static class CryptoConfig implements CryptoSetting {

private short hashAlgorithm;

private boolean autoVerifyHash;

@Override
public CryptoProvider[] getSupportedProviders() {
return new CryptoProvider[0];
}

@Override
public short getHashAlgorithm() {
return hashAlgorithm;
}

@Override
public boolean getAutoVerifyHash() {
return autoVerifyHash;
}

public void setHashAlgorithm(short hashAlgorithm) {
this.hashAlgorithm = hashAlgorithm;
}

public void setAutoVerifyHash(boolean autoVerifyHash) {
this.autoVerifyHash = autoVerifyHash;
}
}

public static class ParticipantCertData implements ParticipantNode{
private int id;
private String address;
private String name;
private PubKey pubKey;

public ParticipantCertData() {
}

public ParticipantCertData(ParticipantNode participantNode) {
this.address = participantNode.getAddress();
this.name = participantNode.getName();
this.pubKey = participantNode.getPubKey();
}

public ParticipantCertData(int id, String address, String name, PubKey pubKey) {
this.id = id;
this.address = address;
this.name = name;
this.pubKey = pubKey;
}

@Override
public String getAddress() {
return address;
}

@Override
public String getName() {
return name;
}

@Override
public PubKey getPubKey() {
return pubKey;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}
}
}

+ 8
- 0
source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/GatewayServiceFactory.java View File

@@ -56,6 +56,14 @@ public class GatewayServiceFactory implements BlockchainServiceFactory, Closeabl
DataContractRegistry.register(ClientIdentifications.class);
DataContractRegistry.register(ClientIdentification.class);
DataContractRegistry.register(CONTRACT_INT8.class);
DataContractRegistry.register(CONTRACT_INT16.class);
DataContractRegistry.register(CONTRACT_INT32.class);
DataContractRegistry.register(CONTRACT_INT64.class);
DataContractRegistry.register(CONTRACT_TEXT.class);
DataContractRegistry.register(CONTRACT_BINARY.class);
DataContractRegistry.register(ContractBizContent.class);
ByteArrayObjectUtil.init();
}


+ 93
- 0
source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/ContractConfigure.java View File

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

import com.jd.blockchain.utils.BaseConstant;
import com.jd.blockchain.utils.ConsoleUtils;
import com.jd.blockchain.utils.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.util.*;

import static com.jd.blockchain.utils.BaseConstant.SYS_CONTRACT_CONF;
import static com.jd.blockchain.utils.BaseConstant.SYS_CONTRACT_PROPS_NAME;

/**
*
* @author zhaogw
* date 2019/3/15 18:22
*/
public enum ContractConfigure {
instance();
private static final Logger LOGGER = LoggerFactory.getLogger(ContractConfigure.class);
static Properties pp;

ContractConfigure(){
init();
}

private void init(){
String contractConfPath = System.getProperty(SYS_CONTRACT_CONF);
System.out.println("contractConfPath="+contractConfPath);
try {
if (contractConfPath == null) {
ConsoleUtils.info("Load build-in default contractConf in ContractConfigure ...");
ClassPathResource contractConfigResource = new ClassPathResource(SYS_CONTRACT_PROPS_NAME);
InputStream in = contractConfigResource.getInputStream();
pp = FileUtils.readProperties(in, BaseConstant.CHARSET_UTF_8);
} else {
ConsoleUtils.info("Load configuration in ContractConfigure,contractConfPath="+contractConfPath);
File file = new File(contractConfPath);
pp = FileUtils.readProperties(file, BaseConstant.CHARSET_UTF_8);
}
} catch (Exception e) {
LOGGER.info(SYS_CONTRACT_PROPS_NAME+"文件异常!"+e.getMessage());
}
}

public String values(String key) {
if(pp == null){
init();
}
return pp.getProperty(key);
}

public String allValues() {
if(pp == null){
init();
}
Set<String> allKeys = pp.stringPropertyNames();
List<String> propList = new ArrayList();
for(String _key : allKeys){
String value = pp.getProperty(_key);
propList.add(_key+": "+value);
LOGGER.info("key={}, value={}",_key,value);
}
return propList.toString();
}

//写入资源文件信息
public static void writeProperties(String fileAllName, String comments, Map<String,String> map){
Properties properties=new Properties();
try {
File file = new File(fileAllName);
if (!file.getParentFile().exists()) {
boolean result = file.getParentFile().mkdirs();
if (!result) {
System.out.println("文件创建失败.");
}
}
OutputStream outputStream=new FileOutputStream(file);
for(Map.Entry<String,String> entry : map.entrySet()){
properties.setProperty(entry.getKey(), entry.getValue());
}
properties.store(outputStream, comments);
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

+ 53
- 0
source/sdk/sdk-samples/src/main/java/com/jd/blockchain/contract/samples/AssetContract2.java View File

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

import com.jd.blockchain.binaryproto.DataContract;
import com.jd.blockchain.consts.DataCodes;
import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;
import com.jd.blockchain.ledger.ContractBizContent;
import com.jd.blockchain.ledger.TransactionContentBody;
import com.jd.blockchain.utils.Bytes;

import java.math.BigDecimal;

/**
* 示例:一个“资产管理”智能合约;
*
* @author zhaogw
*/
@Contract
public interface AssetContract2 {

/**
* 发行资产;
* 新发行的资产数量;
* @param assetHolderAddress
* 新发行的资产的持有账户;
*/
@ContractEvent(name = "issue-asset-0")
void issue(ContractBizContent contractBizContent, String assetHolderAddress);

/**
* issue asset;
* @param contractBizContent
* @param assetHolderAddress
* @param cashNumber
*/
@ContractEvent(name = "issue-asset")
public void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber);

/**
* Bytes can bring the byte[];
* @param bytes
* @param assetHolderAddress
* @param cashNumber
*/
@ContractEvent(name = "issue-asset-2")
void issue(Bytes bytes,String assetHolderAddress, long cashNumber);

@ContractEvent(name = "issue-asset-3")
void issue(Byte bytes, String assetHolderAddress, long cashNumber);

@ContractEvent(name = "issue-asset-4")
void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber);
}

+ 20
- 13
source/sdk/sdk-samples/src/main/java/com/jd/blockchain/sdk/samples/SDKDemo_Contract.java View File

@@ -25,20 +25,24 @@ public class SDKDemo_Contract {

public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519");

public static void main(String[] args) {
demoContract();
}

/**
* 演示合约执行的过程;
*/
public static void demoContract() {
// 账本地址;
String ledgerAddress = "ffkjhkeqwiuhivnsh3298josijdocaijsda==";
String ledgerAddress = "j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7";
// 节点地址列表;
NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080),
new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080),
new NetworkAddress("192.168.10.13", 8080) };
// NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080),
// new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080),
// new NetworkAddress("192.168.10.13", 8080) };

// 创建服务代理;
final String GATEWAY_IP = "127.0.0.1";
final int GATEWAY_PORT = 80;
final String GATEWAY_IP = "localhost";
final int GATEWAY_PORT = 11000;
final boolean SECURE = false;
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE,
CLIENT_CERT);
@@ -52,13 +56,13 @@ public class SDKDemo_Contract {
// 一个贸易账户,贸易结算后的利润将通过一个合约账户来执行利润分配;
// 合约账户被设置为通用的账户,不具备对贸易结算账户的直接权限;
// 只有当前交易发起人具备对贸易账户的直接权限,当交易发起人对交易进行签名之后,权限被间接传递给合约账户;
String commerceAccount = "GGhhreGeasdfasfUUfehf9932lkae99ds66jf==";
String commerceAccount = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
// 处理利润分成的通用业务逻辑的合约账户;
String profitDistributionContract = "AAdfe4346fHhefe34fwf343kaeER4678RT==";
String profitDistributionContract = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";

// 收益人账户;
String receiptorAccount1 = "MMMEy902jkjjJJDkshreGeasdfassdfajjf==";
String receiptorAccount2 = "Kjfe8832hfa9jjjJJDkshrFjksjdlkfj93F==";
String receiptorAccount1 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
String receiptorAccount2 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
// 资产编码;
String assetKey = "RMB-ASSET";
// 此次待分配利润;
@@ -68,9 +72,12 @@ public class SDKDemo_Contract {
Remark remark = new Remark();
String remarkJSON = JSONSerializeUtils.serializeToJSON(remark);
// AssetContract assetContract = txTemp.contract("", AssetContract.class);
// txTemp.contractInvocation(assetContract.issue(amount, assetHolderAddress))

AssetContract assetContract = txTemp.contract(profitDistributionContract, AssetContract.class);
assetContract.issue(1000, receiptorAccount1);
assetContract.transfer(receiptorAccount1, receiptorAccount2, 600);
// assetContract.
// --------------------------------------

// TX 准备就绪;


+ 354
- 0
source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_Contract_Test.java View File

@@ -0,0 +1,354 @@
package test.com.jd.blockchain.sdk.test;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.contract.samples.AssetContract;
import com.jd.blockchain.contract.samples.AssetContract2;
import com.jd.blockchain.crypto.*;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.sdk.client.GatewayServiceFactory;
import com.jd.blockchain.sdk.samples.SDKDemo_Contract;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.io.ByteArray;
import com.jd.blockchain.utils.net.NetworkAddress;
import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import static org.junit.Assert.*;

/**
* 演示合约执行的过程;
*
* @author zhaogw
* 2019-05-21 11:03
*/
public class SDK_Contract_Test {
public static Logger log = LoggerFactory.getLogger(SDKDemo_Contract.class);

public static BlockchainKeypair CLIENT_CERT = BlockchainKeyGenerator.getInstance().generate("ED25519");
// 账本地址;
public static String ledgerAddress;
private PrivKey privKey;
private PubKey pubKey;
BlockchainService bcsrv;
AsymmetricKeypair signKeyPair;
HashDigest ledgerHash;

@Before
public void init(){
ledgerAddress = "j5qHcS8jG6XwpE5wXv9HYMeGTb5Fs2gQao3TPQ3irqFpQL";
ledgerHash = getLedgerHash();
pubKey = SDK_GateWay_KeyPair_Para.pubKey0;
privKey = SDK_GateWay_KeyPair_Para.privkey0;
// 使用私钥进行签名;
signKeyPair = new BlockchainKeypair(pubKey, privKey);

// 创建服务代理;
final String GATEWAY_IP = "localhost";
final int GATEWAY_PORT = 11000;
NetworkAddress addr = new NetworkAddress(GATEWAY_IP,GATEWAY_PORT);
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(addr);
bcsrv = serviceFactory.getBlockchainService();
}

/**
* 演示合约执行的过程;
*/
// @Test
public void demoContract1() {
String dataAddress = registerData4Contract();
// 发起交易;
TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash);
String contractAddress = "LdeNg8JHFCKABJt6AaRNVCZPgY4ofGPd8MgcR";
AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class);
// assetContract.issue(transactionContentBody,contractAddress);
// assetContract.issue(transactionContentBody,contractAddress,888888);
// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777);
// assetContract.issue(Bytes.fromString("zhaogw, contract based interface is OK!"),contractAddress,77777);
Byte byteObj = Byte.parseByte("127");
assetContract.issue(byteObj,dataAddress,321123);
// assetContract.issue(contractBizContent,dataAddress);
assetContract.issue(Byte.parseByte("126"),dataAddress,Bytes.fromString("100.234"));

// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
prepTx.sign(signKeyPair);
// 提交交易;
TransactionResponse transactionResponse = prepTx.commit();

//check;
KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,"total");
assertEquals("100",dataEntries[0].getValue().toString());
}

/**
* 演示合约执行的过程;
*/
// @Test
public void demoContract2() throws IOException {
String contractAddress = deploy();
String dataAddress = registerData4Contract();
System.out.println("dataAddress="+dataAddress);
// 发起交易;
TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash);

AssetContract2 assetContract = txTemp.contract(contractAddress, AssetContract2.class);
ContractBizContent contractBizContent = () -> new String[]{"param1","param2"};
assetContract.issue(contractBizContent,dataAddress,123456);

// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
prepTx.sign(signKeyPair);
// 提交交易;
TransactionResponse transactionResponse = prepTx.commit();

//check;
assertTrue(transactionResponse.isSuccess());
KVDataEntry[] dataEntries = bcsrv.getDataEntries(ledgerHash,dataAddress,contractBizContent.getAttrs()[0],contractBizContent.getAttrs()[1]);
assertEquals("value1",dataEntries[0].getValue().toString());
assertEquals(888,dataEntries[1].getValue());
}

// @Test
public void registerData(){
// 在本地定义 TX 模板
TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash);
BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate();
txTemp.dataAccounts().register(dataAccount.getIdentity());

String key1 = "jd_key1";
String val1 = "www.jd1.com";
String key2 = "jd_key2";
String val2 = "www.jd2.com";
// 定义交易,传输最简单的数字、字符串、提取合约中的地址;
txTemp.dataAccount(dataAccount.getAddress()).set(key1, val1, -1);
txTemp.dataAccount(dataAccount.getAddress()).set(key2, val2, -1);

// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
prepTx.sign(signKeyPair);
// 提交交易;
TransactionResponse transactionResponse = prepTx.commit();

assertTrue(transactionResponse.isSuccess());

//repeat;
String[] keys = {key1,key2};
String[] values = {"www.jd1.com.v1","www.jd2.com.v1"};
this.setDataInDataAddress(dataAccount.getAddress(),keys,values,0);
String[] values2 = {"www.jd1.com.v2","www.jd2.com.v2"};
this.setDataInDataAddress(dataAccount.getAddress(),keys,values2,1);
}

private String registerData4Contract(){
// 在本地定义 TX 模板
TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash);
BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate();
txTemp.dataAccounts().register(dataAccount.getIdentity());
txTemp.dataAccount(dataAccount.getAddress()).set("total", 200, -1);
txTemp.dataAccount(dataAccount.getAddress()).set("param1", "v", -1);
txTemp.dataAccount(dataAccount.getAddress()).set("param2", 123, -1);
// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
prepTx.sign(signKeyPair);
// 提交交易;
TransactionResponse transactionResponse = prepTx.commit();
assertTrue(transactionResponse.isSuccess());

return dataAccount.getAddress().toBase58();
}

private void setDataInDataAddress(Bytes dataAddress, String[] keys, String[] values, long version){
// 在本地定义 TX 模板
TransactionTemplate txTemp = bcsrv.newTransaction(ledgerHash);
BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate();

for(int i=0; i<keys.length; i++){
txTemp.dataAccount(dataAddress).set(keys[i], values[i], version);
}

// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
prepTx.sign(signKeyPair);
// 提交交易;
TransactionResponse transactionResponse = prepTx.commit();
assertTrue(transactionResponse.isSuccess());
}

private String deploy() throws IOException {
ClassPathResource classPathResource = new ClassPathResource("contract.jar");
byte[] chainCode = this.getChainCode(classPathResource.getURL().getPath());
TransactionTemplate txTpl = this.bcsrv.newTransaction(ledgerHash);
BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity();
txTpl.contracts().deploy(contractIdentity, chainCode);
PreparedTransaction ptx = txTpl.prepare();
ptx.sign(signKeyPair);
TransactionResponse txResp = ptx.commit();
System.out.println("contract's address=" + contractIdentity.getAddress());
String contractAddr = contractIdentity.getAddress().toBase58();
log.info("contractAddr="+contractAddr);
return contractAddr;
}

public byte[] getChainCode(String path) {
byte[] chainCode = null;
File file = null;
FileInputStream input = null;

try {
file = new File(path);
input = new FileInputStream(file);
chainCode = new byte[input.available()];
input.read(chainCode);
} catch (IOException var14) {
var14.printStackTrace();
} finally {
try {
if (input != null) {
input.close();
}
} catch (IOException var13) {
var13.printStackTrace();
}

}

return chainCode;
}

/**
* 演示合约执行的过程;
*/
public static void demoContract() {
// 账本地址;
String ledgerAddress = "j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7";
// 节点地址列表;
// NetworkAddress[] peerAddrs = { new NetworkAddress("192.168.10.10", 8080),
// new NetworkAddress("192.168.10.11", 8080), new NetworkAddress("192.168.10.12", 8080),
// new NetworkAddress("192.168.10.13", 8080) };

// 创建服务代理;
final String GATEWAY_IP = "localhost";
final int GATEWAY_PORT = 11000;
final boolean SECURE = false;
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(GATEWAY_IP, GATEWAY_PORT, SECURE,
CLIENT_CERT);
BlockchainService service = serviceFactory.getBlockchainService();

HashDigest ledgerHash = getLedgerHash();
// 发起交易;
TransactionTemplate txTemp = service.newTransaction(ledgerHash);

// --------------------------------------
// 一个贸易账户,贸易结算后的利润将通过一个合约账户来执行利润分配;
// 合约账户被设置为通用的账户,不具备对贸易结算账户的直接权限;
// 只有当前交易发起人具备对贸易账户的直接权限,当交易发起人对交易进行签名之后,权限被间接传递给合约账户;
String commerceAccount = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
// 处理利润分成的通用业务逻辑的合约账户;
String profitDistributionContract = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";

// 收益人账户;
String receiptorAccount1 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
String receiptorAccount2 = "LdeP13gKE6319LvYPyWAT4UXr2brvpitPRBN1";
// 资产编码;
String assetKey = "RMB-ASSET";
// 此次待分配利润;
long profit = 1000000;

// 备注信息;
Remark remark = new Remark();
String remarkJSON = JSONSerializeUtils.serializeToJSON(remark);
AssetContract assetContract = txTemp.contract(profitDistributionContract, AssetContract.class);
assetContract.issue(1000, receiptorAccount1);
assetContract.transfer(receiptorAccount1, receiptorAccount2, 600);
// assetContract.
// --------------------------------------

// TX 准备就绪;
PreparedTransaction prepTx = txTemp.prepare();
String txHash = ByteArray.toBase64(prepTx.getHash().toBytes());

// 使用私钥进行签名;
AsymmetricKeypair keyPair = getSponsorKey();
prepTx.sign(keyPair);

// 提交交易;
prepTx.commit();
}

private static HashDigest getLedgerHash() {
return new HashDigest(Base58Utils.decode(ledgerAddress));
}

/**
* 交易发起人的私钥;<br>
*
* 注:私钥由调用方在本地保管和使用;
*
* @return
*/
private static AsymmetricKeypair getSponsorKey() {
SignatureFunction signatureFunction = Crypto.getSignatureFunction("ED25519");
return signatureFunction.generateKeypair();
}

/**
* 商品信息;
*
* @author huanghaiquan
*
*/
public static class Remark {

private String code;

private String name;

private String venderAddress;

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getVenderAddress() {
return venderAddress;
}

public void setVenderAddress(String venderAddress) {
this.venderAddress = venderAddress;
}

}

@Test
public void testStringArr(){
ContractBizContent contractBizContent = () -> new String[]{"1","2","you are welcome!"};
byte[] bizBytes = BinaryProtocol.encode(contractBizContent,ContractBizContent.class);
ContractBizContent actualObj = BinaryProtocol.decodeAs(bizBytes,ContractBizContent.class);
assertArrayEquals(contractBizContent.getAttrs(),actualObj.getAttrs());
}
}

+ 8
- 8
source/sdk/sdk-samples/src/test/java/test/com/jd/blockchain/sdk/test/SDK_GateWay_KeyPair_Para.java View File

@@ -10,16 +10,16 @@ import com.jd.blockchain.tools.keygen.KeyGenCommand;
public class SDK_GateWay_KeyPair_Para {
public static final String PASSWORD = "abc";

public static final String[] PUB_KEYS = { "endPsK36imXrY66pru6ttZ8dZ3TynWekmdqoM1K7ZRRoRBBiYVzM",
"endPsK36jQE1uYpdVRSnwQXVYhgAMWTaMJiAqii7URiULoBDLUUN",
"endPsK36fc7FSecKAJCJdFhTejbPHMLaGcihJVQCv95czCq4tW5n",
"endPsK36m1grx8mkTMgh8XQHiiaNzajdC5hkuqP6pAuLmMbYkzd4" };
public static final String[] PUB_KEYS = { "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9",
"3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX",
"3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x",
"3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk" };

public static final String[] PRIV_KEYS = {
"177gjsuHdbf3PU68Sm1ZU2aMcyB7sLWj94xwBUoUKvTgHq7qGUfg6ynDB62hocYYXSRXD4X",
"177gjwQwTdXthkutDKVgKwiq6wWfLWYuxhji1U2N1C5MzqLRWCLZXo3i2g4vpfcEAQUPG8H",
"177gjvLHUjxvAWsqVcGgV8eHgVNBvJZYDfpP9FLjTouR1gEJNiamYu1qjTNDh18XWyLg8or",
"177gk2VtYeGbK5TS2xWhbSZA4BsT9Xj5Fb8hqCzxzgbojVVcqaDSFFrFPsLbZBx7rszyCNy" };
"177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x",
"177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT",
"177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF",
"177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns" };

public static PrivKey privkey0 = KeyGenCommand.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD);
public static PrivKey privkey1 = KeyGenCommand.decodePrivKeyWithRawPassword(PRIV_KEYS[1], PASSWORD);


BIN
source/sdk/sdk-samples/src/test/resources/contract.jar View File


+ 13
- 0
source/sdk/sdk-samples/src/test/resources/sys-contract.properties View File

@@ -0,0 +1,13 @@
#ledger info;
ownerPubPath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.pub
ownerPrvPath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.priv
ownerPassword=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\conf\\jd-com.pwd
ledgerHash=j5rpuGWVxSuUbU3gK7MDREfui797AjfdHzvAMiSaSzydu7
host=localhost
port=11000
#execute contract;
event = issue-asset
chainCodePath=F:\\jdsk\\jdsk-files\\github\\jdchain-starter\\contract-compile\\target\\contract.jar
contractArgs=1000##fromAddr##LdeNvLeq6MB6y8CoyawYxgCCYCJkrp5xoVGUw
#contractArgs=fromAddr##toAddr##30##LdeNvLeq6MB6y8CoyawYxgCCYCJkrp5xoVGUw


+ 91
- 108
source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/IntegrationTest.java View File

@@ -1,38 +1,13 @@
package test.com.jd.blockchain.intgr;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

import org.springframework.core.io.ClassPathResource;

import com.jd.blockchain.consensus.ConsensusProvider;
import com.jd.blockchain.consensus.ConsensusProviders;
import com.jd.blockchain.consensus.ConsensusSettings;
import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInfo;
import com.jd.blockchain.ledger.ParticipantNode;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.UserInfo;
import com.jd.blockchain.ledger.core.DataAccountSet;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.LedgerManage;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
@@ -48,10 +23,18 @@ import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.codec.HexUtils;
import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback;
import com.jd.blockchain.utils.net.NetworkAddress;
import org.springframework.core.io.ClassPathResource;
import test.com.jd.blockchain.intgr.IntegratedContext.Node;
import test.com.jd.blockchain.intgr.perf.LedgerInitializeWebTest;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class IntegrationTest {
// 合约测试使用的初始化数据;
BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate();
@@ -547,87 +530,87 @@ public class IntegrationTest {
}
}

private LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash,
BlockchainService blockchainService, IntegratedContext context) {
// valid the basic data in contract;
prepareContractData(adminKey, ledgerHash, blockchainService, context);
BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate();
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
byte[] contractCode = getChainCodeBytes();
txTpl.users().register(userKey.getIdentity());
txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode);
// 签名;
PreparedTransaction ptx = txTpl.prepare();
ptx.sign(adminKey);
// 提交并等待共识返回;
TransactionResponse txResp = ptx.commit();
// 验证结果;
txResp.getContentHash();
Node node0 = context.getNode(0);
LedgerRepository ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash);
LedgerBlock block = ledgerOfNode0.getBlock(txResp.getBlockHeight());
byte[] contractCodeInDb = ledgerOfNode0.getContractAccountSet(block).getContract(contractDeployKey.getAddress())
.getChainCode();
txContentHash = ptx.getHash();
// execute the contract;
testContractExe(adminKey, ledgerHash, userKey, blockchainService, context);
return block;
}
private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey,
BlockchainService blockchainService, IntegratedContext context) {
LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash);
LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1);
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName,
("888##abc##" + contractDataKey.getAddress() + "##" + previousBlock.getHash().toBase58() + "##"
+ userKey.getAddress() + "##" + contractDeployKey.getAddress() + "##" + txContentHash.toBase58()
+ "##SOME-VALUE").getBytes());
// 签名;
PreparedTransaction ptx = txTpl.prepare();
ptx.sign(adminKey);
// 提交并等待共识返回;
TransactionResponse txResp = ptx.commit();
// 验证结果;
txResp.getContentHash();
LedgerInfo latestLedgerInfo = blockchainService.getLedger(ledgerHash);
Node node0 = context.getNode(0);
LedgerRepository ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash);
LedgerBlock backgroundLedgerBlock = ledgerOfNode0.retrieveLatestBlock();
// 验证合约中的赋值,外部可以获得;
DataAccountSet dataAccountSet = ledgerOfNode0.getDataAccountSet(backgroundLedgerBlock);
AsymmetricKeypair key = Crypto.getSignatureFunction("ED25519").generateKeypair();
PubKey pubKey = key.getPubKey();
Bytes dataAddress = AddressEncoding.generateAddress(pubKey);
// 验证userAccount,从合约内部赋值,然后外部验证;由于目前不允许输入重复的key,所以在内部合约中构建的key,不便于在外展示,屏蔽之;
// UserAccountSet userAccountSet =
// ledgerOfNode0.getUserAccountSet(backgroundLedgerBlock);
// PubKey userPubKey = new PubKey(CryptoAlgorithm.ED25519,
// userPubKeyVal.getBytes());
// String userAddress = AddressEncoding.generateAddress(userPubKey);
// assertEquals(userAddress, userAccountSet.getUser(userAddress).getAddress());
}
// private LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash,
// BlockchainService blockchainService, IntegratedContext context) {
// // valid the basic data in contract;
// prepareContractData(adminKey, ledgerHash, blockchainService, context);
//
// BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate();
//
// // 定义交易;
// TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
// byte[] contractCode = getChainCodeBytes();
//
// txTpl.users().register(userKey.getIdentity());
//
// txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode);
//
// // 签名;
// PreparedTransaction ptx = txTpl.prepare();
// ptx.sign(adminKey);
//
// // 提交并等待共识返回;
// TransactionResponse txResp = ptx.commit();
//
// // 验证结果;
// txResp.getContentHash();
//
// Node node0 = context.getNode(0);
// LedgerRepository ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash);
// LedgerBlock block = ledgerOfNode0.getBlock(txResp.getBlockHeight());
// byte[] contractCodeInDb = ledgerOfNode0.getContractAccountSet(block).getContract(contractDeployKey.getAddress())
// .getChainCode();
// txContentHash = ptx.getHash();
//
// // execute the contract;
// testContractExe(adminKey, ledgerHash, userKey, blockchainService, context);
//
// return block;
// }
// private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey,
// BlockchainService blockchainService, IntegratedContext context) {
// LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash);
// LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1);
//
// // 定义交易;
// TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
//
// txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName,
// ("888##abc##" + contractDataKey.getAddress() + "##" + previousBlock.getHash().toBase58() + "##"
// + userKey.getAddress() + "##" + contractDeployKey.getAddress() + "##" + txContentHash.toBase58()
// + "##SOME-VALUE").getBytes());
//
// // 签名;
// PreparedTransaction ptx = txTpl.prepare();
// ptx.sign(adminKey);
//
// // 提交并等待共识返回;
// TransactionResponse txResp = ptx.commit();
//
// // 验证结果;
// txResp.getContentHash();
//
// LedgerInfo latestLedgerInfo = blockchainService.getLedger(ledgerHash);
//
// Node node0 = context.getNode(0);
// LedgerRepository ledgerOfNode0 = node0.getLedgerManager().getLedger(ledgerHash);
// LedgerBlock backgroundLedgerBlock = ledgerOfNode0.retrieveLatestBlock();
//
// // 验证合约中的赋值,外部可以获得;
// DataAccountSet dataAccountSet = ledgerOfNode0.getDataAccountSet(backgroundLedgerBlock);
// AsymmetricKeypair key = Crypto.getSignatureFunction("ED25519").generateKeypair();
// PubKey pubKey = key.getPubKey();
// Bytes dataAddress = AddressEncoding.generateAddress(pubKey);
//
// // 验证userAccount,从合约内部赋值,然后外部验证;由于目前不允许输入重复的key,所以在内部合约中构建的key,不便于在外展示,屏蔽之;
// // UserAccountSet userAccountSet =
// // ledgerOfNode0.getUserAccountSet(backgroundLedgerBlock);
// // PubKey userPubKey = new PubKey(CryptoAlgorithm.ED25519,
// // userPubKeyVal.getBytes());
// // String userAddress = AddressEncoding.generateAddress(userPubKey);
// // assertEquals(userAddress, userAccountSet.getUser(userAddress).getAddress());
// }

private void prepareContractData(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainService blockchainService,
IntegratedContext context) {


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

@@ -28,11 +28,14 @@ import com.jd.blockchain.utils.net.NetworkAddress;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.springframework.core.io.ClassPathResource;
import test.com.jd.blockchain.intgr.contract.AssetContract;
import test.com.jd.blockchain.intgr.contract.AssetContract2;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@@ -52,6 +55,7 @@ import static org.junit.Assert.*;
*/

public class IntegrationBase {
public static String KEY_TOTAL = "total";

static {
DataContractRegistry.register(LedgerInitOperation.class);
@@ -105,6 +109,9 @@ public class IntegrationBase {
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);
txTpl.dataAccounts().register(dataAccount.getIdentity());
txTpl.dataAccount(dataAccount.getAddress()).set("total", 200, -1);
// txTpl.dataAccount(dataAccount.getAddress()).set("param1", "v", -1);
// txTpl.dataAccount(dataAccount.getAddress()).set("param2", 200, -1);

// 签名;
PreparedTransaction ptx = txTpl.prepare();
@@ -430,18 +437,16 @@ public class IntegrationBase {
}

// 合约测试使用的初始化数据;
BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate();
BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate();
static BlockchainKeypair contractDataKey = BlockchainKeyGenerator.getInstance().generate();
static BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate();
// 保存资产总数的键;
private static final String KEY_TOTAL = "TOTAL";
// 第二个参数;
private static final String KEY_ABC = "abc";
private String contractZipName = "Example1.jar";
HashDigest txContentHash;
String pubKeyVal = "jd.com"+System.currentTimeMillis();
private String eventName = "issue-asset";
public LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash,
private static String contractZipName = "contract.jar";
static HashDigest txContentHash;
public static LedgerBlock testSDK_Contract(AsymmetricKeypair adminKey, HashDigest ledgerHash,
BlockchainService blockchainService,LedgerRepository ledgerRepository) {
KeyPairResponse keyPairResponse = testSDK_RegisterDataAccount(adminKey,ledgerHash,blockchainService);

System.out.println("adminKey="+ AddressEncoding.generateAddress(adminKey.getPubKey()));
BlockchainKeypair userKey = BlockchainKeyGenerator.getInstance().generate();
System.out.println("userKey="+userKey.getAddress());
@@ -460,22 +465,22 @@ public class IntegrationBase {
TransactionResponse txResp = ptx.commit();
assertTrue(txResp.isSuccess());

// 验证结果;
txResp.getContentHash();
// 验证结果hash请求的hash=相应的内容hash;
assertEquals(ptx.getHash(),txResp.getContentHash());

LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight());
byte[] contractCodeInDb = ledgerRepository.getContractAccountSet(block).getContract(contractDeployKey.getAddress())
.getChainCode();
assertArrayEquals(contractCode, contractCodeInDb);
txContentHash = ptx.getHash();

// execute the contract;
testContractExe(adminKey, ledgerHash, userKey, blockchainService, ledgerRepository);
testContractExe(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository);
testContractExe1(adminKey, ledgerHash, keyPairResponse.keyPair, blockchainService, ledgerRepository);

return block;
}

private void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair userKey,
private static <T> void testContractExe(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey,
BlockchainService blockchainService,LedgerRepository ledgerRepository) {
LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash);
LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1);
@@ -483,8 +488,38 @@ public class IntegrationBase {
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);

txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName,
("888##123##" + contractDataKey.getAddress()).getBytes());
Byte byteObj = Byte.parseByte("123");
// txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj,
// contractDeployKey.getAddress().toBase58(),321123);
txTpl.contract(contractDeployKey.getAddress(),AssetContract2.class).issue(byteObj,
dataKey.getAddress().toBase58(),Bytes.fromString("123321"));

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

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

// 验证结果;
Assert.assertTrue(txResp.isSuccess());
assertEquals(ptx.getHash(),txResp.getContentHash());
LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight());
KVDataEntry[] kvDataEntries = ledgerRepository.getDataAccountSet(block).getDataAccount(dataKey.getAddress()).getDataEntries(0,1);
assertEquals("100",kvDataEntries[0].getValue().toString());
}

private static <T> void testContractExe1(AsymmetricKeypair adminKey, HashDigest ledgerHash, BlockchainKeypair dataKey,
BlockchainService blockchainService,LedgerRepository ledgerRepository) {
LedgerInfo ledgerInfo = blockchainService.getLedger(ledgerHash);
LedgerBlock previousBlock = blockchainService.getBlock(ledgerHash, ledgerInfo.getLatestBlockHeight() - 1);

// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);

AssetContract2 assetContract = txTpl.contract(contractDeployKey.getAddress(), AssetContract2.class);
ContractBizContent contractBizContent = () -> new String[]{"param1","param2"};
assetContract.issue(contractBizContent,dataKey.getAddress().toBase58(),123456);

// 签名;
PreparedTransaction ptx = txTpl.prepare();
@@ -494,8 +529,12 @@ public class IntegrationBase {
TransactionResponse txResp = ptx.commit();

// 验证结果;
txResp.getContentHash();
Assert.assertTrue(txResp.isSuccess());
assertEquals(ptx.getHash(),txResp.getContentHash());
LedgerBlock block = ledgerRepository.getBlock(txResp.getBlockHeight());
KVDataEntry[] kvDataEntries = ledgerRepository.getDataAccountSet(block).getDataAccount(dataKey.getAddress()).getDataEntries(1,2);
assertEquals("value1",kvDataEntries[0].getValue().toString());
assertEquals(888L,kvDataEntries[1].getValue());
}

/**
@@ -503,7 +542,7 @@ public class IntegrationBase {
*
* @return
*/
private byte[] getChainCodeBytes() {
private static byte[] getChainCodeBytes() {
// 构建合约的字节数组;
byte[] contractCode = null;
File file = null;


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

@@ -1,34 +1,12 @@
package test.com.jd.blockchain.intgr;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.ClassPathResource;

import com.jd.blockchain.consensus.ConsensusProvider;
import com.jd.blockchain.consensus.ConsensusProviders;
import com.jd.blockchain.consensus.ConsensusSettings;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInfo;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.sdk.client.GatewayServiceFactory;
@@ -39,18 +17,29 @@ import com.jd.blockchain.tools.initializer.Prompter;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback;
import com.jd.blockchain.utils.net.NetworkAddress;

import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import test.com.jd.blockchain.intgr.IntegratedContext.Node;
import test.com.jd.blockchain.intgr.contract.AssetContract;
import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest;
import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest.NodeWebContext;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;

import static org.junit.Assert.*;

/**
* 测试合约,提交后不立即进行验证,因为此时可能还没有完成正式结块;
*/
public class IntegrationTest2 {
// 合约测试使用的初始化数据;
BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate();
private String contractZipName = "AssetContract3.contract";
private String contractZipName = "contract.jar";
private String eventName = "issue-asset";

@Test
@@ -315,7 +304,7 @@ public class IntegrationTest2 {
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);

txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName, ("888##999##abc").getBytes());
txTpl.contract(contractDeployKey.getAddress(), AssetContract.class).issue(10,"abc");

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


+ 106
- 0
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationTest4Contract.java View File

@@ -0,0 +1,106 @@
package test.com.jd.blockchain.intgr;

import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.gateway.GatewayConfigProperties;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.sdk.client.GatewayServiceFactory;
import com.jd.blockchain.storage.service.DbConnectionFactory;
import com.jd.blockchain.tools.initializer.LedgerBindingConfig;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.concurrent.ThreadInvoker;

import org.junit.Test;
import test.com.jd.blockchain.intgr.initializer.LedgerInitializeTest;
import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4Nodes;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static test.com.jd.blockchain.intgr.IntegrationBase.*;

public class IntegrationTest4Contract {
private static final boolean isContractDeployAndExe = true;
private static final String DB_TYPE_MEM = "mem";

@Test
public void test4Memory() {
test(LedgerInitConsensusConfig.bftsmartProvider, DB_TYPE_MEM, LedgerInitConsensusConfig.memConnectionStrings);
}

public void test(String[] providers, String dbType, String[] dbConnections) {
final ExecutorService sendReqExecutors = Executors.newFixedThreadPool(10);
// 内存账本初始化
HashDigest ledgerHash = initLedger(dbConnections);
// 启动Peer节点
PeerTestRunner[] peerNodes = peerNodeStart(ledgerHash, dbType);
DbConnectionFactory dbConnectionFactory0 = peerNodes[0].getDBConnectionFactory();
DbConnectionFactory dbConnectionFactory1 = peerNodes[1].getDBConnectionFactory();
DbConnectionFactory dbConnectionFactory2 = peerNodes[2].getDBConnectionFactory();
DbConnectionFactory dbConnectionFactory3 = peerNodes[3].getDBConnectionFactory();

String encodedBase58Pwd = KeyGenCommand.encodePasswordAsBase58(LedgerInitializeTest.PASSWORD);

GatewayConfigProperties.KeyPairConfig gwkey0 = new GatewayConfigProperties.KeyPairConfig();
gwkey0.setPubKeyValue(IntegrationBase.PUB_KEYS[0]);
gwkey0.setPrivKeyValue(IntegrationBase.PRIV_KEYS[0]);
gwkey0.setPrivKeyPassword(encodedBase58Pwd);
GatewayTestRunner gateway = new GatewayTestRunner("127.0.0.1", 11000, gwkey0,
peerNodes[0].getServiceAddress(), providers,null);

ThreadInvoker.AsyncCallback<Object> gwStarting = gateway.start();

gwStarting.waitReturn();

// 执行测试用例之前,校验每个节点的一致性;
LedgerRepository[] ledgers = buildLedgers(new LedgerBindingConfig[]{
peerNodes[0].getLedgerBindingConfig(),
peerNodes[1].getLedgerBindingConfig(),
peerNodes[2].getLedgerBindingConfig(),
peerNodes[3].getLedgerBindingConfig(),
},
new DbConnectionFactory[]{
dbConnectionFactory0,
dbConnectionFactory1,
dbConnectionFactory2,
dbConnectionFactory3});

IntegrationBase.testConsistencyAmongNodes(ledgers);

LedgerRepository ledgerRepository = ledgers[0];

GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(gateway.getServiceAddress());

PrivKey privkey0 = KeyGenCommand.decodePrivKeyWithRawPassword(IntegrationBase.PRIV_KEYS[0], IntegrationBase.PASSWORD);

PubKey pubKey0 = KeyGenCommand.decodePubKey(IntegrationBase.PUB_KEYS[0]);

AsymmetricKeypair adminKey = new AsymmetricKeypair(pubKey0, privkey0);

BlockchainService blockchainService = gwsrvFact.getBlockchainService();

if(isContractDeployAndExe){
IntegrationBase.testSDK_Contract(adminKey,ledgerHash,blockchainService,ledgerRepository);
}

try {
System.out.println("----------------- Init Completed -----------------");
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}

IntegrationBase.testConsistencyAmongNodes(ledgers);
}
private HashDigest initLedger(String[] dbConnections) {
LedgerInitializeWeb4Nodes ledgerInit = new LedgerInitializeWeb4Nodes();
HashDigest ledgerHash = ledgerInit.testInitWith4Nodes(LedgerInitConsensusConfig.bftsmartConfig, dbConnections);
System.out.printf("LedgerHash = %s \r\n", ledgerHash.toBase58());
return ledgerHash;
}
}

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

@@ -1,36 +1,8 @@
package test.com.jd.blockchain.intgr;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;

import org.junit.Test;
import org.springframework.core.io.ClassPathResource;

import com.jd.blockchain.crypto.AddressEncoding;
import com.jd.blockchain.crypto.AsymmetricKeypair;
import com.jd.blockchain.crypto.Crypto;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.crypto.*;
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig;
import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.ledger.DataAccountKVSetOperation;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.ledger.LedgerBlock;
import com.jd.blockchain.ledger.LedgerInfo;
import com.jd.blockchain.ledger.PreparedTransaction;
import com.jd.blockchain.ledger.TransactionResponse;
import com.jd.blockchain.ledger.TransactionState;
import com.jd.blockchain.ledger.TransactionTemplate;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.DataAccount;
import com.jd.blockchain.ledger.core.DataAccountSet;
import com.jd.blockchain.ledger.core.LedgerManage;
@@ -47,9 +19,19 @@ import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.codec.HexUtils;
import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback;
import com.jd.blockchain.utils.net.NetworkAddress;

import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import test.com.jd.blockchain.intgr.contract.AssetContract;
import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4SingleStepsTest;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;

import static org.junit.Assert.*;

public class IntegrationTestAll4Redis {

public static final String PASSWORD = "abc";
@@ -450,10 +432,7 @@ public class IntegrationTestAll4Redis {
// 定义交易;
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash);

txTpl.contractEvents().send(contractDeployKey.getAddress(), eventName,
("888##abc##" + contractDataKey.getAddress() + "##" + previousBlock.getHash().toBase58() + "##"
+ userKey.getAddress() + "##" + contractDeployKey.getAddress() + "##" + txContentHash.toBase58()
+ "##" + pubKeyVal).getBytes());
txTpl.contract(contractDeployKey.getAddress(), AssetContract.class).issue(10,"abc");

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


+ 39
- 0
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract.java View File

@@ -0,0 +1,39 @@
package test.com.jd.blockchain.intgr.contract;

import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;

/**
* 示例:一个“资产管理”智能合约;
*
* @author huanghaiquan
*
*/
@Contract
public interface AssetContract {

/**
* 发行资产;
*
* @param amount
* 新发行的资产数量;
* @param assetHolderAddress
* 新发行的资产的持有账户;
*/
@ContractEvent(name = "issue-asset")
void issue(long amount, String assetHolderAddress);

/**
* 转移资产
*
* @param fromAddress
* 转出账户;
* @param toAddress
* 转入账户;
* @param amount
* 转移的资产数额;
*/
@ContractEvent(name = "transfer-asset")
void transfer(String fromAddress, String toAddress, long amount);

}

+ 44
- 0
source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/contract/AssetContract2.java View File

@@ -0,0 +1,44 @@
package test.com.jd.blockchain.intgr.contract;

import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;
import com.jd.blockchain.ledger.ContractBizContent;
import com.jd.blockchain.utils.Bytes;

import java.math.BigDecimal;

/**
* 示例:一个“资产管理”智能合约;
*
* @author zhaogw
*/
@Contract
public interface AssetContract2 {

/**
* 发行资产;
* 新发行的资产数量;
* @param assetHolderAddress
* 新发行的资产的持有账户;
*/
@ContractEvent(name = "issue-asset-0")
void issue(ContractBizContent contractBizContent, String assetHolderAddress);

/**
* 发行资产;
* 新发行的资产数量;
* @param assetHolderAddress
* 新发行的资产的持有账户;
*/
@ContractEvent(name = "issue-asset")
void issue(ContractBizContent contractBizContent, String assetHolderAddress, long cashNumber);

@ContractEvent(name = "issue-asset-2")
void issue(Bytes bytes, String assetHolderAddress, long cashNumber);

@ContractEvent(name = "issue-asset-3")
void issue(Byte byteObj, String assetHolderAddress, long cashNumber);

@ContractEvent(name = "issue-asset-4")
void issue(Byte byteObj, String assetHolderAddress, Bytes cashNumber);
}

BIN
source/test/test-integration/src/test/resources/contract.jar View File


+ 0
- 1
source/test/test-integration/src/test/resources/ledger_init_test_web2.init View File

@@ -1,4 +1,3 @@

#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取;
ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe



+ 2
- 1
source/tools/pom.xml View File

@@ -15,6 +15,7 @@
<module>tools-initializer</module>
<module>tools-initializer-booter</module>
<module>tools-capability</module>
<!-- <module>tools-package</module> -->
<module>tools-mocker</module>
<!-- <module>tools-package</module> -->
</modules>
</project>

+ 1
- 1
source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java View File

@@ -127,7 +127,7 @@ public class LedgerInitProperties {
return resolve(props);
}

private static LedgerInitProperties resolve(Properties props) {
public static LedgerInitProperties resolve(Properties props) {
String hexLedgerSeed = PropertiesUtils.getRequiredProperty(props, LEDGER_SEED).replace("-", "");
byte[] ledgerSeed = HexUtils.decode(hexLedgerSeed);
LedgerInitProperties initProps = new LedgerInitProperties(ledgerSeed);


+ 1
- 1
source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LocalConfig.java View File

@@ -78,7 +78,7 @@ public class LocalConfig {
return resolve(props, null);
}

private static LocalConfig resolve(Properties props, String initSettingFile) {
public static LocalConfig resolve(Properties props, String initSettingFile) {

LocalConfig conf = new LocalConfig();



+ 44
- 0
source/tools/tools-mocker/pom.xml View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tools</artifactId>
<groupId>com.jd.blockchain</groupId>
<version>0.9.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tools-mocker</artifactId>

<name>tools-mocker</name>

<dependencies>
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>peer</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>gateway</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>tools-initializer</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>sdk-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>crypto-classic</artifactId>
<version>${project.version}</version>
</dependency>

</dependencies>
</project>

+ 342
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java View File

@@ -0,0 +1,342 @@
package com.jd.blockchain.mocker;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.consensus.ConsensusProvider;
import com.jd.blockchain.consensus.ConsensusProviders;
import com.jd.blockchain.consensus.ConsensusSettings;
import com.jd.blockchain.crypto.*;
import com.jd.blockchain.crypto.service.classic.ClassicCryptoService;
import com.jd.blockchain.crypto.service.sm.SMCryptoService;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.*;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
import com.jd.blockchain.storage.service.DbConnection;
import com.jd.blockchain.storage.service.DbConnectionFactory;
import com.jd.blockchain.tools.initializer.*;
import com.jd.blockchain.tools.initializer.LedgerInitProperties.ConsensusParticipantConfig;
import com.jd.blockchain.tools.initializer.web.LedgerInitConsensusService;
import com.jd.blockchain.tools.initializer.web.LedgerInitDecisionData;
import com.jd.blockchain.transaction.DigitalSignatureBlob;
import com.jd.blockchain.transaction.LedgerInitSettingData;
import com.jd.blockchain.transaction.TxBuilder;
import com.jd.blockchain.transaction.TxRequestBuilder;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.concurrent.InvocationResult;
import com.jd.blockchain.utils.io.BytesUtils;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.*;

/**
* 账本初始化控制器;
*
* @author huanghaiquan
*
*/
public class MockerLedgerInitializer implements LedgerInitProcess, LedgerInitConsensusService {

static {
DataContractRegistry.register(TransactionRequest.class);
}

private static final String[] SUPPORTED_PROVIDERS = {
ClassicCryptoService.class.getName(),
SMCryptoService.class.getName() };

private static final String DEFAULT_SIGN_ALGORITHM = "ED25519";

private final SignatureFunction SIGN_FUNC;

private volatile LedgerInitPermission localPermission;

private TransactionContent initTxContent;

private volatile int currentId = -1;

private volatile LedgerInitSetting ledgerInitSetting;

// private volatile LedgerInitPermission[] permissions;
// private volatile LedgerInitPermission permission;

private volatile Prompter prompter;

private volatile ConsensusProvider consensusProvider;

private volatile LedgerBlock genesisBlock;

private volatile LedgerInitDecision localDecision;

private volatile DecisionResultHandle[] decisions;

private volatile DbConnection dbConn;

private volatile LedgerEditor ledgerEditor;

private LedgerManager ledgerManager;

private DbConnectionFactory dbConnFactory;

public MockerLedgerInitializer() {
this.SIGN_FUNC = Crypto.getSignatureFunction(DEFAULT_SIGN_ALGORITHM);
}

public MockerLedgerInitializer(DbConnectionFactory dbConnFactory, LedgerManager ledgerManager) {
this.SIGN_FUNC = Crypto.getSignatureFunction(DEFAULT_SIGN_ALGORITHM);
this.dbConnFactory = dbConnFactory;
this.ledgerManager = ledgerManager;
}

public int getId() {
return currentId;
}

public TransactionContent getInitTxContent() {
return initTxContent;
}

public LedgerInitPermission getLocalPermission() {
return localPermission;
}

public LedgerInitDecision getLocalDecision() {
return localDecision;
}

public void setPrompter(Prompter prompter) {
this.prompter = prompter;
}

private void setConsensusProvider(ConsensusProvider consensusProvider) {
this.consensusProvider = consensusProvider;
}

@Override
public HashDigest initialize(int currentId, PrivKey privKey, LedgerInitProperties ledgerInitProps,
DBConnectionConfig dbConnConfig, Prompter prompter) {
return initialize(currentId, privKey, ledgerInitProps, dbConnConfig, prompter, createDefaultCryptoSetting());
}

@Override
public synchronized HashDigest initialize(int currentId, PrivKey privKey, LedgerInitProperties ledgerInitProps,
DBConnectionConfig dbConnConfig, Prompter prompter, CryptoSetting cryptoSetting) {

if (this.ledgerInitSetting != null) {
throw new IllegalStateException("ledger init process has already started.");
}

setPrompter(prompter);

ConsensusProvider csProvider = ConsensusProviders.getProvider(ledgerInitProps.getConsensusProvider());
setConsensusProvider(csProvider);

prompter.info("Init settings and sign permision...");

prepareLocalPermission(currentId, privKey, ledgerInitProps, null, cryptoSetting);

try {
// 连接数据库;
connectDb(dbConnConfig);

// 生成账本;
makeLocalDecision(privKey);

// 获取其它参与方的账本生成结果;
return consensusDecisions();
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
closeDb();
}
}

public DbConnection connectDb(DBConnectionConfig dbConnConfig) {
this.dbConn = dbConnFactory.connect(dbConnConfig.getUri(), dbConnConfig.getPassword());
return dbConn;
}

public LedgerInitDecision makeLocalDecision(PrivKey privKey) {
// 生成账本;
this.ledgerEditor = ledgerManager.newLedger(this.ledgerInitSetting, dbConn.getStorageService());
this.genesisBlock = initLedgerDataset(ledgerEditor);

// 生成签名决定;
this.localDecision = makeDecision(currentId, genesisBlock.getHash(), privKey);
this.decisions = new DecisionResultHandle[this.ledgerInitSetting.getConsensusParticipants().length];
for (int i = 0; i < decisions.length; i++) {
// 参与者的 id 是依次递增的;
this.decisions[i] = new DecisionResultHandle(i);
}
// 预置当前参与方的“决定”到列表,避免向自己发起请求;
this.decisions[currentId].setValue(localDecision);
return localDecision;
}

public HashDigest consensusDecisions() {
// 执行提交提交;
ledgerEditor.commit();
return genesisBlock.getHash();
}

public void closeDb() {
if (dbConn != null) {
DbConnection connection = dbConn;
dbConn = null;
try {
connection.close();
} catch (IOException e) {
prompter.error(e, "Error occurred on closing db connection! --" + e.getMessage());
}
}
}

public CryptoSetting createDefaultCryptoSetting() {
CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length];
for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) {
supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]);
}
CryptoConfig defCryptoSetting = new CryptoConfig();
defCryptoSetting.setSupportedProviders(supportedProviders);
defCryptoSetting.setAutoVerifyHash(true);
defCryptoSetting.setHashAlgorithm(Crypto.getAlgorithm("SHA256"));

return defCryptoSetting;
}

public LedgerInitPermission prepareLocalPermission(int currentId, PrivKey privKey, LedgerInitProperties ledgerProps,
ConsensusSettings csSettings, CryptoSetting cryptoSetting) {
// 创建初始化配置;
LedgerInitSettingData initSetting = new LedgerInitSettingData();
initSetting.setLedgerSeed(ledgerProps.getLedgerSeed());
initSetting.setCryptoSetting(cryptoSetting);

List<ConsensusParticipantConfig> partiList = ledgerProps.getConsensusParticipants();
ConsensusParticipantConfig[] parties = partiList.toArray(new ConsensusParticipantConfig[partiList.size()]);
ConsensusParticipantConfig[] orderedParties = sortAndVerify(parties);
initSetting.setConsensusParticipants(orderedParties);

// 创建默认的共识配置;
try {
byte[] csSettingBytes = new byte[1024];
new Random().nextBytes(csSettingBytes);

initSetting.setConsensusProvider(consensusProvider.getName());
initSetting.setConsensusSettings(new Bytes(csSettingBytes));
} catch (Exception e) {
throw new LedgerInitException("Create default consensus config failed! --" + e.getMessage(), e);
}

if (currentId < 0 || currentId >= orderedParties.length) {
throw new LedgerInitException("Your id is out of bound of participant list!");
}
this.currentId = currentId;
this.ledgerInitSetting = initSetting;

// 校验当前的公钥、私钥是否匹配;
byte[] testBytes = BytesUtils.toBytes(currentId);
SignatureDigest testSign = SIGN_FUNC.sign(privKey, testBytes);
PubKey myPubKey = orderedParties[currentId].getPubKey();
if (!SIGN_FUNC.verify(testSign, myPubKey, testBytes)) {
throw new LedgerInitException("Your pub-key specified in the init-settings isn't match your priv-key!");
}
// 生成初始化交易,并签署许可;
TransactionBuilder initTxBuilder = new TxBuilder(null);// 账本初始化交易的账本 hash 为 null;
initTxBuilder.ledgers().create(initSetting);
for (ParticipantNode p : initSetting.getConsensusParticipants()) {
// TODO:暂时只支持注册用户的初始化操作;
BlockchainIdentity superUserId = new BlockchainIdentityData(p.getPubKey());
initTxBuilder.users().register(superUserId);
}
this.initTxContent = initTxBuilder.prepareContent();

// 对初始交易签名,生成当前参与者的账本初始化许可;
SignatureDigest permissionSign = TxRequestBuilder.sign(initTxContent, privKey);
localPermission = new LedgerInitPermissionData(currentId, permissionSign);

this.currentId = currentId;
return localPermission;
}

private LedgerInitDecision makeDecision(int participantId, HashDigest ledgerHash, PrivKey privKey) {
byte[] dataBytes = getDecisionBytes(participantId, ledgerHash);
SignatureFunction signFunc = Crypto.getSignatureFunction(privKey.getAlgorithm());
SignatureDigest signature = signFunc.sign(privKey, dataBytes);

LedgerInitDecisionData decision = new LedgerInitDecisionData();
decision.setParticipantId(participantId);
decision.setLedgerHash(ledgerHash);
decision.setSignature(signature);
return decision;
}

private LedgerBlock initLedgerDataset(LedgerEditor ledgerEditor) {
// 初始化时,自动将参与方注册为账本的用户;
TxRequestBuilder txReqBuilder = new TxRequestBuilder(this.initTxContent);
// ParticipantNode[] parties = this.ledgerInitSetting.getConsensusParticipants();
ParticipantNode parti = this.ledgerInitSetting.getConsensusParticipants()[currentId];

PubKey pubKey = parti.getPubKey();
SignatureDigest signDigest = this.localPermission.getTransactionSignature();
DigitalSignatureBlob digitalSignature = new DigitalSignatureBlob(pubKey, signDigest);
txReqBuilder.addNodeSignature(digitalSignature);

TransactionRequest txRequest = txReqBuilder.buildRequest();

LedgerTransactionContext txCtx = ledgerEditor.newTransaction(txRequest);
Operation[] ops = txRequest.getTransactionContent().getOperations();
// 注册用户; 注:第一个操作是 LedgerInitOperation;
// TODO:暂时只支持注册用户的初始化操作;
for (int i = 1; i < ops.length; i++) {
UserRegisterOperation userRegOP = (UserRegisterOperation) ops[i];
txCtx.getDataSet().getUserAccountSet().register(userRegOP.getUserID().getAddress(),
userRegOP.getUserID().getPubKey());
}

txCtx.commit(TransactionState.SUCCESS);

return ledgerEditor.prepare();
}

private byte[] getDecisionBytes(int participantId, HashDigest ledgerHash) {
return BytesUtils.concat(BytesUtils.toBytes(participantId), ledgerHash.toBytes());
}

@Override
public LedgerInitPermission requestPermission(int requesterId, SignatureDigest signature) {
return localPermission;
}

@Override
public LedgerInitDecision synchronizeDecision(@RequestBody LedgerInitDecision initDecision) {
return localDecision;
}

/**
* 对参与者列表按照 id 进行升序排列,并校验id是否从 1 开始且没有跳跃;
*
* @param parties
* @return
*/
private ConsensusParticipantConfig[] sortAndVerify(ConsensusParticipantConfig[] parties) {
Arrays.sort(parties, (o1, o2) -> o1.getId() - o2.getId());
for (int i = 0; i < parties.length; i++) {
if (parties[i].getId() != i) {
throw new LedgerInitException(
"The ids of participants are not match their positions in the participant-list!");
}
}
return parties;
}

private static class DecisionResultHandle extends InvocationResult<LedgerInitDecision> {

private final int PARTICIPANT_ID;

public DecisionResultHandle(int participantId) {
this.PARTICIPANT_ID = participantId;
}

}

}

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

@@ -0,0 +1,461 @@
package com.jd.blockchain.mocker;

import com.jd.blockchain.binaryproto.DataContractRegistry;
import com.jd.blockchain.consensus.ClientIdentification;
import com.jd.blockchain.consensus.ClientIdentifications;
import com.jd.blockchain.consensus.action.ActionRequest;
import com.jd.blockchain.consensus.action.ActionResponse;
import com.jd.blockchain.crypto.*;
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm;
import com.jd.blockchain.crypto.service.classic.ClassicCryptoService;
import com.jd.blockchain.crypto.service.sm.SMCryptoService;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.CryptoConfig;
import com.jd.blockchain.ledger.core.LedgerDataSet;
import com.jd.blockchain.ledger.core.LedgerEditor;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
import com.jd.blockchain.ledger.core.impl.LedgerQueryService;
import com.jd.blockchain.ledger.core.impl.TransactionBatchProcessor;
import com.jd.blockchain.mocker.config.MockerConstant;
import com.jd.blockchain.mocker.config.PresetAnswerPrompter;
import com.jd.blockchain.mocker.handler.MockerContractExeHandle;
import com.jd.blockchain.mocker.handler.MockerOperationHandleRegister;
import com.jd.blockchain.mocker.proxy.ContractProxy;
import com.jd.blockchain.service.TransactionBatchResultHandle;
import com.jd.blockchain.storage.service.DbConnectionFactory;
import com.jd.blockchain.storage.service.utils.MemoryDBConnFactory;
import com.jd.blockchain.tools.initializer.DBConnectionConfig;
import com.jd.blockchain.tools.initializer.LedgerInitProperties;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.transaction.*;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.io.BytesUtils;
import com.jd.blockchain.web.serializes.ByteArrayObjectUtil;

import java.util.*;

import static java.lang.reflect.Proxy.newProxyInstance;

public class MockerNodeContext implements BlockchainQueryService {

private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(),
SMCryptoService.class.getName() };

private static final DBConnectionConfig dbConnectionConfig = new DBConnectionConfig("memory://local/0");

private DbConnectionFactory dbConnFactory = new MemoryDBConnFactory();

private MockerOperationHandleRegister opHandler = new MockerOperationHandleRegister();

private MockerContractExeHandle contractExeHandle = new MockerContractExeHandle();

private Map<String, BlockchainKeypair> participants = new HashMap<>();

private LedgerManager ledgerManager = new LedgerManager();

private BlockchainKeypair defaultKeypair;

private LedgerRepository ledgerRepository;

private LedgerQueryService queryService;

private HashDigest ledgerHash;

private String ledgerSeed;

static {
DataContractRegistry.register(TransactionContent.class);
DataContractRegistry.register(TransactionContentBody.class);
DataContractRegistry.register(TransactionRequest.class);
DataContractRegistry.register(NodeRequest.class);
DataContractRegistry.register(EndpointRequest.class);
DataContractRegistry.register(TransactionResponse.class);

DataContractRegistry.register(Operation.class);
DataContractRegistry.register(ContractCodeDeployOperation.class);
DataContractRegistry.register(ContractEventSendOperation.class);
DataContractRegistry.register(DataAccountRegisterOperation.class);
DataContractRegistry.register(UserRegisterOperation.class);
DataContractRegistry.register(DataAccountKVSetOperation.class);
DataContractRegistry.register(DataAccountKVSetOperation.KVWriteEntry.class);

DataContractRegistry.register(ActionRequest.class);
DataContractRegistry.register(ActionResponse.class);
DataContractRegistry.register(ClientIdentifications.class);
DataContractRegistry.register(ClientIdentification.class);

ByteArrayObjectUtil.init();
}

public MockerNodeContext() {
}

public MockerNodeContext(String ledgerSeed) {
this.ledgerSeed = ledgerSeed;
}

public MockerNodeContext participants(String name, BlockchainKeypair partiKey) {
participants.put(name, partiKey);
return this;
}

public MockerNodeContext participants(BlockchainKeypair partiKey) {
participants.put(partiKey.getPubKey().toBase58(), partiKey);
return this;
}

public MockerNodeContext build() {
if (ledgerSeed == null || ledgerSeed.length() == 0) {
ledgerSeed = MockerConstant.DEFAULT_LEDGER_SEED;
}
if (participants.size() < 4) {
// 缺少的需要补充,使用常量中的内容进行补充
for (int i = 0; i < MockerConstant.PUBLIC_KEYS.length; i++) {
String pubKeyString = MockerConstant.PUBLIC_KEYS[i];
boolean isExist = false;
// 通过公钥进行判断
for (Map.Entry<String, BlockchainKeypair> entry : participants.entrySet()) {
String existPubKey = KeyGenCommand.encodePubKey(entry.getValue().getPubKey());
if (pubKeyString.equals(existPubKey)) {
isExist = true;
}
}
if (!isExist) {
// 加入系统中
PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(MockerConstant.PRIVATE_KEYS[i], MockerConstant.PASSWORD);
PubKey pubKey = KeyGenCommand.decodePubKey(MockerConstant.PUBLIC_KEYS[i]);
participants(new BlockchainKeypair(pubKey, privKey));
}
if (participants.size() >= 4) {
break;
}
}
}

LedgerInitProperties ledgerInitProperties = loadInitSetting();

MockerLedgerInitializer mockLedgerInitializer = new MockerLedgerInitializer(dbConnFactory, ledgerManager);

ledgerHash = mockLedgerInitializer.initialize(0, defaultKeypair.getPrivKey(),
ledgerInitProperties, dbConnectionConfig, new PresetAnswerPrompter("N"), cryptoConfig());

ledgerRepository = registerLedger(ledgerHash, dbConnectionConfig);

queryService = new LedgerQueryService(ledgerManager);

contractExeHandle.initLedger(ledgerManager, ledgerHash);

opHandler.registerHandler(contractExeHandle);

return this;
}

public String registerUser(BlockchainKeypair user) {
TxBuilder txBuilder = txBuilder();
txBuilder.users().register(user.getIdentity());
txProcess(txRequest(txBuilder));
return user.getAddress().toBase58();
}

public String registerDataAccount(BlockchainKeypair dataAccount) {
TxBuilder txBuilder = txBuilder();
txBuilder.dataAccounts().register(dataAccount.getIdentity());
txProcess(txRequest(txBuilder));
return dataAccount.getAddress().toBase58();
}

public String registerDataAccount() {
return registerDataAccount(BlockchainKeyGenerator.getInstance().generate());
}

public void writeKv(String address, String key, String value, long version) {
TxBuilder txBuilder = txBuilder();
txBuilder.dataAccount(address).set(key, value, version);
txProcess(txRequest(txBuilder));
}

public void writeKv(String address, String key, long value, long version) {
TxBuilder txBuilder = txBuilder();
txBuilder.dataAccount(address).set(key, value, version);
txProcess(txRequest(txBuilder));
}

public void writeKv(String address, String key, byte[] value, long version) {
TxBuilder txBuilder = txBuilder();
txBuilder.dataAccount(address).set(key, value, version);
txProcess(txRequest(txBuilder));
}

public void writeKv(String address, String key, Bytes value, long version) {
TxBuilder txBuilder = txBuilder();
txBuilder.dataAccount(address).set(key, value, version);
txProcess(txRequest(txBuilder));
}

public <T> T deployContract(T contract) {
// 首先发布合约
BlockchainIdentity identity = deployContract2Ledger(contract);
// 生成代理对象
ContractProxy<T> contractProxy = new ContractProxy<>(identity, this,
contract, contractExeHandle);

T proxy = (T) newProxyInstance(contract.getClass().getClassLoader(),
contract.getClass().getInterfaces(), contractProxy);

return proxy;
}

private BlockchainIdentity deployContract2Ledger(Object contract) {
BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity();
// 合约发布
// 注意此处只是将其放入内存中,而不需要真正编译为字节码
TxBuilder txBuilder = txBuilder();
txBuilder.contracts().deploy(contractIdentity, BytesUtils.toBytes(contract.getClass().getName()));
// 执行
txProcess(txRequest(txBuilder));
return contractIdentity;
}

public String getLedgerSeed() {
return ledgerSeed;
}

public HashDigest getLedgerHash() {
return ledgerHash;
}

@Override
public HashDigest[] getLedgerHashs() {
return queryService.getLedgerHashs();
}

@Override
public LedgerInfo getLedger(HashDigest ledgerHash) {
return queryService.getLedger(ledgerHash);
}

@Override
public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) {
return queryService.getConsensusParticipants(ledgerHash);
}

@Override
public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) {
return queryService.getLedgerMetadata(ledgerHash);
}

@Override
public LedgerBlock getBlock(HashDigest ledgerHash, long height) {
return queryService.getBlock(ledgerHash, height);
}

@Override
public LedgerBlock getBlock(HashDigest ledgerHash, HashDigest blockHash) {
return queryService.getBlock(ledgerHash, blockHash);
}

@Override
public long getTransactionCount(HashDigest ledgerHash, long height) {
return queryService.getTransactionCount(ledgerHash, height);
}

@Override
public long getTransactionCount(HashDigest ledgerHash, HashDigest blockHash) {
return queryService.getTransactionCount(ledgerHash, blockHash);
}

@Override
public long getTransactionTotalCount(HashDigest ledgerHash) {
return queryService.getTransactionTotalCount(ledgerHash);
}

@Override
public long getDataAccountCount(HashDigest ledgerHash, long height) {
return queryService.getDataAccountCount(ledgerHash, height);
}

@Override
public long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash) {
return queryService.getDataAccountCount(ledgerHash, blockHash);
}

@Override
public long getDataAccountTotalCount(HashDigest ledgerHash) {
return queryService.getDataAccountTotalCount(ledgerHash);
}

@Override
public long getUserCount(HashDigest ledgerHash, long height) {
return queryService.getUserCount(ledgerHash, height);
}

@Override
public long getUserCount(HashDigest ledgerHash, HashDigest blockHash) {
return queryService.getUserCount(ledgerHash, blockHash);
}

@Override
public long getUserTotalCount(HashDigest ledgerHash) {
return queryService.getUserTotalCount(ledgerHash);
}

@Override
public long getContractCount(HashDigest ledgerHash, long height) {
return queryService.getContractCount(ledgerHash, height);
}

@Override
public long getContractCount(HashDigest ledgerHash, HashDigest blockHash) {
return queryService.getContractCount(ledgerHash, blockHash);
}

@Override
public long getContractTotalCount(HashDigest ledgerHash) {
return queryService.getContractTotalCount(ledgerHash);
}

@Override
public LedgerTransaction[] getTransactions(HashDigest ledgerHash, long height, int fromIndex, int count) {
return queryService.getTransactions(ledgerHash, height, fromIndex, count);
}

@Override
public LedgerTransaction[] getTransactions(HashDigest ledgerHash, HashDigest blockHash, int fromIndex, int count) {
return queryService.getTransactions(ledgerHash, blockHash, fromIndex, count);
}

@Override
public LedgerTransaction getTransactionByContentHash(HashDigest ledgerHash, HashDigest contentHash) {
return queryService.getTransactionByContentHash(ledgerHash, contentHash);
}

@Override
public TransactionState getTransactionStateByContentHash(HashDigest ledgerHash, HashDigest contentHash) {
return queryService.getTransactionStateByContentHash(ledgerHash, contentHash);
}

@Override
public UserInfo getUser(HashDigest ledgerHash, String address) {
return queryService.getUser(ledgerHash, address);
}

@Override
public AccountHeader getDataAccount(HashDigest ledgerHash, String address) {
return queryService.getDataAccount(ledgerHash, address);
}

@Override
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) {
return queryService.getDataEntries(ledgerHash, address, keys);
}

@Override
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) {
return queryService.getDataEntries(ledgerHash, address, kvInfoVO);
}

@Override
public long getDataEntriesTotalCount(HashDigest ledgerHash, String address) {
return queryService.getDataEntriesTotalCount(ledgerHash, address);
}

@Override
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) {
return queryService.getDataEntries(ledgerHash, address, fromIndex, count);
}

@Override
public AccountHeader getContract(HashDigest ledgerHash, String address) {
return queryService.getContract(ledgerHash, address);
}

@Override
public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) {
return queryService.getUsers(ledgerHash, fromIndex, count);
}

@Override
public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) {
return queryService.getDataAccounts(ledgerHash, fromIndex, count);
}

@Override
public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) {
return queryService.getContractAccounts(ledgerHash, fromIndex, count);
}

public TxBuilder txBuilder() {
return new TxBuilder(ledgerHash);
}

public TransactionRequest txRequest(TxBuilder txBuilder) {
TransactionRequestBuilder reqBuilder = txBuilder.prepareRequest();
reqBuilder.signAsEndpoint(defaultKeypair);
return reqBuilder.buildRequest();
}

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

private LedgerRepository registerLedger(HashDigest ledgerHash, DBConnectionConfig dbConnConf) {
return ledgerManager.register(ledgerHash, dbConnFactory.connect(dbConnConf.getUri()).getStorageService());
}

private CryptoConfig cryptoConfig() {
CryptoProvider[] supportedProviders = new CryptoProvider[SUPPORTED_PROVIDERS.length];
for (int i = 0; i < SUPPORTED_PROVIDERS.length; i++) {
supportedProviders[i] = Crypto.getProvider(SUPPORTED_PROVIDERS[i]);
}
CryptoConfig cryptoSetting = new CryptoConfig();
cryptoSetting.setSupportedProviders(supportedProviders);
cryptoSetting.setAutoVerifyHash(false);
cryptoSetting.setHashAlgorithm(ClassicAlgorithm.SHA256);
return cryptoSetting;
}

private LedgerInitProperties loadInitSetting() {

Properties ledgerProp = new Properties();

ledgerProp.put(LedgerInitProperties.LEDGER_SEED, ledgerSeed);

ledgerProp.put("ledger.name", MockerConstant.LEDGER_NAME);

ledgerProp.put(LedgerInitProperties.CONSENSUS_SERVICE_PROVIDER, "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider");

ledgerProp.put(LedgerInitProperties.CONSENSUS_CONFIG, "classpath:bftsmart.config");

ledgerProp.put(LedgerInitProperties.CRYPTO_SERVICE_PROVIDERS, "com.jd.blockchain.crypto.service.classic.ClassicCryptoService," +
"com.jd.blockchain.crypto.service.sm.SMCryptoService");

ledgerProp.put(LedgerInitProperties.PART_COUNT, String.valueOf(participants.size()));

int partiIndex = 0;
for (Map.Entry<String, BlockchainKeypair> entry : participants.entrySet()) {
String name = entry.getKey();
BlockchainKeypair keypair = entry.getValue();
if (partiIndex == 0) {
defaultKeypair = keypair;
}
String partiPrefix = String.format(LedgerInitProperties.PART_ID_PATTERN, partiIndex) + ".";
ledgerProp.put(partiPrefix + LedgerInitProperties.PART_NAME, name);
ledgerProp.put(partiPrefix + LedgerInitProperties.PART_PUBKEY_PATH, "");
ledgerProp.put(partiPrefix + LedgerInitProperties.PART_PUBKEY, KeyGenCommand.encodePubKey(keypair.getPubKey()));
ledgerProp.put(partiPrefix + LedgerInitProperties.PART_INITIALIZER_HOST, MockerConstant.LOCAL_ADDRESS);
ledgerProp.put(partiPrefix + LedgerInitProperties.PART_INITIALIZER_PORT, String.valueOf(MockerConstant.LEDGER_INIT_PORT_START + partiIndex * 10));
ledgerProp.put(partiPrefix + LedgerInitProperties.PART_INITIALIZER_SECURE, String.valueOf(false));
partiIndex++;
}

return LedgerInitProperties.resolve(ledgerProp);
}
}

+ 22
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/LedgerInitWebConfiguration.java View File

@@ -0,0 +1,22 @@
package com.jd.blockchain.mocker.config;

import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory;
import com.jd.blockchain.tools.initializer.web.InitWebSecurityConfiguration;
import com.jd.blockchain.tools.initializer.web.InitWebServerConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@Configuration
@EnableConfigurationProperties
@Import(value = { InitWebServerConfiguration.class, InitWebSecurityConfiguration.class })
public class LedgerInitWebConfiguration {

@Bean
public CompositeConnectionFactory getCompositeConnectionFactory() {
return new CompositeConnectionFactory();
}
}

+ 67
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/MockerConstant.java View File

@@ -0,0 +1,67 @@
package com.jd.blockchain.mocker.config;

public class MockerConstant {

public static final String DEFAULT_LEDGER_SEED = "932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffa";

public static final int PEER_PORT_START = 12000;

public static final int LEDGER_INIT_PORT_START = 1600;

public static final int GATEWAY_PORT = 11000;

public static final String LOCAL_ADDRESS = "127.0.0.1";

public static final String LEDGER_NAME = "JDChain";

public static final String LEDGER_INIT_FORMATTER = "ledger%s.init";

public static final String[] CONSENSUS_PROVIDERS = new String[] {"com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"};

public static final String PASSWORD = "abc";

public static final String PASSWORD_ENCODE = "DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY";

public static final String[] PUBLIC_KEYS = {
"3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9",
"3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX",
"3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x",
"3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk",
"3snPdw7i7PXPRMp3EAjsxJkHe7aZJRLNzdW8kEHBWeQsSgcPAiHP2J",
"3snPdw7i7PmmQoPgUpUmmAUj6nakHj8wMSQmiMi1RaiZp4YU1D4AXk",
"3snPdw7i7PiJKsa94q3EcLT1y6GRJ7LeFGe799hdzRRHmf6LNodyiM",
"3snPdw7i7Pm2wJwEnKn8kK8eGTkN36C2BZRRjVTr9FPB2rqtcgTq7h"
};

public static final String[] ADDRESS_ARRAY = {
"LdeP3fY7jJbNwL8CiL2wU21AF9unDWQjVEW5w",
"LdeNnz88dH6CA6PwkVdn3nFRibUKP3sFT2byG",
"LdeNmdpT4DiTwLUP9jRQhwdRBRiXeHno456vy",
"LdeNekdXMHqyz9Qxc2jDSBnkvvZLbty6pRDdP",
"LdeNryu2DK96tDvtLJfBz7ArWynAWPJAep38n",
"LdeNkoQpXffVF9qjsa4A7wZVgT9W2vnhpEEm5",
"LdeNzfFrsJT7Ni1L7k1EP3NuxUfK8QGAxMGpt",
"LdeNuLhR5AoyhQoVeS15haJvvGC5ByoPezrGq"
};

public static final String[] PRIVATE_KEYS = {
"177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x",
"177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT",
"177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF",
"177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns",
"177gjwyHzfmsD4g3MVB655seYWXua2KBdQEqTf9kHgeMc6gdRZADKb6cL13L5koqMsBtkGX",
"177gk2C9V7gwPhAGgawL53W8idDpSo63jnbg8finbZkk4zermr5aqgTeKspN45fbymey8t6",
"177gjtz29TXa2E3FFBpCNr5LpU5zYxkNPAgcAJZW7tCGUgWQr4gcVv8PHmoVVPeSVVnyZV5",
"177gjzpHnqGEuSKyi3pW69WhpEPmeFPxLNVmUfXQb4DDV2EfnMgY7T4NFsyRsThjJFsau7X"};

public static final String[] DB_MEMS = {
"memory://127.0.0.1/0",
"memory://127.0.0.1/1",
"memory://127.0.0.1/2",
"memory://127.0.0.1/3",
"memory://127.0.0.1/4",
"memory://127.0.0.1/5",
"memory://127.0.0.1/6",
"memory://127.0.0.1/7"
};
}

+ 32
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/PresetAnswerPrompter.java View File

@@ -0,0 +1,32 @@
package com.jd.blockchain.mocker.config;

import com.jd.blockchain.tools.initializer.ConsolePrompter;

import java.util.Properties;

public class PresetAnswerPrompter extends ConsolePrompter {

private Properties answers = new Properties();

private String defaultAnswer;

public PresetAnswerPrompter(String defaultAnswer) {
this.defaultAnswer = defaultAnswer;
}

public void setAnswer(String tag, String answer) {
answers.setProperty(tag, answer);
}

public void setDefaultAnswer(String defaultAnswer) {
this.defaultAnswer = defaultAnswer;
}

@Override
public String confirm(String tag, String format, Object... args) {
System.out.print(String.format(format, args));
String answer = answers.getProperty(tag, defaultAnswer);
System.out.println(String.format("\r\n [Mocked answer:%s]", answer));
return answer;
}
}

+ 17
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContract.java View File

@@ -0,0 +1,17 @@
package com.jd.blockchain.mocker.contracts;

import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;

@Contract
public interface AccountContract {

@ContractEvent(name = "create")
void create(String address, String account, long money);

@ContractEvent(name = "transfer")
void transfer(String address, String from, String to, long money);

@ContractEvent(name = "print")
void print(String address, String from, String to);
}

+ 81
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java View File

@@ -0,0 +1,81 @@
package com.jd.blockchain.mocker.contracts;

import com.jd.blockchain.contract.ContractEventContext;
import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.contract.EventProcessingAwire;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.KVDataEntry;

public class AccountContractImpl implements EventProcessingAwire, AccountContract {

private ContractEventContext eventContext;

private HashDigest ledgerHash;

@Override
public void create(String address, String account, long money) {
// 暂不处理该账户已经存在的问题
eventContext.getLedger().dataAccount(address).set(account, money, -1);
}

@Override
public void transfer(String address, String from, String to, long money) {
// 首先分别查询from与to的结果
KVDataEntry[] dataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to);
long currentFromMoney = 0L, currentToMoney = 0L, currentFromVer = -1L, currentToVer = -1L;
if (dataEntries != null && dataEntries.length > 0) {
for (KVDataEntry dataEntry : dataEntries) {
String key = dataEntry.getKey();
Object value = dataEntry.getValue();
long version = dataEntry.getVersion();
if (key.equals(from)) {
currentFromMoney = (long) value;
currentFromVer = version;
}
if (key.equals(to)) {
currentToMoney = (long) value;
currentToVer = version;
}
}
}
currentFromMoney -= money;
currentToMoney += money;
// 重新设置结果
eventContext.getLedger().dataAccount(address).set(from, currentFromMoney, currentFromVer)
.set(to, currentToMoney, currentToVer);
}

@Override
public void print(String address, String from, String to) {
KVDataEntry[] dataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to);
if (dataEntries != null && dataEntries.length > 0) {
for (KVDataEntry dataEntry : dataEntries) {
String key = dataEntry.getKey();
Object value = dataEntry.getValue();
long version = dataEntry.getVersion();
System.out.printf("Key = %s Value = %s Version = %s \r\n", key, value, version);
}
}
}

@Override
public void beforeEvent(ContractEventContext eventContext) {
this.eventContext = eventContext;
this.ledgerHash = this.eventContext.getCurrentLedgerHash();
}

@Override
public void postEvent(ContractEventContext eventContext, ContractException error) {

}

@Override
public void postEvent(ContractException error) {

}

@Override
public void postEvent() {

}
}

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

@@ -0,0 +1,14 @@
package com.jd.blockchain.mocker.contracts;

import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;

@Contract
public interface WriteContract {

@ContractEvent(name = "print")
void print(String name);

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

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

@@ -0,0 +1,41 @@
package com.jd.blockchain.mocker.contracts;

import com.jd.blockchain.contract.ContractEventContext;
import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.contract.EventProcessingAwire;

public class WriteContractImpl implements EventProcessingAwire, WriteContract {

private ContractEventContext eventContext;

@Override
public void print(String name) {
System.out.printf("My Name is %s \r\n", name);
System.out.printf("My Ledger Hash is %s \r\n", eventContext.getCurrentLedgerHash().toBase58());
}

@Override
public void writeKv(String address, String key, String value) {
eventContext.getLedger().dataAccount(address).set(key, value, -1);
}

@Override
public void beforeEvent(ContractEventContext eventContext) {
this.eventContext = eventContext;
}

@Override
public void postEvent(ContractEventContext eventContext, ContractException error) {
System.out.println("----- postEvent1 -----");
}

@Override
public void postEvent(ContractException error) {
System.out.println("----- postEvent2 -----");
}

@Override
public void postEvent() {
System.out.println("----- postEvent3 -----");
}
}

+ 54
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/KvData.java View File

@@ -0,0 +1,54 @@
package com.jd.blockchain.mocker.data;

public class KvData {

private String dataAccount;

private String key;

private byte[] value;

private long version;

public KvData() {
}

public KvData(String dataAccount, String key, byte[] value, long version) {
this.dataAccount = dataAccount;
this.key = key;
this.value = value;
this.version = version;
}

public String getDataAccount() {
return dataAccount;
}

public String getKey() {
return key;
}

public byte[] getValue() {
return value;
}

public long getVersion() {
return version;
}

public void setDataAccount(String dataAccount) {
this.dataAccount = dataAccount;
}

public void setKey(String key) {
this.key = key;
}

public void setValue(byte[] value) {
this.value = value;
}

public void setVersion(long version) {
this.version = version;
}
}

+ 38
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/ResponseData.java View File

@@ -0,0 +1,38 @@
package com.jd.blockchain.mocker.data;

import com.jd.blockchain.ledger.TransactionResponse;

public class ResponseData<T> {

private TransactionResponse txResponse;

private T data;

public ResponseData() {
}

public ResponseData(TransactionResponse txResponse) {
this.txResponse = txResponse;
}

public ResponseData(TransactionResponse txResponse, T data) {
this.txResponse = txResponse;
this.data = data;
}

public TransactionResponse getTxResponse() {
return txResponse;
}

public T getData() {
return data;
}

public void setTxResponse(TransactionResponse txResponse) {
this.txResponse = txResponse;
}

public void setData(T data) {
this.data = data;
}
}

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

@@ -0,0 +1,136 @@
package com.jd.blockchain.mocker.handler;

import com.jd.blockchain.contract.ContractEventContext;
import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.contract.EventProcessingAwire;
import com.jd.blockchain.contract.LedgerContext;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.ContractEventSendOperation;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.ledger.core.*;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
import com.jd.blockchain.ledger.core.impl.LedgerQueryService;
import com.jd.blockchain.ledger.core.impl.OperationHandleContext;
import com.jd.blockchain.ledger.core.impl.handles.ContractLedgerContext;
import com.jd.blockchain.mocker.proxy.ExecutorProxy;

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


public class MockerContractExeHandle implements OperationHandle {

private Map<HashDigest, ExecutorProxy> executorProxyMap = new ConcurrentHashMap<>();

private LedgerManager ledgerManager;

private HashDigest ledgerHash;

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

HashDigest txHash = requestContext.getRequest().getTransactionContent().getHash();

ExecutorProxy executorProxy = executorProxyMap.get(txHash);

if (executorProxy != null) {
LedgerQueryService queryService = new LedgerQueryService(ledgerManager);
ContractLedgerContext ledgerContext = new ContractLedgerContext(queryService, opHandleContext);

MockerContractEventContext contractEventContext = new MockerContractEventContext(
ledgerHash, contractOP.getEvent(), requestContext.getRequest(), ledgerContext);

EventProcessingAwire eventProcessingAwire = (EventProcessingAwire) executorProxy.getInstance();
try {
//
// Before处理过程
eventProcessingAwire.beforeEvent(contractEventContext);
executorProxy.invoke();

// After处理过程
eventProcessingAwire.postEvent();
} catch (Exception e) {
eventProcessingAwire.postEvent(new ContractException(e.getMessage()));
} finally {
removeExecutorProxy(txHash);
}
}
}

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

public void initLedger(LedgerManager ledgerManager, HashDigest ledgerHash) {
this.ledgerManager = ledgerManager;
this.ledgerHash = ledgerHash;
}

public void registerExecutorProxy(HashDigest hashDigest, ExecutorProxy executorProxy) {
executorProxyMap.put(hashDigest, executorProxy);
}

public ExecutorProxy removeExecutorProxy(HashDigest hashDigest) {
return executorProxyMap.remove(hashDigest);
}

public static class MockerContractEventContext implements ContractEventContext {

private HashDigest ledgeHash;

private String event;

private TransactionRequest transactionRequest;

private LedgerContext ledgerContext;

public MockerContractEventContext(HashDigest ledgeHash, String event,
TransactionRequest transactionRequest, LedgerContext ledgerContext) {
this.ledgeHash = ledgeHash;
this.event = event;
this.transactionRequest = transactionRequest;
this.ledgerContext = ledgerContext;
}

@Override
public HashDigest getCurrentLedgerHash() {
return ledgeHash;
}

@Override
public TransactionRequest getTransactionRequest() {
return transactionRequest;
}

@Override
public Set<BlockchainIdentity> getTxSigners() {
return null;
}

@Override
public String getEvent() {
return event;
}

@Override
public byte[] getArgs() {
return null;
}

@Override
public LedgerContext getLedger() {
return ledgerContext;
}

@Override
public Set<BlockchainIdentity> getContracOwners() {
return null;
}
}
}

+ 189
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerNodeHandler.java View File

@@ -0,0 +1,189 @@
package com.jd.blockchain.mocker.handler;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.gateway.GatewayConfigProperties;
import com.jd.blockchain.mocker.config.MockerConstant;
import com.jd.blockchain.mocker.config.PresetAnswerPrompter;
import com.jd.blockchain.mocker.node.GatewayNodeRunner;
import com.jd.blockchain.mocker.node.NodeWebContext;
import com.jd.blockchain.mocker.node.PeerNodeRunner;
import com.jd.blockchain.tools.initializer.DBConnectionConfig;
import com.jd.blockchain.tools.initializer.LedgerBindingConfig;
import com.jd.blockchain.tools.initializer.LedgerInitProperties;
import com.jd.blockchain.tools.initializer.Prompter;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.concurrent.ThreadInvoker;
import com.jd.blockchain.utils.net.NetworkAddress;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileInputStream;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.jd.blockchain.mocker.config.MockerConstant.*;

public class MockerNodeHandler {

private static final String LEDGER_BINDING_FORMAT = "binding.%s.";

private static final String PARTI_FORMAT = LEDGER_BINDING_FORMAT + "parti.";

private static final String BINDING_ID_FORMAT = PARTI_FORMAT + "id";

private static final String BINDING_PK_PATH_FORMAT = PARTI_FORMAT + "pk-path";

private static final String BINDING_PK_FORMAT = PARTI_FORMAT + "pk";

private static final String BINDING_PWD_FORMAT = PARTI_FORMAT + "pwd";

private static final String BINDING_ADDRESS_FORMAT = PARTI_FORMAT + "address";

private static final String DB_FORMAT = LEDGER_BINDING_FORMAT + "db.";

private static final String BINDING_DB_URI_FORMAT = DB_FORMAT + "uri";

private static final String BINDING_DB_PWD_FORMAT = DB_FORMAT + "pwd";

private PeerNodeRunner[] peerNodes;

private GatewayNodeRunner gatewayNodeRunner;

public void start(int nodeSize) throws Exception {

HashDigest ledgerHash = ledgerInit(nodeSize);

// 启动Peer节点
peerNodes = peerNodeStart(nodeSize, ledgerHash);

// 启动网关节点
gatewayNodeRunner = gatewayNodeStart(peerNodes[0].getServiceAddress());
}

public LedgerInitProperties initLedgerProperties(int nodeSize) throws Exception {

File ledgerInitFile = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX +
String.format(MockerConstant.LEDGER_INIT_FORMATTER, nodeSize));

final LedgerInitProperties ledgerInitProperties = LedgerInitProperties.resolve(new FileInputStream(ledgerInitFile));

return ledgerInitProperties;
}

private HashDigest ledgerInit(int nodeSize) throws Exception {

System.out.println("----------- is daemon=" + Thread.currentThread().isDaemon());

Prompter consolePrompter = new PresetAnswerPrompter("N"); // new ConsolePrompter();

LedgerInitProperties initSetting = initLedgerProperties(nodeSize);

Set<HashDigest> hashDigestSet = new HashSet<>();

CountDownLatch quitLatch = new CountDownLatch(nodeSize);

ExecutorService peerThreads = Executors.newFixedThreadPool(nodeSize);

for (int i = 0; i < nodeSize; i++) {
final int nodeIndex = i;
peerThreads.execute(() -> {
// 启动服务器;
NetworkAddress initAddr = initSetting.getConsensusParticipant(nodeIndex).getInitializerAddress();
NodeWebContext node = new NodeWebContext(nodeIndex, initAddr);
PrivKey privkey = KeyGenCommand.decodePrivKeyWithRawPassword(PRIVATE_KEYS[nodeIndex], PASSWORD);
DBConnectionConfig dbConn = new DBConnectionConfig();
dbConn.setConnectionUri(MockerConstant.DB_MEMS[nodeIndex]);
ThreadInvoker.AsyncCallback<HashDigest> nodeCallback = node.startInit(privkey, initSetting, dbConn, consolePrompter,
quitLatch);
hashDigestSet.add(nodeCallback.waitReturn());
});
}

quitLatch.await();

if (hashDigestSet.size() != 1) {
throw new IllegalStateException(String.format("%s Node Ledger Init Fail !!!", nodeSize));
}
return hashDigestSet.toArray(new HashDigest[hashDigestSet.size()])[0];
}


public PeerNodeRunner[] peerNodeStart(int nodeSize, HashDigest ledgerHash) {

int portStart = PEER_PORT_START;

List<ThreadInvoker.AsyncCallback<Object>> threadInvokers = new ArrayList<>();

final PeerNodeRunner[] peerNodeRunners = new PeerNodeRunner[nodeSize];

for (int i = 0; i < nodeSize; i++) {
NetworkAddress peerSrvAddr = new NetworkAddress(LOCAL_ADDRESS, portStart);
LedgerBindingConfig bindingConfig = loadBindingConfig(i, ledgerHash);
PeerNodeRunner peerNodeRunner = new PeerNodeRunner(peerSrvAddr, bindingConfig);
peerNodeRunners[i] = peerNodeRunner;
portStart += 10;
threadInvokers.add(peerNodeRunner.start());
}

// 等待结果
for (ThreadInvoker.AsyncCallback<Object> threadInvoker : threadInvokers) {
threadInvoker.waitReturn();
}

return peerNodeRunners;
}

public GatewayNodeRunner gatewayNodeStart(NetworkAddress peerAddress) {
GatewayConfigProperties.KeyPairConfig gwKeyPair = new GatewayConfigProperties.KeyPairConfig();
gwKeyPair.setPubKeyValue(PUBLIC_KEYS[0]);
gwKeyPair.setPrivKeyValue(PRIVATE_KEYS[0]);
gwKeyPair.setPrivKeyPassword(PASSWORD_ENCODE);
GatewayNodeRunner gateway = new GatewayNodeRunner(LOCAL_ADDRESS, GATEWAY_PORT, gwKeyPair,
peerAddress, CONSENSUS_PROVIDERS,null);

ThreadInvoker.AsyncCallback<Object> gwStarting = gateway.start();

gwStarting.waitReturn();

return gateway;
}

public void stop() {
if (peerNodes != null) {
for (PeerNodeRunner peerNodeRunner : peerNodes) {
peerNodeRunner.stop();
}
}
if (gatewayNodeRunner != null) {
gatewayNodeRunner.stop();
}
}

private LedgerBindingConfig loadBindingConfig(int nodeIndex, HashDigest ledgerHash) {

Properties properties = new Properties();

String ledgerHashBase58 = ledgerHash.toBase58();

properties.put("ledger.bindings", ledgerHashBase58);

properties.put(String.format(BINDING_ID_FORMAT, ledgerHashBase58), nodeIndex);

properties.put(String.format(BINDING_PK_PATH_FORMAT, ledgerHashBase58), "");

properties.put(String.format(BINDING_PK_FORMAT, ledgerHashBase58), PUBLIC_KEYS[nodeIndex]);

properties.put(String.format(BINDING_PWD_FORMAT, ledgerHashBase58), PASSWORD_ENCODE);

properties.put(String.format(BINDING_ADDRESS_FORMAT, ledgerHashBase58), ADDRESS_ARRAY[nodeIndex]);

properties.put(String.format(BINDING_DB_URI_FORMAT, ledgerHashBase58), DB_MEMS[nodeIndex]);

properties.put(String.format(BINDING_DB_PWD_FORMAT, ledgerHashBase58), "");

return LedgerBindingConfig.resolve(properties);
}
}

+ 51
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerOperationHandleRegister.java View File

@@ -0,0 +1,51 @@
package com.jd.blockchain.mocker.handler;

import com.jd.blockchain.ledger.core.LedgerException;
import com.jd.blockchain.ledger.core.OperationHandle;
import com.jd.blockchain.ledger.core.impl.OperationHandleRegisteration;
import com.jd.blockchain.ledger.core.impl.handles.*;

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

public class MockerOperationHandleRegister implements OperationHandleRegisteration {

private List<OperationHandle> opHandles = new ArrayList<>();
public MockerOperationHandleRegister() {
initDefaultHandles();
}

/**
* 针对不采用bean依赖注入的方式来处理;
*/
private void initDefaultHandles(){
opHandles.add(new DataAccountKVSetOperationHandle());
opHandles.add(new DataAccountRegisterOperationHandle());
opHandles.add(new UserRegisterOperationHandle());
opHandles.add(new ContractCodeDeployOperationHandle());
// opHandles.add(new ContractEventSendOperationHandle());
}

public List<OperationHandle> getOpHandles() {
return opHandles;
}

public void registerHandler(OperationHandle operationHandle) {
opHandles.add(operationHandle);
}

public void removeHandler(OperationHandle operationHandle) {
opHandles.remove(operationHandle);
}

@Override
public OperationHandle getHandle(Class<?> operationType) {
for (OperationHandle handle : opHandles) {
if (handle.support(operationType)) {
return handle;
}
}
throw new LedgerException("Unsupported operation type[" + operationType.getName() + "]!");
}
}

+ 216
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerServiceHandler.java View File

@@ -0,0 +1,216 @@
package com.jd.blockchain.mocker.handler;

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.mocker.config.MockerConstant;
import com.jd.blockchain.mocker.data.KvData;
import com.jd.blockchain.mocker.data.ResponseData;
import com.jd.blockchain.sdk.BlockchainService;
import com.jd.blockchain.sdk.client.GatewayServiceFactory;
import com.jd.blockchain.tools.keygen.KeyGenCommand;

public class MockerServiceHandler {

private BlockchainKeypair defaultParticipant;

private BlockchainKeypair defaultUser;

private BlockchainKeypair defaultDataAccount;

private String gatewayHost;

private int gatewayPort;

private GatewayServiceFactory gatewayServiceFactory;

private BlockchainService blockchainService;

private HashDigest ledgerHash;

public MockerServiceHandler(String gatewayHost, int gatewayPort) {
this.gatewayHost = gatewayHost;
this.gatewayPort = gatewayPort;
init();
}

public BlockchainKeypair getDefaultParticipant() {
return defaultParticipant;
}

public BlockchainKeypair getDefaultUser() {
return defaultUser;
}

public BlockchainKeypair getDefaultDataAccount() {
return defaultDataAccount;
}

public String getDefaultDataAccountAddress() {
return defaultDataAccount.getAddress().toBase58();
}

public String getGatewayHost() {
return gatewayHost;
}

public int getGatewayPort() {
return gatewayPort;
}

public GatewayServiceFactory getGatewayServiceFactory() {
return gatewayServiceFactory;
}

public BlockchainService getBlockchainService() {
return blockchainService;
}

public HashDigest getLedgerHash() {
return ledgerHash;
}

private void init() {

defaultParticipant = defaultParticipant();

gatewayServiceFactory = GatewayServiceFactory.connect(gatewayHost, gatewayPort,
false, defaultParticipant);

blockchainService = gatewayServiceFactory.getBlockchainService();

HashDigest[] ledgerHashs = blockchainService.getLedgerHashs();

ledgerHash = ledgerHashs[0];

// 默认注册部分内容
// 注册一个用户和一个数据账户
TransactionTemplate txTemplate = blockchainService.newTransaction(ledgerHash);

defaultUser = newKeypair();

defaultDataAccount = newKeypair();

// 注册用户
txTemplate.users().register(defaultUser.getIdentity());

// 注册数据账户
txTemplate.dataAccounts().register(defaultDataAccount.getIdentity());

// TX 准备就绪;
PreparedTransaction prepTx = txTemplate.prepare();

// 使用私钥进行签名;
prepTx.sign(defaultParticipant);

// 提交交易;
TransactionResponse txResponse = prepTx.commit();

System.out.printf("Commit Transaction Result = %s \r\n", txResponse.isSuccess());
}

public BlockchainKeypair newKeypair() {
return BlockchainKeyGenerator.getInstance().generate();
}

private BlockchainKeypair defaultParticipant() {
PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(MockerConstant.PRIVATE_KEYS[0], MockerConstant.PASSWORD);
PubKey pubKey = KeyGenCommand.decodePubKey(MockerConstant.PUBLIC_KEYS[0]);
return new BlockchainKeypair(pubKey, privKey);
}

public ResponseData<KvData> writeKv(String key, byte[] value) {
return writeKv(key, value, -1);
}

public ResponseData<KvData> writeKv(String key, byte[] value, long version) {
return writeKv(getDefaultDataAccountAddress(), key, value, version);
}

public ResponseData<KvData> writeKv(String dataAccount, String key, byte[] value) {
return writeKv(dataAccount, key, value, -1);
}

public ResponseData<KvData> writeKv(String dataAccount, String key, byte[] value, long version) {

TransactionTemplate txTemplate = newTxTemplate();

txTemplate.dataAccount(dataAccount).set(key, value, version);

TransactionResponse txResponse = txPrepareAndCommit(txTemplate);

long saveVersion = version;

if (txResponse.isSuccess()) {
saveVersion = version + 1;
}

KvData kvData = new KvData(dataAccount, key, value, saveVersion);

return new ResponseData(txResponse, kvData);
}

public ResponseData<BlockchainKeypair> registerUser() {

BlockchainKeypair newUser = BlockchainKeyGenerator.getInstance().generate();

return registerUser(newUser);
}

public ResponseData<BlockchainKeypair> registerUser(BlockchainKeypair user) {

TransactionTemplate txTemplate = newTxTemplate();

// 注册
txTemplate.users().register(user.getIdentity());

TransactionResponse txResponse = txPrepareAndCommit(txTemplate);

return new ResponseData(txResponse, user);
}

public ResponseData<BlockchainKeypair> registerDataAccount() {

BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate();

return registerDataAccount(newDataAccount);
}

public ResponseData<BlockchainKeypair> registerDataAccount(BlockchainKeypair dataAccount) {

TransactionTemplate txTemplate = newTxTemplate();

// 注册
txTemplate.dataAccounts().register(dataAccount.getIdentity());

TransactionResponse txResponse = txPrepareAndCommit(txTemplate);

return new ResponseData(txResponse, dataAccount);
}

public ResponseData<Object> deployContract() {
return null;
}

public ResponseData<Object> executeContract() {
return null;
}

private TransactionTemplate newTxTemplate() {
return blockchainService.newTransaction(ledgerHash);
}

private TransactionResponse txPrepareAndCommit(TransactionTemplate txTemplate) {
// TX 准备就绪;
PreparedTransaction prepTx = txTemplate.prepare();

// 使用私钥进行签名;
prepTx.sign(defaultParticipant);

// 提交交易;
TransactionResponse txResponse = prepTx.commit();

return txResponse;
}
}

+ 75
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/GatewayNodeRunner.java View File

@@ -0,0 +1,75 @@
package com.jd.blockchain.mocker.node;

import com.jd.blockchain.gateway.GatewayConfigProperties;
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig;
import com.jd.blockchain.gateway.GatewayServerBooter;
import com.jd.blockchain.utils.concurrent.ThreadInvoker;
import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback;
import com.jd.blockchain.utils.net.NetworkAddress;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.CollectionUtils;

import java.util.Map;

public class GatewayNodeRunner {
private NetworkAddress serviceAddress;
private GatewayServerBooter gatewayServer;

public GatewayNodeRunner(String host, int port, KeyPairConfig gatewayDefaultKey, NetworkAddress masterPeerAddres) {
this(host, port, gatewayDefaultKey, masterPeerAddres, null,null);
}

public GatewayNodeRunner(String host, int port, KeyPairConfig gatewayDefaultKey, NetworkAddress masterPeerAddres, String[] providers,
Map<String,Object> otherMap) {
this.serviceAddress = new NetworkAddress(host, port);
GatewayConfigProperties config = new GatewayConfigProperties();

config.http().setHost(host);
config.http().setPort(port);

if (providers != null) {
for (String provider : providers) {
config.providerConfig().add(provider);
}
}

config.setMasterPeerAddress(masterPeerAddres);

config.keys().getDefault().setPubKeyValue(gatewayDefaultKey.getPubKeyValue());
config.keys().getDefault().setPrivKeyValue(gatewayDefaultKey.getPrivKeyValue());
config.keys().getDefault().setPrivKeyPassword(gatewayDefaultKey.getPrivKeyPassword());

if(!CollectionUtils.isEmpty(otherMap)){
config.setDataRetrievalUrl(otherMap.get("DATA_RETRIEVAL_URL").toString());
}


//get the springConfigLocation;
ClassPathResource configResource = new ClassPathResource("application-gw.properties");
String springConfigLocation = "classPath:"+configResource.getPath();

this.gatewayServer = new GatewayServerBooter(config,springConfigLocation);
}

public AsyncCallback<Object> start() {
ThreadInvoker<Object> invoker = new ThreadInvoker<Object>() {
@Override
protected Object invoke() throws Exception {
gatewayServer.start();
return null;
}
};
return invoker.start();
}

public void stop() {
gatewayServer.close();
}

public NetworkAddress getServiceAddress() {
return serviceAddress;
}
}

+ 106
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/NodeWebContext.java View File

@@ -0,0 +1,106 @@
package com.jd.blockchain.mocker.node;

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.ledger.TransactionContent;
import com.jd.blockchain.ledger.core.LedgerInitDecision;
import com.jd.blockchain.ledger.core.LedgerInitPermission;
import com.jd.blockchain.ledger.core.LedgerRepository;
import com.jd.blockchain.ledger.core.impl.LedgerManager;
import com.jd.blockchain.mocker.config.LedgerInitWebConfiguration;
import com.jd.blockchain.storage.service.DbConnection;
import com.jd.blockchain.storage.service.impl.composite.CompositeConnectionFactory;
import com.jd.blockchain.tools.initializer.DBConnectionConfig;
import com.jd.blockchain.tools.initializer.LedgerInitProcess;
import com.jd.blockchain.tools.initializer.LedgerInitProperties;
import com.jd.blockchain.tools.initializer.Prompter;
import com.jd.blockchain.tools.initializer.web.LedgerInitializeWebController;
import com.jd.blockchain.utils.concurrent.ThreadInvoker;
import com.jd.blockchain.utils.net.NetworkAddress;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.concurrent.CountDownLatch;

public class NodeWebContext {

private NetworkAddress serverAddress;

private DBConnectionConfig dbConnConfig;

private volatile ConfigurableApplicationContext ctx;

private volatile LedgerInitProcess initProcess;

private volatile LedgerInitializeWebController controller;

private volatile LedgerManager ledgerManager;

private volatile CompositeConnectionFactory db;

private int id;

public int getId() {
return controller.getId();
}

public TransactionContent getInitTxContent() {
return controller.getInitTxContent();
}

public LedgerInitPermission getLocalPermission() {
return controller.getLocalPermission();
}

public LedgerInitDecision getLocalDecision() {
return controller.getLocalDecision();
}

public NodeWebContext(int id, NetworkAddress serverAddress) {
this.id = id;
this.serverAddress = serverAddress;
}

public LedgerRepository registLedger(HashDigest ledgerHash) {
DbConnection conn = db.connect(dbConnConfig.getUri());
LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, conn.getStorageService());
return ledgerRepo;
}

public ThreadInvoker.AsyncCallback<HashDigest> startInit(PrivKey privKey, LedgerInitProperties setting,
DBConnectionConfig dbConnConfig, Prompter prompter, CountDownLatch quitLatch) {

ThreadInvoker<HashDigest> invoker = new ThreadInvoker<HashDigest>() {
@Override
protected HashDigest invoke() throws Exception {
doStartServer();

NodeWebContext.this.dbConnConfig = dbConnConfig;
HashDigest ledgerHash = NodeWebContext.this.initProcess.initialize(id, privKey, setting,
dbConnConfig, prompter);

System.out.printf("ledgerHash = %s \r\n", ledgerHash.toBase58());

quitLatch.countDown();
return ledgerHash;
}
};

return invoker.start();
}

public void doStartServer() {
String argServerAddress = String.format("--server.address=%s", serverAddress.getHost());
String argServerPort = String.format("--server.port=%s", serverAddress.getPort());
String nodebug = "--debug=false";
String[] innerArgs = { argServerAddress, argServerPort, nodebug };

ctx = SpringApplication.run(LedgerInitWebConfiguration.class, innerArgs);

ctx.setId("Node-" + id);
controller = ctx.getBean(LedgerInitializeWebController.class);
ledgerManager = ctx.getBean(LedgerManager.class);
db = ctx.getBean(CompositeConnectionFactory.class);
initProcess = ctx.getBean(LedgerInitProcess.class);
}
}

+ 62
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/PeerNodeRunner.java View File

@@ -0,0 +1,62 @@
package com.jd.blockchain.mocker.node;

import com.jd.blockchain.peer.PeerServerBooter;
import com.jd.blockchain.storage.service.DbConnectionFactory;
import com.jd.blockchain.tools.initializer.LedgerBindingConfig;
import com.jd.blockchain.utils.concurrent.ThreadInvoker;
import com.jd.blockchain.utils.concurrent.ThreadInvoker.AsyncCallback;
import com.jd.blockchain.utils.net.NetworkAddress;

public class PeerNodeRunner {

private NetworkAddress serviceAddress;

private volatile PeerServerBooter peerServer;

private LedgerBindingConfig ledgerBindingConfig;

public DbConnectionFactory getDBConnectionFactory() {
return peerServer.getDBConnectionFactory();
}

public NetworkAddress getServiceAddress() {
return serviceAddress;
}

public LedgerBindingConfig getLedgerBindingConfig() {
return ledgerBindingConfig;
}

public PeerNodeRunner(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig) {
this(serviceAddress, ledgerBindingConfig, null);
}

public PeerNodeRunner(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig,
DbConnectionFactory dbConnectionFactory) {
this.serviceAddress = serviceAddress;
this.ledgerBindingConfig = ledgerBindingConfig;
if (dbConnectionFactory == null) {
this.peerServer = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), serviceAddress.getPort(),null);
}else {
this.peerServer = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), serviceAddress.getPort(),null,
dbConnectionFactory);
}
}

public AsyncCallback<Object> start() {
ThreadInvoker<Object> invoker = new ThreadInvoker<Object>() {
@Override
protected Object invoke() throws Exception {
peerServer.start();

return null;
}
};

return invoker.start();
}

public void stop() {
peerServer.close();
}
}

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

@@ -0,0 +1,80 @@
package com.jd.blockchain.mocker.proxy;

import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractEvent;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.BlockchainIdentity;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.mocker.MockerNodeContext;
import com.jd.blockchain.mocker.handler.MockerContractExeHandle;
import com.jd.blockchain.transaction.TxBuilder;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ContractProxy<T> implements InvocationHandler {

private BlockchainIdentity identity;

private MockerNodeContext mockerNodeContext;

private T instance;

private MockerContractExeHandle operationHandle;

public ContractProxy(BlockchainIdentity identity, MockerNodeContext mockerNodeContext,
T instance, MockerContractExeHandle operationHandle) {
this.identity = identity;
this.mockerNodeContext = mockerNodeContext;
this.instance = instance;
this.operationHandle = operationHandle;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 实际执行时,首先判断执行的是否是添加注解的方法
if (!isExecuteContractMethod(method)) {
return method.invoke(instance, args);
}

// 首先发送一次执行的请求
TxBuilder txBuilder = mockerNodeContext.txBuilder();

Class<?> contractInft = null;

Class<?>[] instanceInfts = instance.getClass().getInterfaces();

for (Class<?> instanceInft : instanceInfts) {
if (instanceInft.isAnnotationPresent(Contract.class)) {
contractInft = instanceInft;
break;
}
}

if (contractInft == null) {
throw new IllegalStateException("This object does not implement the interface for the @Contract annotation !!!");
}

// 生成代理类
Object proxyInstance = txBuilder.contract(identity.getAddress().toBase58(), contractInft);
// 代理方式执行一次
method.invoke(proxyInstance, args);

TransactionRequest txRequest = mockerNodeContext.txRequest(txBuilder);

// 放入到Map中
HashDigest txHash = txRequest.getTransactionContent().getHash();
operationHandle.registerExecutorProxy(txHash, new ExecutorProxy(instance, method, args));

// 提交该请求至整个区块链系统
mockerNodeContext.txProcess(txRequest);
// 不处理返回值
return null;
}

private boolean isExecuteContractMethod(Method method) {
Annotation annotation = method.getAnnotation(ContractEvent.class);
return annotation != null;
}
}

+ 34
- 0
source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ExecutorProxy.java View File

@@ -0,0 +1,34 @@
package com.jd.blockchain.mocker.proxy;

import java.lang.reflect.Method;

public class ExecutorProxy {

private Object instance;

private Method method;

private Object[] args;

public ExecutorProxy(Object instance, Method method, Object[] args) {
this.instance = instance;
this.method = method;
this.args = args;
}

public Object getInstance() {
return instance;
}

public Method getMethod() {
return method;
}

public Object[] getArgs() {
return args;
}

public Object invoke() throws Exception {
return method.invoke(instance, args);
}
}

+ 167
- 0
source/tools/tools-mocker/src/main/resources/bftsmart.config View File

@@ -0,0 +1,167 @@
# Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


############################################
###### Consensus Commit Block Parameters: transaction count ######
############################################
system.block.txsize=500

############################################
###### Consensus Commit Block Parameters: delay time ######
############################################
system.block.maxdelay=5000

############################################
###### #Consensus Participant0 ######
############################################

system.server.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9
system.server.0.network.host=127.0.0.1
system.server.0.network.port=16000
system.server.0.network.secure=false

############################################
###### #Consensus Participant1 ######
############################################

system.server.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX
system.server.1.network.host=127.0.0.1
system.server.1.network.port=16100
system.server.1.network.secure=false

############################################
###### #Consensus Participant2 ######
############################################

system.server.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x
system.server.2.network.host=127.0.0.1
system.server.2.network.port=16200
system.server.2.network.secure=false

############################################
###### #Consensus Participant3 ######
############################################

system.server.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk
system.server.3.network.host=127.0.0.1
system.server.3.network.port=16300
system.server.3.network.secure=false

############################################
####### Communication Configurations #######
############################################

#HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value)
#This parameter is not currently being used
#system.authentication.hmacAlgorithm = HmacSHA1

#Specify if the communication system should use a thread to send data (true or false)
system.communication.useSenderThread = true

#Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments
#and benchmarks, but must not be used in production systems.
system.communication.defaultkeys = true

############################################
### Replication Algorithm Configurations ###
############################################

#Number of servers in the group
system.servers.num = 4

#Maximum number of faulty replicas
system.servers.f = 1

#Timeout to asking for a client request
system.totalordermulticast.timeout = 2000

#Maximum batch size (in number of messages)
system.totalordermulticast.maxbatchsize = 500

#Number of nonces (for non-determinism actions) generated
system.totalordermulticast.nonces = 10

#if verification of leader-generated timestamps are increasing
#it can only be used on systems in which the network clocks
#are synchronized
system.totalordermulticast.verifyTimestamps = false

#Quantity of messages that can be stored in the receive queue of the communication system
system.communication.inQueueSize = 500000

# Quantity of messages that can be stored in the send queue of each replica
system.communication.outQueueSize = 500000

#Set to 1 if SMaRt should use signatures, set to 0 if otherwise
system.communication.useSignatures = 0

#Set to 1 if SMaRt should use MAC's, set to 0 if otherwise
system.communication.useMACs = 1

#Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise
system.debug = 0

#Print information about the replica when it is shutdown
system.shutdownhook = true

############################################
###### State Transfer Configurations #######
############################################

#Activate the state transfer protocol ('true' to activate, 'false' to de-activate)
system.totalordermulticast.state_transfer = true

#Maximum ahead-of-time message not discarded
system.totalordermulticast.highMark = 10000

#Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered)
system.totalordermulticast.revival_highMark = 10

#Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs
system.totalordermulticast.timeout_highMark = 200

############################################
###### Log and Checkpoint Configurations ###
############################################

system.totalordermulticast.log = true
system.totalordermulticast.log_parallel = false
system.totalordermulticast.log_to_disk = false
system.totalordermulticast.sync_log = false

#Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol)
system.totalordermulticast.checkpoint_period = 1000
system.totalordermulticast.global_checkpoint_period = 120000

system.totalordermulticast.checkpoint_to_disk = false
system.totalordermulticast.sync_ckp = false


############################################
###### Reconfiguration Configurations ######
############################################

#Replicas ID for the initial view, separated by a comma.
# The number of replicas in this parameter should be equal to that specified in 'system.servers.num'
system.initial.view = 0,1,2,3

#The ID of the trust third party (TTP)
system.ttp.id = 7002

#This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults
system.bft = true

#Custom View Storage;
#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage

+ 167
- 0
source/tools/tools-mocker/src/main/resources/bftsmart4.config View File

@@ -0,0 +1,167 @@
# Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


############################################
###### Consensus Commit Block Parameters: transaction count ######
############################################
system.block.txsize=500

############################################
###### Consensus Commit Block Parameters: delay time ######
############################################
system.block.maxdelay=5000

############################################
###### #Consensus Participant0 ######
############################################

system.server.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9
system.server.0.network.host=127.0.0.1
system.server.0.network.port=16000
system.server.0.network.secure=false

############################################
###### #Consensus Participant1 ######
############################################

system.server.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX
system.server.1.network.host=127.0.0.1
system.server.1.network.port=16100
system.server.1.network.secure=false

############################################
###### #Consensus Participant2 ######
############################################

system.server.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x
system.server.2.network.host=127.0.0.1
system.server.2.network.port=16200
system.server.2.network.secure=false

############################################
###### #Consensus Participant3 ######
############################################

system.server.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk
system.server.3.network.host=127.0.0.1
system.server.3.network.port=16300
system.server.3.network.secure=false

############################################
####### Communication Configurations #######
############################################

#HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value)
#This parameter is not currently being used
#system.authentication.hmacAlgorithm = HmacSHA1

#Specify if the communication system should use a thread to send data (true or false)
system.communication.useSenderThread = true

#Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments
#and benchmarks, but must not be used in production systems.
system.communication.defaultkeys = true

############################################
### Replication Algorithm Configurations ###
############################################

#Number of servers in the group
system.servers.num = 4

#Maximum number of faulty replicas
system.servers.f = 1

#Timeout to asking for a client request
system.totalordermulticast.timeout = 2000

#Maximum batch size (in number of messages)
system.totalordermulticast.maxbatchsize = 500

#Number of nonces (for non-determinism actions) generated
system.totalordermulticast.nonces = 10

#if verification of leader-generated timestamps are increasing
#it can only be used on systems in which the network clocks
#are synchronized
system.totalordermulticast.verifyTimestamps = false

#Quantity of messages that can be stored in the receive queue of the communication system
system.communication.inQueueSize = 500000

# Quantity of messages that can be stored in the send queue of each replica
system.communication.outQueueSize = 500000

#Set to 1 if SMaRt should use signatures, set to 0 if otherwise
system.communication.useSignatures = 0

#Set to 1 if SMaRt should use MAC's, set to 0 if otherwise
system.communication.useMACs = 1

#Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise
system.debug = 0

#Print information about the replica when it is shutdown
system.shutdownhook = true

############################################
###### State Transfer Configurations #######
############################################

#Activate the state transfer protocol ('true' to activate, 'false' to de-activate)
system.totalordermulticast.state_transfer = true

#Maximum ahead-of-time message not discarded
system.totalordermulticast.highMark = 10000

#Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered)
system.totalordermulticast.revival_highMark = 10

#Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs
system.totalordermulticast.timeout_highMark = 200

############################################
###### Log and Checkpoint Configurations ###
############################################

system.totalordermulticast.log = true
system.totalordermulticast.log_parallel = false
system.totalordermulticast.log_to_disk = false
system.totalordermulticast.sync_log = false

#Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol)
system.totalordermulticast.checkpoint_period = 1000
system.totalordermulticast.global_checkpoint_period = 120000

system.totalordermulticast.checkpoint_to_disk = false
system.totalordermulticast.sync_ckp = false


############################################
###### Reconfiguration Configurations ######
############################################

#Replicas ID for the initial view, separated by a comma.
# The number of replicas in this parameter should be equal to that specified in 'system.servers.num'
system.initial.view = 0,1,2,3

#The ID of the trust third party (TTP)
system.ttp.id = 7002

#This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults
system.bft = true

#Custom View Storage;
#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage

+ 208
- 0
source/tools/tools-mocker/src/main/resources/bftsmart8.config View File

@@ -0,0 +1,208 @@
# Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


############################################
###### Consensus Commit Block Parameters: transaction count ######
############################################
system.block.txsize=500

############################################
###### Consensus Commit Block Parameters: delay time ######
############################################
system.block.maxdelay=5000

############################################
###### #Consensus Participant0 ######
############################################

system.server.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9
system.server.0.network.host=127.0.0.1
system.server.0.network.port=16000
system.server.0.network.secure=false

############################################
###### #Consensus Participant1 ######
############################################

system.server.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX
system.server.1.network.host=127.0.0.1
system.server.1.network.port=16100
system.server.1.network.secure=false

############################################
###### #Consensus Participant2 ######
############################################

system.server.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x
system.server.2.network.host=127.0.0.1
system.server.2.network.port=16200
system.server.2.network.secure=false

############################################
###### #Consensus Participant3 ######
############################################

system.server.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk
system.server.3.network.host=127.0.0.1
system.server.3.network.port=16300
system.server.3.network.secure=false


############################################
###### #Consensus Participant4 ######
############################################

system.server.4.pubkey=3snPdw7i7PXPRMp3EAjsxJkHe7aZJRLNzdW8kEHBWeQsSgcPAiHP2J
system.server.4.network.host=127.0.0.1
system.server.4.network.port=16400
system.server.4.network.secure=false


############################################
###### #Consensus Participant5 ######
############################################

system.server.5.pubkey=3snPdw7i7PmmQoPgUpUmmAUj6nakHj8wMSQmiMi1RaiZp4YU1D4AXk
system.server.5.network.host=127.0.0.1
system.server.5.network.port=16500
system.server.5.network.secure=false


############################################
###### #Consensus Participant6 ######
############################################

system.server.6.pubkey=3snPdw7i7PiJKsa94q3EcLT1y6GRJ7LeFGe799hdzRRHmf6LNodyiM
system.server.6.network.host=127.0.0.1
system.server.6.network.port=16600
system.server.6.network.secure=false


############################################
###### #Consensus Participant7 ######
############################################

system.server.7.pubkey=3snPdw7i7Pm2wJwEnKn8kK8eGTkN36C2BZRRjVTr9FPB2rqtcgTq7h
system.server.7.network.host=127.0.0.1
system.server.7.network.port=16700
system.server.7.network.secure=false


############################################
####### Communication Configurations #######
############################################

#HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value)
#This parameter is not currently being used
#system.authentication.hmacAlgorithm = HmacSHA1

#Specify if the communication system should use a thread to send data (true or false)
system.communication.useSenderThread = true

#Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments
#and benchmarks, but must not be used in production systems.
system.communication.defaultkeys = true

############################################
### Replication Algorithm Configurations ###
############################################

#Number of servers in the group
system.servers.num = 8

#Maximum number of faulty replicas
system.servers.f = 2

#Timeout to asking for a client request
system.totalordermulticast.timeout = 2000

#Maximum batch size (in number of messages)
system.totalordermulticast.maxbatchsize = 500

#Number of nonces (for non-determinism actions) generated
system.totalordermulticast.nonces = 10

#if verification of leader-generated timestamps are increasing
#it can only be used on systems in which the network clocks
#are synchronized
system.totalordermulticast.verifyTimestamps = false

#Quantity of messages that can be stored in the receive queue of the communication system
system.communication.inQueueSize = 500000

# Quantity of messages that can be stored in the send queue of each replica
system.communication.outQueueSize = 500000

#Set to 1 if SMaRt should use signatures, set to 0 if otherwise
system.communication.useSignatures = 0

#Set to 1 if SMaRt should use MAC's, set to 0 if otherwise
system.communication.useMACs = 1

#Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise
system.debug = 0

#Print information about the replica when it is shutdown
system.shutdownhook = true

############################################
###### State Transfer Configurations #######
############################################

#Activate the state transfer protocol ('true' to activate, 'false' to de-activate)
system.totalordermulticast.state_transfer = true

#Maximum ahead-of-time message not discarded
system.totalordermulticast.highMark = 10000

#Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered)
system.totalordermulticast.revival_highMark = 10

#Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs
system.totalordermulticast.timeout_highMark = 200

############################################
###### Log and Checkpoint Configurations ###
############################################

system.totalordermulticast.log = true
system.totalordermulticast.log_parallel = false
system.totalordermulticast.log_to_disk = false
system.totalordermulticast.sync_log = false

#Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol)
system.totalordermulticast.checkpoint_period = 1000
system.totalordermulticast.global_checkpoint_period = 120000

system.totalordermulticast.checkpoint_to_disk = false
system.totalordermulticast.sync_ckp = false


############################################
###### Reconfiguration Configurations ######
############################################

#Replicas ID for the initial view, separated by a comma.
# The number of replicas in this parameter should be equal to that specified in 'system.servers.num'
system.initial.view = 0,1,2,3,4,5,6,7

#The ID of the trust third party (TTP)
system.ttp.id = 7002

#This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults
system.bft = true

#Custom View Storage;
#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage

+ 72
- 0
source/tools/tools-mocker/src/main/resources/ledger4.init View File

@@ -0,0 +1,72 @@
#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取;
ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffa

#账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途;
ledger.name=JDChain


#共识服务提供者;必须;
consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider

#共识服务的参数配置;必须;
consensus.conf=classpath:bftsmart4.config

#密码服务提供者列表,以英文逗点“,”分隔;必须;
crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \
com.jd.blockchain.crypto.service.sm.SMCryptoService


#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置;
cons_parti.count=4

#第0个参与方的名称;
cons_parti.0.name=jd.com
#第0个参与方的公钥文件路径;
cons_parti.0.pubkey-path=
#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9
#第0个参与方的账本初始服务的主机;
cons_parti.0.initializer.host=127.0.0.1
#第0个参与方的账本初始服务的端口;
cons_parti.0.initializer.port=1601
#第0个参与方的账本初始服务是否开启安全连接;
cons_parti.0.initializer.secure=false

#第1个参与方的名称;
cons_parti.1.name=at.com
#第1个参与方的公钥文件路径;
cons_parti.1.pubkey-path=
#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX
#第1个参与方的账本初始服务的主机;
cons_parti.1.initializer.host=127.0.0.1
#第1个参与方的账本初始服务的端口;
cons_parti.1.initializer.port=1611
#第1个参与方的账本初始服务是否开启安全连接;
cons_parti.1.initializer.secure=false

#第2个参与方的名称;
cons_parti.2.name=bt.com
#第2个参与方的公钥文件路径;
cons_parti.2.pubkey-path=
#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x
#第2个参与方的账本初始服务的主机;
cons_parti.2.initializer.host=127.0.0.1
#第2个参与方的账本初始服务的端口;
cons_parti.2.initializer.port=1621
#第2个参与方的账本初始服务是否开启安全连接;
cons_parti.2.initializer.secure=false

#第3个参与方的名称;
cons_parti.3.name=xt.com
#第3个参与方的公钥文件路径;
cons_parti.3.pubkey-path=
#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk
#第3个参与方的账本初始服务的主机;
cons_parti.3.initializer.host=127.0.0.1
#第3个参与方的账本初始服务的端口;
cons_parti.3.initializer.port=1631
#第3个参与方的账本初始服务是否开启安全连接;
cons_parti.3.initializer.secure=false

+ 125
- 0
source/tools/tools-mocker/src/main/resources/ledger8.init View File

@@ -0,0 +1,125 @@
#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取;
ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe

#账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途;
ledger.name=JDChain


#共识服务提供者;必须;
consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider

#共识服务的参数配置;必须;
consensus.conf=classpath:bftsmart8.config

#密码服务提供者列表,以英文逗点“,”分隔;必须;
crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \
com.jd.blockchain.crypto.service.sm.SMCryptoService


#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置;
cons_parti.count=8

#第0个参与方的名称;
cons_parti.0.name=jd.com
#第0个参与方的公钥文件路径;
cons_parti.0.pubkey-path=
#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9
#第0个参与方的账本初始服务的主机;
cons_parti.0.initializer.host=127.0.0.1
#第0个参与方的账本初始服务的端口;
cons_parti.0.initializer.port=1601
#第0个参与方的账本初始服务是否开启安全连接;
cons_parti.0.initializer.secure=false

#第1个参与方的名称;
cons_parti.1.name=at.com
#第1个参与方的公钥文件路径;
cons_parti.1.pubkey-path=
#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX
#第1个参与方的账本初始服务的主机;
cons_parti.1.initializer.host=127.0.0.1
#第1个参与方的账本初始服务的端口;
cons_parti.1.initializer.port=1611
#第1个参与方的账本初始服务是否开启安全连接;
cons_parti.1.initializer.secure=false

#第2个参与方的名称;
cons_parti.2.name=bt.com
#第2个参与方的公钥文件路径;
cons_parti.2.pubkey-path=
#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.2.pubkey=3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x
#第2个参与方的账本初始服务的主机;
cons_parti.2.initializer.host=127.0.0.1
#第2个参与方的账本初始服务的端口;
cons_parti.2.initializer.port=1621
#第2个参与方的账本初始服务是否开启安全连接;
cons_parti.2.initializer.secure=false

#第3个参与方的名称;
cons_parti.3.name=xt.com
#第3个参与方的公钥文件路径;
cons_parti.3.pubkey-path=
#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk
#第3个参与方的账本初始服务的主机;
cons_parti.3.initializer.host=127.0.0.1
#第3个参与方的账本初始服务的端口;
cons_parti.3.initializer.port=1631
#第3个参与方的账本初始服务是否开启安全连接;
cons_parti.3.initializer.secure=false


#第4个参与方的名称;
cons_parti.4.name=mt.com
#第4个参与方的公钥文件路径;
cons_parti.4.pubkey-path=
#第4个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.4.pubkey=3snPdw7i7PXPRMp3EAjsxJkHe7aZJRLNzdW8kEHBWeQsSgcPAiHP2J
#第4个参与方的账本初始服务的主机;
cons_parti.4.initializer.host=127.0.0.1
#第4个参与方的账本初始服务的端口;
cons_parti.4.initializer.port=1641
#第4个参与方的账本初始服务是否开启安全连接;
cons_parti.4.initializer.secure=false

#第5个参与方的名称;
cons_parti.5.name=nt.com
#第5个参与方的公钥文件路径;
cons_parti.5.pubkey-path=
#第5个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.5.pubkey=3snPdw7i7PmmQoPgUpUmmAUj6nakHj8wMSQmiMi1RaiZp4YU1D4AXk
#第5个参与方的账本初始服务的主机;
cons_parti.5.initializer.host=127.0.0.1
#第5个参与方的账本初始服务的端口;
cons_parti.5.initializer.port=1651
#第5个参与方的账本初始服务是否开启安全连接;
cons_parti.5.initializer.secure=false

#第6个参与方的名称;
cons_parti.6.name=yt.com
#第6个参与方的公钥文件路径;
cons_parti.6.pubkey-path=
#第6个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.6.pubkey=3snPdw7i7PiJKsa94q3EcLT1y6GRJ7LeFGe799hdzRRHmf6LNodyiM
#第6个参与方的账本初始服务的主机;
cons_parti.6.initializer.host=127.0.0.1
#第6个参与方的账本初始服务的端口;
cons_parti.6.initializer.port=1661
#第6个参与方的账本初始服务是否开启安全连接;
cons_parti.6.initializer.secure=false

#第7个参与方的名称;
cons_parti.7.name=zt.com
#第7个参与方的公钥文件路径;
cons_parti.7.pubkey-path=
#第7个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
cons_parti.7.pubkey=3snPdw7i7Pm2wJwEnKn8kK8eGTkN36C2BZRRjVTr9FPB2rqtcgTq7h
#第7个参与方的账本初始服务的主机;
cons_parti.7.initializer.host=127.0.0.1
#第7个参与方的账本初始服务的端口;
cons_parti.7.initializer.port=1671
#第7个参与方的账本初始服务是否开启安全连接;
cons_parti.7.initializer.secure=false

+ 50
- 0
source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/AccountMockerTest.java View File

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

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.mocker.MockerNodeContext;
import com.jd.blockchain.mocker.contracts.AccountContract;
import com.jd.blockchain.mocker.contracts.AccountContractImpl;
import org.junit.Before;
import org.junit.Test;

public class AccountMockerTest {

String accountFrom = "zhangsan";

String accountTo = "lisi";

MockerNodeContext mockerNodeContext = null;

HashDigest ledgerHash = null;

@Before
public void init() {
mockerNodeContext = new MockerNodeContext().build();
ledgerHash = mockerNodeContext.getLedgerHash();
}

@Test
public void test() {
// 首先创建一个数据账户
String address = mockerNodeContext.registerDataAccount();

// 处理合约
AccountContract accountContract = new AccountContractImpl();

// 发布合约
accountContract = mockerNodeContext.deployContract(accountContract);

//首先创建账户
accountContract.create(address, accountFrom, 1000L);

accountContract.create(address, accountTo, 1000L);

accountContract.print(address, accountFrom, accountTo);

// 开始转账
accountContract.transfer(address, accountFrom, accountTo, 500);

// 打印转账后结果
accountContract.print(address, accountFrom, accountTo);
}
}

+ 54
- 0
source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/MockTest.java View File

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

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.mocker.MockerNodeContext;
import com.jd.blockchain.mocker.config.MockerConstant;
import com.jd.blockchain.mocker.contracts.WriteContract;
import com.jd.blockchain.mocker.contracts.WriteContractImpl;
import org.junit.Test;

public class MockTest {

@Test
public void test() {
// 准备环境
BlockchainKeypair blockchainKeypair = BlockchainKeyGenerator.getInstance().generate();
MockerNodeContext mockerNodeContext =
new MockerNodeContext(MockerConstant.DEFAULT_LEDGER_SEED)
.participants("zhangsan", blockchainKeypair)
.build();
HashDigest ledgerHash = mockerNodeContext.getLedgerHash();

System.out.printf("LedgerHash = %s \r\n", ledgerHash.toBase58());
System.out.printf("LedgerSeed = %s \r\n", mockerNodeContext.getLedgerSeed());

// 注册用户
String userAddress = mockerNodeContext.registerUser(BlockchainKeyGenerator.getInstance().generate());
System.out.printf("----- 注册用户地址 {%s} -----\r\n", userAddress);

// 注册数据账户
String dataAccountAddress = mockerNodeContext.registerDataAccount(BlockchainKeyGenerator.getInstance().generate());
System.out.printf("----- 注册数据账户地址 {%s} -----\r\n", dataAccountAddress);

WriteContract writeContract = new WriteContractImpl();

// 发布合约
writeContract = mockerNodeContext.deployContract(writeContract);

writeContract.print("张三");

String key = "Hello", value = "World";

writeContract.writeKv(dataAccountAddress, key, value);

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

for (KVDataEntry kvDataEntry : kvDataEntries) {
System.out.printf("Key = %s, Value = %s \r\n", kvDataEntry.getKey(), kvDataEntry.getValue());
}
}
}

+ 47
- 0
source/tools/tools-mocker/src/test/java/test/com/jd/blockchain/contract/SampleTest.java View File

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

import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.KVDataEntry;
import com.jd.blockchain.mocker.MockerNodeContext;
import com.jd.blockchain.mocker.contracts.WriteContract;
import com.jd.blockchain.mocker.contracts.WriteContractImpl;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class SampleTest {

MockerNodeContext mockerNodeContext = null;

HashDigest ledgerHash = null;

@Before
public void init() {
mockerNodeContext = new MockerNodeContext().build();
ledgerHash = mockerNodeContext.getLedgerHash();
}

@Test
public void writeTest() {

String key = "MyKey-" + System.currentTimeMillis(), value = "JDChain";

WriteContract writeContract = new WriteContractImpl();

String dataAccountAddress = mockerNodeContext.registerDataAccount();

writeContract = mockerNodeContext.deployContract(writeContract);

writeContract.writeKv(dataAccountAddress, key, value);

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

for (KVDataEntry kvDataEntry : dataEntries) {
assertEquals(key, kvDataEntry.getKey());
assertEquals(value, kvDataEntry.getValue());
System.out.printf("Key = %s, Value = %s \r\n", kvDataEntry.getKey(), kvDataEntry.getValue());
}
}
}

+ 1
- 1
source/utils/utils-common/src/main/java/com/jd/blockchain/utils/BaseConstant.java View File

@@ -22,7 +22,7 @@ public class BaseConstant {
public static final String SYS_CONTRACT_PROPS_NAME = "sys-contract.properties";
public static final String CONTRACT_MAIN_CLASS_KEY = "contract";
public static final String CONTRACT_EVENT_PREFIX="@com.jd.blockchain.contract.model.ContractEvent(name=";
// public static final String CONTRACT_EVENT_PREFIX="@com.jd.blockchain.contract.ContractEvent(name=";
// 编译时引用包黑名单
public static final String PACKAGE_BLACKLIST = "BLACKLIST";


+ 3
- 1
source/utils/utils-common/src/main/java/com/jd/blockchain/utils/security/DESUtils.java View File

@@ -1,5 +1,7 @@
package com.jd.blockchain.utils.security;
import com.jd.blockchain.utils.io.BytesUtils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@@ -32,7 +34,7 @@ public class DESUtils {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey secretKey = keyFactory.generateSecret(keySpec);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(code.getBytes());
return cipher.doFinal(BytesUtils.toBytes(code));
}
/** DES解密 */


Loading…
Cancel
Save