@@ -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,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); | |||
@@ -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); | |||
@@ -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; | |||
} | |||
} | |||
} |
@@ -1,4 +1,3 @@ | |||
#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取; | |||
ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe | |||
@@ -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> |
@@ -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); | |||
@@ -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(); | |||
@@ -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> |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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" | |||
}; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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() { | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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 -----"); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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() + "]!"); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} | |||
} |
@@ -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()); | |||
} | |||
} | |||
} |