Browse Source

Adding Tool-Mocker module, which can be used for mocker test contract function !!!

tags/1.0.0
shaozhuguang 5 years ago
parent
commit
7db6392a58
36 changed files with 3173 additions and 9 deletions
  1. +1
    -1
      source/peer/src/test/java/test/com/jd/blockchain/peer/web/ControllerTestConfiguration.java
  2. +2
    -2
      source/peer/src/test/java/test/com/jd/blockchain/peer/web/LedgerInitializingTest.java
  3. +2
    -2
      source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java
  4. +280
    -0
      source/sdk/sdk-client/src/main/java/com/jd/blockchain/sdk/client/ClientOperationUtil.java
  5. +0
    -1
      source/test/test-integration/src/test/resources/ledger_init_test_web2.init
  6. +2
    -1
      source/tools/pom.xml
  7. +1
    -1
      source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java
  8. +1
    -1
      source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LocalConfig.java
  9. +44
    -0
      source/tools/tools-mocker/pom.xml
  10. +342
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerLedgerInitializer.java
  11. +460
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java
  12. +22
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/LedgerInitWebConfiguration.java
  13. +67
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/MockerConstant.java
  14. +32
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/config/PresetAnswerPrompter.java
  15. +17
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContract.java
  16. +81
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/AccountContractImpl.java
  17. +14
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContract.java
  18. +41
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/contracts/WriteContractImpl.java
  19. +54
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/KvData.java
  20. +38
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/data/ResponseData.java
  21. +136
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java
  22. +189
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerNodeHandler.java
  23. +51
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerOperationHandleRegister.java
  24. +216
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerServiceHandler.java
  25. +75
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/GatewayNodeRunner.java
  26. +106
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/NodeWebContext.java
  27. +62
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/node/PeerNodeRunner.java
  28. +80
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ContractProxy.java
  29. +34
    -0
      source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/proxy/ExecutorProxy.java
  30. +167
    -0
      source/tools/tools-mocker/src/main/resources/bftsmart4.config
  31. +208
    -0
      source/tools/tools-mocker/src/main/resources/bftsmart8.config
  32. +72
    -0
      source/tools/tools-mocker/src/main/resources/ledger4.init
  33. +125
    -0
      source/tools/tools-mocker/src/main/resources/ledger8.init
  34. +50
    -0
      source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/AccountMockerTest.java
  35. +54
    -0
      source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/MockTest.java
  36. +47
    -0
      source/tools/tools-mocker/src/test/java/com/jd/blockchain/test/SampleTest.java

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


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

@@ -0,0 +1,280 @@
/**
* 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 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(ledgerSeedStr.getBytes()));

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, chainCodeStr.getBytes());
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, argsStr.getBytes());
}

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

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

}

}

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

@@ -0,0 +1,460 @@
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.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, contract.getClass().getName().getBytes());
// 执行
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/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/com/jd/blockchain/test/AccountMockerTest.java View File

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

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/com/jd/blockchain/test/MockTest.java View File

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

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/com/jd/blockchain/test/SampleTest.java View File

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

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

Loading…
Cancel
Save