@@ -15,7 +15,6 @@ | |||
<module>core</module> | |||
<module>deploy</module> | |||
<module>test</module> | |||
<module>samples</module> | |||
</modules> | |||
@@ -1,60 +0,0 @@ | |||
## JD Chain Samples | |||
本项目为`JD Chain SDK`的使用样例,开发者可以参考此项目快速上手`JD Chain SDK`,主要包括[交易发送查询](#交易发送查询),[合约开发部署](#合约开发部署)两部分。 | |||
本项目提供了基于内存的`JD Chain`四节点+网关的网络环境启动程序[TestNet](sdk-samples/src/main/java/com/jdchain/samples/sdk/TestNet.java),运行`TestNet`的`main`方法启动测试网络,等待日志输出:`START TESTNET SUCCESS`,网络启动成功会写入一些测试数据,可直接运行本项目提供的所有测试用例。 | |||
> `TestNet`测试网络默认会占用`8910`/`8920`/`8930`/`8940`/`8911`/`8921`/`8931`/`8941`用于共识服务,`12000`/`12010`/`12020`/`12030`用于四节点`API`服务端口,`11000`用于网关`API`服务端口,启动前请检查相关端口可用。 | |||
### 交易发送查询 | |||
相关代码放在[sdk-sample](sdk-samples/src)下。 | |||
> 若并非使用`TestNet`启动的测试网络,开发者在运行本样例前,请根据实际环境修改[config.properties](sdk-samples/src/main/resources/config.properties)中的网关配置,用户配置等信息。 | |||
#### 交易发送 | |||
参照[UserSample](sdk-samples/src/test/java/com/jdchain/samples/sdk/UserSample.java)实现注册用户,配置用户角色权限功能; | |||
参照[DataAccountSample](sdk-samples/src/test/java/com/jdchain/samples/sdk/DataAccountSample.java)实现注册数据账户,存储`KV`数据功能; | |||
参照[EventSample](sdk-samples/src/test/java/com/jdchain/samples/sdk/EventSample.java)实现注册事件账户,发布事件,事件监听功能; | |||
参照[ContractSample](sdk-samples/src/test/java/com/jdchain/samples/sdk/ContractSample.java)实现合约调用,非插件方式合约部署功能。 | |||
#### 数据查询 | |||
参照[QuerySample](sdk-samples/src/test/java/com/jdchain/samples/sdk/QuerySample.java)实现对于区块链上数据查询功能。 | |||
### 合约开发部署 | |||
[contract-samples](contract-samples/src)提供了通过合约注册用户,注册数据账户,注册事件账户,设置`KV`,发布事件的简单合约样例。 | |||
> 若并非使用`TestNet`启动的测试网络,开发者在运行本样例前,请根据实际环境修改[pom.xml](contract-samples/pom.xml)中的网关配置,用户配置等信息。 | |||
修改相关代码,确认配置正确,`contract-samples`项目目录下命令行执行: | |||
- 合约打包 | |||
```bash | |||
mvn clean package | |||
``` | |||
可以生成`car`包,可以用于`SDK`方式合约部署。 | |||
- 合约部署 | |||
```bash | |||
mvn clean deploy | |||
``` | |||
可以直接部署合约上链。 | |||
### 了解更多 | |||
访问[JD Chain官网](http://ledger.jd.com/)查阅设计及文档。 | |||
访问[github主页](https://github.com/blockchain-jd-com)阅读`JD Chain`源码并参与社区建设。 | |||
Thanks~ |
@@ -1,81 +0,0 @@ | |||
<?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"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>jdchain-samples</artifactId> | |||
<version>1.6.0.RELEASE</version> | |||
</parent> | |||
<!-- 声明为合约代码工程,编译输出扩展名为".car"合约代码 --> | |||
<packaging>contract</packaging> | |||
<artifactId>contract-samples</artifactId> | |||
<name>contract-samples</name> | |||
<dependencies> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>contract-starter</artifactId> | |||
<version>${framework.version}</version> | |||
<scope>provided</scope> | |||
</dependency> | |||
</dependencies> | |||
<build> | |||
<plugins> | |||
<plugin> | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-compiler-plugin</artifactId> | |||
<configuration> | |||
<source>1.8</source> | |||
<target>1.8</target> | |||
<encoding>UTF-8</encoding> | |||
<optimize>false</optimize> | |||
<debug>true</debug> | |||
<showDeprecation>false</showDeprecation> | |||
<showWarnings>false</showWarnings> | |||
</configuration> | |||
</plugin> | |||
<!-- 合约编译、打包、发布插件 --> | |||
<plugin> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>contract-maven-plugin</artifactId> | |||
<version>${framework.version}</version> | |||
<extensions>true</extensions> | |||
<!-- 合约发布配置,不配置时请不要执行deploy阶段 --> | |||
<configuration> | |||
<!-- <maxCarSize>1</maxCarSize>--> | |||
<!-- <maxCarSizeUnit>MB</maxCarSizeUnit>--> | |||
<deployment> | |||
<!-- 线上网关的配置,必选项 --> | |||
<gateway> | |||
<host>localhost</host> | |||
<port>11000</port> | |||
</gateway> | |||
<!-- 账本,不填默认选择列表第一个 --> | |||
<!-- <ledger>j5uXbSp6V9VCXxHQzp8pFGKoR9NrAkE6TUvfwWxvEVR5HK</ledger>--> | |||
<!-- 更新已存在合约代码 --> | |||
<!-- <contractAddress>--> | |||
<!-- <pubKey></pubKey>--> | |||
<!-- </contractAddress>--> | |||
<!-- 用户信息,必选项,任何一个合约发布都需要拥有者进行签名 --> | |||
<signer> | |||
<pubKey>7VeRLdGtSz1Y91gjLTqEdnkotzUfaAqdap3xw6fQ1yKHkvVq</pubKey> | |||
<privKey>177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x</privKey> | |||
<privKeyPwd>DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY</privKeyPwd> | |||
</signer> | |||
</deployment> | |||
</configuration> | |||
</plugin> | |||
</plugins> | |||
</build> | |||
</project> |
@@ -1,132 +0,0 @@ | |||
package com.jdchain.samples.contract; | |||
import com.jd.blockchain.contract.Contract; | |||
import com.jd.blockchain.contract.ContractEvent; | |||
/** | |||
* 合约样例,提供通过合约创建用户/数据账户/事件账户,写入KV,发布事件等功能 | |||
*/ | |||
@Contract | |||
public interface SampleContract { | |||
// a. 创建角色,并分配权限 | |||
@ContractEvent(name = "createRoleAndPermissions") | |||
void createRoleAndPermissions(String role, String ledgerPermissionSemicolonStr, String txPermissionSemicolonStr); | |||
// b. 注册用户 | |||
@ContractEvent(name = "registerUserByPubKey") | |||
void registerUserByPubKey(String pubkey); | |||
// c. 修改用户角色 | |||
@ContractEvent(name = "modifyUserRole") | |||
void modifyUserRole(String address, String role); | |||
// d. 修改用户状态 | |||
@ContractEvent(name = "modifyUserState") | |||
void modifyUserState(String userAddress, String state); | |||
// e. 注册数据账户 | |||
//void registerDataAccount(String seed); | |||
// f. 修改数据账户角色及mode | |||
@ContractEvent(name = "modifyDataAccountRoleAndMode") | |||
void modifyDataAccountRoleAndMode(String dataAccountAddress, String role, String mode); | |||
// h. 数据账户赋值,更新值 | |||
@ContractEvent(name = "dataAccountAddress") | |||
void setKV(String dataAccountAddress, String key, String value, String version); | |||
// i. 注册事件账户 | |||
// String registerEventAccount(String seed) | |||
// j. 修改事件账户角色及mode | |||
@ContractEvent(name = "modifyEventAccountRoleAndMode") | |||
void modifyEventAccountRoleAndMode(String eventAccountAddress, String role, String mode); | |||
// k. 发布事件 | |||
@ContractEvent(name = "publishEventAccount") | |||
void publishEventAccount(String eventAccountAddress, String eventName, String value, String sequence); | |||
// l. 合约中调用合约 | |||
@ContractEvent(name = "invokeContract") | |||
void invokeContract(String contractAddress, String method, String argDotStr); | |||
// m. 合约中部署合约 | |||
@ContractEvent(name = "deployContract") | |||
String deployContract(String pubkey, byte[] carBytes); | |||
// n. 修改合约角色及mode | |||
@ContractEvent(name = "modifyContractRoleAndMode") | |||
void modifyContractRoleAndMode(String contractAddress, String role, String mode); | |||
// o. 修改合约状态 | |||
@ContractEvent(name = "modifyContractState") | |||
void modifyContractState(String contractAddress, String state); | |||
/** | |||
* 设置KV | |||
* | |||
* @param address 数据账户地址 | |||
* @param key 键 | |||
* @param value 值 | |||
* @param version 版本 | |||
*/ | |||
@ContractEvent(name = "setKVWithVersion") | |||
void setKVWithVersion(String address, String key, String value, long version); | |||
/** | |||
* 设置KV,基于最新数据版本 | |||
* | |||
* @param address 数据账户地址 | |||
* @param key 键 | |||
* @param value 值 | |||
*/ | |||
@ContractEvent(name = "setKV") | |||
void setKV(String address, String key, String value); | |||
/** | |||
* 注册用户 | |||
* | |||
* @param seed 种子,不小于32个字符 | |||
*/ | |||
@ContractEvent(name = "registerUser") | |||
String registerUser(String seed); | |||
/** | |||
* 注册数据账户 | |||
* | |||
* @param seed 种子,不小于32个字符 | |||
*/ | |||
@ContractEvent(name = "registerDataAccount") | |||
String registerDataAccount(String seed); | |||
/** | |||
* 注册事件账户 | |||
* | |||
* @param seed 种子,不小于32个字符 | |||
*/ | |||
@ContractEvent(name = "registerEventAccount") | |||
String registerEventAccount(String seed); | |||
/** | |||
* 发布事件 | |||
* | |||
* @param address 事件账户地址 | |||
* @param topic 消息名称 | |||
* @param content 内容 | |||
* @param sequence 当前消息名称下最大序号(初始为-1) | |||
*/ | |||
@ContractEvent(name = "publishEventWithSequence") | |||
void publishEventWithSequence(String address, String topic, String content, long sequence); | |||
/** | |||
* 发布事件,基于最新时间序号 | |||
* | |||
* @param address 事件账户地址 | |||
* @param topic 消息名称 | |||
* @param content 内容 | |||
*/ | |||
@ContractEvent(name = "publishEvent") | |||
void publishEvent(String address, String topic, String content); | |||
} |
@@ -1,233 +0,0 @@ | |||
package com.jdchain.samples.contract; | |||
import com.jd.blockchain.contract.ContractEventContext; | |||
import com.jd.blockchain.contract.EventProcessingAware; | |||
import com.jd.blockchain.crypto.*; | |||
import com.jd.blockchain.crypto.base.DefaultCryptoEncoding; | |||
import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.transaction.SimpleSecurityOperationBuilder; | |||
import utils.Bytes; | |||
/** | |||
* 合约样例实现 | |||
*/ | |||
public class SampleContractImpl implements EventProcessingAware, SampleContract { | |||
private ContractEventContext eventContext; | |||
@Override | |||
public void setKVWithVersion(String address, String key, String value, long version) { | |||
eventContext.getLedger().dataAccount(Bytes.fromBase58(address)).setText(key, value, version); | |||
} | |||
@Override | |||
public void setKV(String address, String key, String value) { | |||
// 查询最新版本,初始为-1 | |||
// 查询已提交区块数据,不包括此操作所在未提交区块的所有数据 | |||
// TypedKVEntry[] entries = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), address, key); | |||
// 可查询包括此操作所在未提交区块的所有数据 | |||
TypedKVEntry[] entries = eventContext.getUncommittedLedger().getDataEntries(address, key); | |||
long version = -1; | |||
if (null != entries && entries.length > 0) { | |||
version = entries[0].getVersion(); | |||
} | |||
eventContext.getLedger().dataAccount(Bytes.fromBase58(address)).setText(key, value, version); | |||
} | |||
@Override | |||
public String registerUser(String seed) { | |||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519"); | |||
SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm); | |||
AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes()); | |||
BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); | |||
eventContext.getLedger().users().register(keypair.getIdentity()); | |||
return keypair.getAddress().toBase58(); | |||
} | |||
@Override | |||
public String registerDataAccount(String seed) { | |||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519"); | |||
SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm); | |||
AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes()); | |||
BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); | |||
eventContext.getLedger().dataAccounts().register(keypair.getIdentity()); | |||
return keypair.getAddress().toBase58(); | |||
} | |||
@Override | |||
public String registerEventAccount(String seed) { | |||
CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519"); | |||
SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm); | |||
AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes()); | |||
BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); | |||
eventContext.getLedger().eventAccounts().register(keypair.getIdentity()); | |||
return keypair.getAddress().toBase58(); | |||
} | |||
@Override | |||
public void publishEventWithSequence(String address, String topic, String content, long sequence) { | |||
eventContext.getLedger().eventAccount(Bytes.fromBase58(address)).publish(topic, content, sequence); | |||
} | |||
@Override | |||
public void publishEvent(String address, String topic, String content) { | |||
// 查询最新序号,初始为-1 | |||
// 查询已提交区块数据,不包括此操作所在未提交区块的所有数据 | |||
// Event event = eventContext.getLedger().getRuntimeLedger().getLatestEvent(address, topic); | |||
// 可查询包括此操作所在未提交区块的所有数据 | |||
Event event = eventContext.getUncommittedLedger().getLatestEvent(address, topic); | |||
long sequence = -1; | |||
if (null != event) { | |||
sequence = event.getSequence(); | |||
} | |||
eventContext.getLedger().eventAccount(Bytes.fromBase58(address)).publish(topic, content, sequence); | |||
} | |||
/** | |||
* 合约方法调用前操作 | |||
* | |||
* @param eventContext | |||
*/ | |||
@Override | |||
public void beforeEvent(ContractEventContext eventContext) { | |||
this.eventContext = eventContext; | |||
} | |||
/** | |||
* 合约方法调用后操作 | |||
* | |||
* @param eventContext | |||
* @param error | |||
*/ | |||
@Override | |||
public void postEvent(ContractEventContext eventContext, Exception error) { | |||
} | |||
@Override | |||
public void createRoleAndPermissions(String role, String ledgerPermissionSemicolonStr, String txPermissionSemicolonStr) { | |||
SimpleSecurityOperationBuilder.SimpleRoleConfigurer roleConfigurer = eventContext.getLedger().security().role(role); | |||
if(ledgerPermissionSemicolonStr != null){ | |||
for(String perm : ledgerPermissionSemicolonStr.split(";")){ | |||
LedgerPermission permission = LedgerPermission.valueOf(perm.trim().toUpperCase()); | |||
roleConfigurer.enable(permission); | |||
} | |||
} | |||
if(txPermissionSemicolonStr != null){ | |||
for(String perm : txPermissionSemicolonStr.split(";")){ | |||
TransactionPermission permission = TransactionPermission.valueOf(perm.trim().toUpperCase()); | |||
roleConfigurer.enable(permission); | |||
} | |||
} | |||
} | |||
@Override | |||
public void registerUserByPubKey(String pubkey) { | |||
PubKey pubKey = DefaultCryptoEncoding.createPubKey(ClassicAlgorithm.ED25519.code(), Bytes.fromBase58(pubkey).toBytes()); | |||
BlockchainIdentityData identityData = new BlockchainIdentityData(pubKey); | |||
eventContext.getLedger().users().register(identityData); | |||
} | |||
@Override | |||
public void modifyUserRole(String address, String role) { | |||
eventContext.getLedger() | |||
.security() | |||
.authorziation(Bytes.fromBase58(address)) | |||
.authorize(role); | |||
} | |||
@Override | |||
public void modifyUserState(String userAddress, String state) { | |||
AccountState accountState = AccountState.valueOf(state.trim().toUpperCase()); | |||
eventContext.getLedger().user(userAddress) | |||
.state(accountState); | |||
} | |||
@Override | |||
public void modifyDataAccountRoleAndMode(String dataAccountAddress, String role, String mode) { | |||
eventContext.getLedger().dataAccount(dataAccountAddress) | |||
.permission() | |||
.role(role) | |||
.mode(Integer.parseInt(mode)); | |||
} | |||
@Override | |||
public void setKV(String dataAccountAddress, String key, String value, String version) { | |||
eventContext.getLedger().dataAccount(dataAccountAddress) | |||
.setText(key, value, Integer.parseInt(version)); | |||
} | |||
@Override | |||
public void modifyEventAccountRoleAndMode(String eventAccountAddress, String role, String mode) { | |||
eventContext.getLedger().eventAccount(eventAccountAddress) | |||
.permission() | |||
.role(role) | |||
.mode(Integer.parseInt(mode)); | |||
} | |||
@Override | |||
public void publishEventAccount(String eventAccountAddress, String eventName, String value, String sequence) { | |||
eventContext.getLedger().eventAccount(eventAccountAddress) | |||
.publish(eventName, value, Integer.parseInt(sequence)); | |||
} | |||
@Override | |||
public void invokeContract(String contractAddress, String method, String argSemicolonStr) { | |||
String[] args = argSemicolonStr.split(";"); | |||
BytesValue[] bytesValues = new BytesValue[args.length]; | |||
for(int i = 0; i < args.length; i++){ | |||
bytesValues[i] = TypedValue.fromText(args[i]); | |||
} | |||
eventContext.getLedger() | |||
.contract(contractAddress) | |||
.invoke(method, new BytesValueList() { | |||
@Override | |||
public BytesValue[] getValues() { | |||
return bytesValues; | |||
} | |||
}); | |||
} | |||
@Override | |||
public String deployContract(String pubkey, byte[] carBytes) { | |||
PubKey pubKey = KeyGenUtils.decodePubKey(pubkey); | |||
ContractCodeDeployOperation deployOperation = eventContext.getLedger().contracts() | |||
.deploy(new BlockchainIdentityData(pubKey), carBytes); | |||
return deployOperation.getContractID().getAddress().toString(); | |||
} | |||
@Override | |||
public void modifyContractRoleAndMode(String contractAddress, String role, String mode) { | |||
eventContext.getLedger().contract(contractAddress) | |||
.permission() | |||
.role(role) | |||
.mode(Integer.parseInt(mode)); | |||
} | |||
@Override | |||
public void modifyContractState(String contractAddress, String state) { | |||
AccountState accountState = AccountState.valueOf(state.trim().toUpperCase()); | |||
eventContext.getLedger().contract(contractAddress) | |||
.state(accountState); | |||
} | |||
} |
@@ -1,41 +0,0 @@ | |||
<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"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>jdchain-samples</artifactId> | |||
<version>1.6.0.RELEASE</version> | |||
<packaging>pom</packaging> | |||
<properties> | |||
<framework.version>1.6.0.RELEASE</framework.version> | |||
<core.version>1.6.0.RELEASE</core.version> | |||
</properties> | |||
<modules> | |||
<module>sdk-samples</module> | |||
<module>contract-samples</module> | |||
</modules> | |||
<build> | |||
<plugins> | |||
<plugin> | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-compiler-plugin</artifactId> | |||
<version>3.8.1</version> | |||
<configuration> | |||
<source>1.8</source> | |||
<target>1.8</target> | |||
<encoding>UTF-8</encoding> | |||
<optimize>false</optimize> | |||
<debug>true</debug> | |||
<showDeprecation>false</showDeprecation> | |||
<showWarnings>false</showWarnings> | |||
</configuration> | |||
</plugin> | |||
</plugins> | |||
</build> | |||
</project> |
@@ -1,74 +0,0 @@ | |||
<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"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>jdchain-samples</artifactId> | |||
<version>1.6.0.RELEASE</version> | |||
</parent> | |||
<artifactId>sdk-samples</artifactId> | |||
<dependencies> | |||
<!--以下依赖用于SDK常规使用--> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>sdk-client</artifactId> | |||
<version>${framework.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>sdk-rpc</artifactId> | |||
<version>${framework.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>crypto-classic</artifactId> | |||
<version>${framework.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>ledger-model</artifactId> | |||
<version>${framework.version}</version> | |||
</dependency> | |||
<!--样例程序中使用到的合约--> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>contract-samples</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<!--以下依赖用于 com.jdchain.samples.Network 中四节点网路环境初始化和启动 --> | |||
<dependency> | |||
<groupId>org.reflections</groupId> | |||
<artifactId>reflections</artifactId> | |||
<version>0.9.12</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>tools-initializer</artifactId> | |||
<version>${core.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>peer</artifactId> | |||
<version>${core.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>gateway</artifactId> | |||
<version>${core.version}</version> | |||
</dependency> | |||
<!--Junit--> | |||
<dependency> | |||
<groupId>junit</groupId> | |||
<artifactId>junit</artifactId> | |||
<version>4.12</version> | |||
</dependency> | |||
</dependencies> | |||
</project> |
@@ -1,299 +0,0 @@ | |||
package com.jdchain.samples.sdk; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.gateway.GatewayConfigProperties; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.LedgerInitProperties; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.ParticipantNodeState; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import com.jd.blockchain.sdk.BlockchainService; | |||
import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||
import com.jd.blockchain.tools.initializer.DBConnectionConfig; | |||
import com.jd.blockchain.tools.initializer.LedgerBindingConfig; | |||
import com.jd.blockchain.tools.initializer.PresetAnswerPrompter; | |||
import com.jd.blockchain.tools.initializer.Prompter; | |||
import com.jdchain.samples.sdk.testnet.GatewayRunner; | |||
import com.jdchain.samples.sdk.testnet.NodeWebContext; | |||
import com.jdchain.samples.sdk.testnet.PartNode; | |||
import com.jdchain.samples.sdk.testnet.PeerServer; | |||
import utils.concurrent.ThreadInvoker; | |||
import utils.io.FileUtils; | |||
import utils.net.NetworkAddress; | |||
import org.apache.logging.log4j.Level; | |||
import org.apache.logging.log4j.core.config.Configurator; | |||
import org.junit.Assert; | |||
import org.springframework.core.io.ClassPathResource; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.concurrent.CountDownLatch; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
/** | |||
* 测试网络 | |||
* 初始化启动基于内存的4节点JD Chain网络 | |||
*/ | |||
public class TestNet { | |||
// 测试网络公私钥及私钥密码信息 | |||
private static final String[] PUB_KEYS = { | |||
"7VeRLdGtSz1Y91gjLTqEdnkotzUfaAqdap3xw6fQ1yKHkvVq", | |||
"7VeRBsHM2nsGwP8b2ufRxz36hhNtSqjKTquzoa4WVKWty5sD", | |||
"7VeRAr3dSbi1xatq11ZcF7sEPkaMmtZhV9shonGJWk9T4pLe", | |||
"7VeRKoM5RE6iFXr214Hsiic2aoqCQ7MEU1dHQFRnjXQcReAS"}; | |||
private static final String[] PRIV_KEYS = { | |||
"177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", | |||
"177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", | |||
"177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", | |||
"177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns"}; | |||
private static final String PASSWORD = "abc"; | |||
// 存储配置 | |||
private static final String[] dbConnections = { | |||
"memory://local/0", | |||
"memory://local/1", | |||
"memory://local/2", | |||
"memory://local/3"}; | |||
// 共识协议 | |||
private static final String BFTSMART_PROVIDER = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"; | |||
// node节点服务端口,共识节点还会占用8910/8920/8930/8940/8911/8921/8931/8941用于共识服务,可以通过修改resources/network/bftsmart.config修改 | |||
private static final int[] NODE_PORTS = {12000, 12010, 12020, 12030}; | |||
// 网关服务端口 | |||
private static final int GATEWAY_PORT = 11000; | |||
public static void main(String[] args) { | |||
try { | |||
Configurator.setRootLevel(Level.OFF); | |||
// 内存账本初始化 | |||
HashDigest ledgerHash = initLedger(); | |||
// 启动Peer节点 | |||
PeerServer[] peerNodes = peerNodeStart(ledgerHash); | |||
// 睡20秒,等待共识节点启动成功 | |||
Thread.sleep(20000); | |||
// 启动网关 | |||
startGateway(peerNodes); | |||
// 睡10秒,等待网关启动成功 | |||
Thread.sleep(10000); | |||
// 初始化样例数据 | |||
initSampleData(ledgerHash); | |||
System.out.println(" ------------------- START NETWORK SUCCESS ------------------- "); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
System.out.println(" ------------------- START NETWORK FAILED ------------------- "); | |||
System.exit(-1); | |||
} | |||
} | |||
private static HashDigest initLedger() throws IOException { | |||
Prompter consolePrompter = new PresetAnswerPrompter("N"); | |||
LedgerInitProperties initSetting = LedgerInitProperties.resolve(new ClassPathResource("testnet/ledger.init").getInputStream()); | |||
ParticipantNode[] participantNodes = new ParticipantNode[PUB_KEYS.length]; | |||
for (int i = 0; i < PUB_KEYS.length; i++) { | |||
participantNodes[i] = new PartNode(i, KeyGenUtils.decodePubKey(PUB_KEYS[i]), ParticipantNodeState.CONSENSUS); | |||
} | |||
NetworkAddress initAddr0 = initSetting.getConsensusParticipant(0).getInitializerAddress(); | |||
NodeWebContext node0 = new NodeWebContext(0, initAddr0); | |||
NetworkAddress initAddr1 = initSetting.getConsensusParticipant(1).getInitializerAddress(); | |||
NodeWebContext node1 = new NodeWebContext(1, initAddr1); | |||
NetworkAddress initAddr2 = initSetting.getConsensusParticipant(2).getInitializerAddress(); | |||
NodeWebContext node2 = new NodeWebContext(2, initAddr2); | |||
NetworkAddress initAddr3 = initSetting.getConsensusParticipant(3).getInitializerAddress(); | |||
NodeWebContext node3 = new NodeWebContext(3, initAddr3); | |||
PrivKey privkey0 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD); | |||
PrivKey privkey1 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[1], PASSWORD); | |||
PrivKey privkey2 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[2], PASSWORD); | |||
PrivKey privkey3 = KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[3], PASSWORD); | |||
CountDownLatch quitLatch = new CountDownLatch(4); | |||
DBConnectionConfig testDb0 = new DBConnectionConfig(); | |||
testDb0.setConnectionUri(dbConnections[0]); | |||
ThreadInvoker.AsyncCallback<HashDigest> callback0 = node0.startInit(privkey0, initSetting, testDb0, consolePrompter, | |||
quitLatch); | |||
DBConnectionConfig testDb1 = new DBConnectionConfig(); | |||
testDb1.setConnectionUri(dbConnections[1]); | |||
ThreadInvoker.AsyncCallback<HashDigest> callback1 = node1.startInit(privkey1, initSetting, testDb1, consolePrompter, | |||
quitLatch); | |||
DBConnectionConfig testDb2 = new DBConnectionConfig(); | |||
testDb2.setConnectionUri(dbConnections[2]); | |||
ThreadInvoker.AsyncCallback<HashDigest> callback2 = node2.startInit(privkey2, initSetting, testDb2, consolePrompter, | |||
quitLatch); | |||
DBConnectionConfig testDb03 = new DBConnectionConfig(); | |||
testDb03.setConnectionUri(dbConnections[3]); | |||
ThreadInvoker.AsyncCallback<HashDigest> callback3 = node3.startInit(privkey3, initSetting, testDb03, consolePrompter, | |||
quitLatch); | |||
HashDigest ledgerHash0 = callback0.waitReturn(); | |||
HashDigest ledgerHash1 = callback1.waitReturn(); | |||
HashDigest ledgerHash2 = callback2.waitReturn(); | |||
HashDigest ledgerHash3 = callback3.waitReturn(); | |||
assertNotNull(ledgerHash0); | |||
assertEquals(ledgerHash0, ledgerHash1); | |||
assertEquals(ledgerHash0, ledgerHash2); | |||
assertEquals(ledgerHash0, ledgerHash3); | |||
return ledgerHash0; | |||
} | |||
private static PeerServer[] peerNodeStart(HashDigest ledgerHash) { | |||
NetworkAddress peerSrvAddr0 = new NetworkAddress("127.0.0.1", NODE_PORTS[0]); | |||
LedgerBindingConfig bindingConfig0 = loadBindingConfig(0, ledgerHash); | |||
PeerServer peer0 = new PeerServer(peerSrvAddr0, bindingConfig0); | |||
NetworkAddress peerSrvAddr1 = new NetworkAddress("127.0.0.1", NODE_PORTS[1]); | |||
LedgerBindingConfig bindingConfig1 = loadBindingConfig(1, ledgerHash); | |||
PeerServer peer1 = new PeerServer(peerSrvAddr1, bindingConfig1); | |||
NetworkAddress peerSrvAddr2 = new NetworkAddress("127.0.0.1", NODE_PORTS[2]); | |||
LedgerBindingConfig bindingConfig2 = loadBindingConfig(2, ledgerHash); | |||
PeerServer peer2 = new PeerServer(peerSrvAddr2, bindingConfig2); | |||
NetworkAddress peerSrvAddr3 = new NetworkAddress("127.0.0.1", NODE_PORTS[3]); | |||
LedgerBindingConfig bindingConfig3 = loadBindingConfig(3, ledgerHash); | |||
PeerServer peer3 = new PeerServer(peerSrvAddr3, bindingConfig3); | |||
ThreadInvoker.AsyncCallback<Object> peerStarting0 = peer0.start(); | |||
ThreadInvoker.AsyncCallback<Object> peerStarting1 = peer1.start(); | |||
ThreadInvoker.AsyncCallback<Object> peerStarting2 = peer2.start(); | |||
ThreadInvoker.AsyncCallback<Object> peerStarting3 = peer3.start(); | |||
peerStarting0.waitReturn(); | |||
peerStarting1.waitReturn(); | |||
peerStarting2.waitReturn(); | |||
peerStarting3.waitReturn(); | |||
return new PeerServer[]{peer0, peer1, peer2, peer3}; | |||
} | |||
private static LedgerBindingConfig loadBindingConfig(int id, HashDigest ledgerHash) { | |||
LedgerBindingConfig ledgerBindingConfig; | |||
String newLedger = ledgerHash.toBase58(); | |||
String resourceClassPath = "testnet/ledger-binding-mem-" + id + ".conf"; | |||
String ledgerBindingUrl = TestNet.class.getResource("/") + resourceClassPath; | |||
try { | |||
URL url = new URL(ledgerBindingUrl); | |||
File ledgerBindingConf = new File(url.getPath()); | |||
if (ledgerBindingConf.exists()) { | |||
List<String> readLines = org.apache.commons.io.FileUtils.readLines(ledgerBindingConf); | |||
List<String> writeLines = new ArrayList<>(); | |||
if (readLines != null && !readLines.isEmpty()) { | |||
String oldLedgerLine = null; | |||
for (String readLine : readLines) { | |||
if (readLine.startsWith("ledger")) { | |||
oldLedgerLine = readLine; | |||
break; | |||
} | |||
} | |||
String[] oldLedgerArray = oldLedgerLine.split("="); | |||
String oldLedger = oldLedgerArray[1]; | |||
if (!oldLedger.equalsIgnoreCase(newLedger)) { | |||
for (String readLine : readLines) { | |||
String newLine = readLine.replace(oldLedger, newLedger); | |||
writeLines.add(newLine); | |||
} | |||
} | |||
if (!writeLines.isEmpty()) { | |||
org.apache.commons.io.FileUtils.writeLines(ledgerBindingConf, writeLines); | |||
} | |||
} | |||
} | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
ClassPathResource res = new ClassPathResource(resourceClassPath); | |||
try (InputStream in = res.getInputStream()) { | |||
ledgerBindingConfig = LedgerBindingConfig.resolve(in); | |||
} catch (IOException e) { | |||
throw new IllegalStateException(e.getMessage(), e); | |||
} | |||
return ledgerBindingConfig; | |||
} | |||
private static void startGateway(PeerServer[] peerNodes) { | |||
GatewayConfigProperties.KeyPairConfig keyPairConfig = new GatewayConfigProperties.KeyPairConfig(); | |||
keyPairConfig.setPubKeyValue(PUB_KEYS[0]); | |||
keyPairConfig.setPrivKeyValue(PRIV_KEYS[0]); | |||
keyPairConfig.setPrivKeyPassword(KeyGenUtils.encodePasswordAsBase58(PASSWORD)); | |||
GatewayRunner gateway = new GatewayRunner("127.0.0.1", GATEWAY_PORT, keyPairConfig, new String[]{BFTSMART_PROVIDER}, null, peerNodes[0].getServiceAddress()); | |||
ThreadInvoker.AsyncCallback<Object> gwStarting = gateway.start(); | |||
gwStarting.waitReturn(); | |||
} | |||
private static void initSampleData(HashDigest ledgerHash) throws IOException { | |||
BlockchainKeypair admin = new BlockchainKeypair(KeyGenUtils.decodePubKey(PUB_KEYS[0]), KeyGenUtils.decodePrivKeyWithRawPassword(PRIV_KEYS[0], PASSWORD)); | |||
BlockchainKeypair user = new BlockchainKeypair( | |||
KeyGenUtils.decodePubKey("7VeRCfSaoBW3uRuvTqVb26PYTNwvQ1iZ5HBY92YKpEVN7Qht"), | |||
KeyGenUtils.decodePrivKey("177gjuGapUVdLnEDAkqjQWhZxHh5jL5W6Hg1q8kbdsbk1BKht4QkmuB6dKvyJrgKTRmXSgK", "8EjkXVSTxMFjCvNNsTo8RBMDEVQmk7gYkW4SCDuvdsBG")); | |||
BlockchainService blockchainService = GatewayServiceFactory.connect( | |||
"127.0.0.1", GATEWAY_PORT, false, admin).getBlockchainService(); | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledgerHash); | |||
// 初始化一个用户 | |||
txTemp.users().register(user.getIdentity()); | |||
// 创建角色 MANAGER | |||
txTemp.security().roles().configure("SAMPLE-ROLE") | |||
.enable(LedgerPermission.WRITE_DATA_ACCOUNT) | |||
.enable(TransactionPermission.DIRECT_OPERATION); | |||
// 设置用户角色权限 | |||
txTemp.security().authorziations().forUser(user.getAddress()).authorize("SAMPLE-ROLE"); | |||
// 初始化一个数据账户并设置KV | |||
txTemp.dataAccounts().register(user.getIdentity()); | |||
txTemp.dataAccount(user.getAddress()).setText("sample-key", "sample-value", -1); | |||
// 初始化一个事件账户并发布一个事件 | |||
txTemp.eventAccounts().register(user.getIdentity()); | |||
txTemp.eventAccount(user.getAddress()).publish("sample-event", "sample-content", -1); | |||
// 初始化一个合约 | |||
txTemp.contracts().deploy(user.getIdentity(), FileUtils.readBytes(new ClassPathResource("contract-samples-1.6.0.RELEASE.car").getFile())); | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
ptx.sign(admin); | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
} |
@@ -1,80 +0,0 @@ | |||
package com.jdchain.samples.sdk.testnet; | |||
import com.jd.blockchain.gateway.GatewayConfigProperties; | |||
import com.jd.blockchain.gateway.GatewayConfigProperties.KeyPairConfig; | |||
import utils.concurrent.ThreadInvoker; | |||
import utils.concurrent.ThreadInvoker.AsyncCallback; | |||
import utils.net.NetworkAddress; | |||
import com.jd.blockchain.gateway.GatewayServerBooter; | |||
import org.springframework.core.io.ClassPathResource; | |||
import org.springframework.util.CollectionUtils; | |||
import java.util.Map; | |||
public class GatewayRunner { | |||
private NetworkAddress serviceAddress; | |||
private GatewayServerBooter gatewayServer; | |||
public GatewayRunner(String host, int port, KeyPairConfig gatewayDefaultKey, NetworkAddress... masterPeerAddresses) { | |||
this(host, port, gatewayDefaultKey, null, null, masterPeerAddresses); | |||
} | |||
public GatewayRunner(String host, int port, KeyPairConfig gatewayDefaultKey, String[] providers, | |||
Map<String, Object> otherMap, NetworkAddress... masterPeerAddresses) { | |||
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); | |||
} | |||
} | |||
for (NetworkAddress address : masterPeerAddresses) { | |||
config.setMasterPeerAddress(address); | |||
} | |||
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; | |||
} | |||
} |
@@ -1,22 +0,0 @@ | |||
package com.jdchain.samples.sdk.testnet; | |||
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 LedgerInit { | |||
@Bean | |||
public CompositeConnectionFactory getCompositeConnectionFactory() { | |||
return new CompositeConnectionFactory(); | |||
} | |||
} |
@@ -1,99 +0,0 @@ | |||
package com.jdchain.samples.sdk.testnet; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.ledger.LedgerInitProperties; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.core.LedgerInitDecision; | |||
import com.jd.blockchain.ledger.core.LedgerInitProposal; | |||
import com.jd.blockchain.ledger.core.LedgerManager; | |||
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.Prompter; | |||
import com.jd.blockchain.tools.initializer.web.LedgerInitializeWebController; | |||
import utils.concurrent.ThreadInvoker; | |||
import 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 LedgerInitProposal getLocalPermission() { | |||
return controller.getLocalPermission(); | |||
} | |||
public LedgerInitDecision getLocalDecision() { | |||
return controller.getLocalDecision(); | |||
} | |||
public NodeWebContext(int id, NetworkAddress serverAddress) { | |||
this.id = id; | |||
this.serverAddress = serverAddress; | |||
} | |||
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); | |||
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(LedgerInit.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); | |||
} | |||
} |
@@ -1,59 +0,0 @@ | |||
package com.jdchain.samples.sdk.testnet; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.ParticipantNodeState; | |||
import utils.Bytes; | |||
public class PartNode implements ParticipantNode { | |||
private int id; | |||
private Bytes address; | |||
private String name; | |||
private PubKey pubKey; | |||
private ParticipantNodeState participantNodeState; | |||
public PartNode(int id, PubKey pubKey, ParticipantNodeState participantNodeState) { | |||
this(id, id + "", pubKey, participantNodeState); | |||
} | |||
public PartNode(int id, String name, PubKey pubKey, ParticipantNodeState participantNodeState) { | |||
this.id = id; | |||
this.name = name; | |||
this.pubKey = pubKey; | |||
this.address = AddressEncoding.generateAddress(pubKey); | |||
this.participantNodeState = participantNodeState; | |||
} | |||
@Override | |||
public int getId() { | |||
return id; | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
@Override | |||
public String getName() { | |||
return name; | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
@Override | |||
public ParticipantNodeState getParticipantNodeState() { | |||
return participantNodeState; | |||
} | |||
} |
@@ -1,67 +0,0 @@ | |||
package com.jdchain.samples.sdk.testnet; | |||
import com.jd.blockchain.ledger.core.LedgerManager; | |||
import com.jd.blockchain.peer.PeerServerBooter; | |||
import com.jd.blockchain.storage.service.DbConnectionFactory; | |||
import com.jd.blockchain.tools.initializer.LedgerBindingConfig; | |||
import utils.concurrent.ThreadInvoker; | |||
import utils.net.NetworkAddress; | |||
public class PeerServer { | |||
private NetworkAddress serviceAddress; | |||
private volatile PeerServerBooter booter; | |||
private LedgerBindingConfig ledgerBindingConfig; | |||
public DbConnectionFactory getDBConnectionFactory() { | |||
return booter.getDBConnectionFactory(); | |||
} | |||
public NetworkAddress getServiceAddress() { | |||
return serviceAddress; | |||
} | |||
public LedgerBindingConfig getLedgerBindingConfig() { | |||
return ledgerBindingConfig; | |||
} | |||
public PeerServer(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig) { | |||
this(serviceAddress, ledgerBindingConfig, null, null); | |||
} | |||
public PeerServer(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig, DbConnectionFactory dbConnectionFactory) { | |||
this(serviceAddress, ledgerBindingConfig, dbConnectionFactory, null); | |||
} | |||
public PeerServer(NetworkAddress serviceAddress, LedgerBindingConfig ledgerBindingConfig, | |||
DbConnectionFactory dbConnectionFactory, LedgerManager ledgerManager) { | |||
this.serviceAddress = serviceAddress; | |||
this.ledgerBindingConfig = ledgerBindingConfig; | |||
if (dbConnectionFactory == null) { | |||
this.booter = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), | |||
serviceAddress.getPort()); | |||
} else { | |||
this.booter = new PeerServerBooter(ledgerBindingConfig, serviceAddress.getHost(), | |||
serviceAddress.getPort(), dbConnectionFactory, ledgerManager); | |||
} | |||
} | |||
public ThreadInvoker.AsyncCallback<Object> start() { | |||
ThreadInvoker<Object> invoker = new ThreadInvoker<Object>() { | |||
@Override | |||
protected Object invoke() throws Exception { | |||
booter.start(); | |||
return null; | |||
} | |||
}; | |||
return invoker.start(); | |||
} | |||
public void stop() { | |||
booter.close(); | |||
} | |||
} |
@@ -1,20 +0,0 @@ | |||
# SDK Sample 相关配置,请根据实际情况进行修改 | |||
# 签名用户配置 | |||
# 公钥 | |||
pubkey=7VeRLdGtSz1Y91gjLTqEdnkotzUfaAqdap3xw6fQ1yKHkvVq | |||
# 私钥 | |||
privkey=177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x | |||
# Base58编码的私钥密码 | |||
password=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY | |||
# 网关配置 | |||
# IP | |||
gateway.host=localhost | |||
# 端口 | |||
gateway.port=11000 | |||
# 账本,为空时选择网关查询到的账本列表第一个 | |||
ledger= |
@@ -1,155 +0,0 @@ | |||
# 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 Participant0 ###### | |||
############################################ | |||
system.server.0.network.host=127.0.0.1 | |||
system.server.0.network.port=8910 | |||
system.server.0.network.secure=false | |||
############################################ | |||
###### #Consensus Participant1 ###### | |||
############################################ | |||
system.server.1.network.host=127.0.0.1 | |||
system.server.1.network.port=8920 | |||
system.server.1.network.secure=false | |||
############################################ | |||
###### #Consensus Participant2 ###### | |||
############################################ | |||
system.server.2.network.host=127.0.0.1 | |||
system.server.2.network.port=8930 | |||
system.server.2.network.secure=false | |||
############################################ | |||
###### Consensus Participant3 ###### | |||
############################################ | |||
system.server.3.network.host=127.0.0.1 | |||
system.server.3.network.port=8940 | |||
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 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 = 5000 | |||
#Maximum batch size (in number of messages) | |||
system.totalordermulticast.maxbatchsize = 400 | |||
#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 = 2001 | |||
#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 |
@@ -1,25 +0,0 @@ | |||
#绑定的账本的hash列表;以逗号分隔; | |||
ledger.bindings=6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ | |||
#第 1 个账本[6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ]的配置; | |||
#账本的名字; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.name=sample-network | |||
#账本底层数据结构; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.data.structure=MERKLE_TREE | |||
#账本的当前共识参与方的ID; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.id=0 | |||
#账本的当前共识参与方的名字; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.name=a.com | |||
#账本的当前共识参与方的私钥文件的保存路径; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk-path= | |||
#账本的当前共识参与方的私钥内容(Base58编码);如果指定了,优先选用此属性,其次是 pk-path 属性; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk=177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x | |||
#账本的当前共识参与方的私钥文件的读取口令;可为空;如果为空时,节点的启动过程中需要手动从控制台输入; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pwd=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY | |||
#账本的当前共识参与方地址 | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.address=LdeP3fY7jJbNwL8CiL2wU21AF9unDWQjVEW5w | |||
#账本的存储数据库的连接字符串; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.uri=memory://local/0 | |||
#账本的存储数据库的连接口令; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.pwd= |
@@ -1,25 +0,0 @@ | |||
#绑定的账本的hash列表;以逗号分隔; | |||
ledger.bindings=6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ | |||
#第 1 个账本[6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ]的配置; | |||
#账本的名字; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.name=sample-network | |||
#账本底层数据结构; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.data.structure=MERKLE_TREE | |||
#账本的当前共识参与方的ID; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.id=1 | |||
#账本的当前共识参与方的名字; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.name=b.com | |||
#账本的当前共识参与方的私钥文件的保存路径; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk-path= | |||
#账本的当前共识参与方的私钥内容(Base58编码);如果指定了,优先选用此属性,其次是 pk-path 属性; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk=177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT | |||
#账本的当前共识参与方的私钥文件的读取口令;可为空;如果为空时,节点的启动过程中需要手动从控制台输入; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pwd=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY | |||
#账本的当前共识参与方地址 | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.address=LdeNnz88dH6CA6PwkVdn3nFRibUKP3sFT2byG | |||
#账本的存储数据库的连接字符串; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.uri=memory://local/1 | |||
#账本的存储数据库的连接口令; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.pwd= |
@@ -1,25 +0,0 @@ | |||
#绑定的账本的hash列表;以逗号分隔; | |||
ledger.bindings=6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ | |||
#第 1 个账本[6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ]的配置; | |||
#账本的名字; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.name=sample-network | |||
#账本底层数据结构; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.data.structure=MERKLE_TREE | |||
#账本的当前共识参与方的ID; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.id=2 | |||
#账本的当前共识参与方的名字; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.name=c.com | |||
#账本的当前共识参与方的私钥文件的保存路径; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk-path= | |||
#账本的当前共识参与方的私钥内容(Base58编码);如果指定了,优先选用此属性,其次是 pk-path 属性; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk=177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF | |||
#账本的当前共识参与方的私钥文件的读取口令;可为空;如果为空时,节点的启动过程中需要手动从控制台输入; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pwd=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY | |||
#账本的当前共识参与方地址 | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.address=LdeNmdpT4DiTwLUP9jRQhwdRBRiXeHno456vy | |||
#账本的存储数据库的连接字符串; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.uri=memory://local/2 | |||
#账本的存储数据库的连接口令; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.pwd= |
@@ -1,25 +0,0 @@ | |||
#绑定的账本的hash列表;以逗号分隔; | |||
ledger.bindings=6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ | |||
#第 1 个账本[6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ]的配置; | |||
#账本的名字; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.name=sample-network | |||
#账本底层数据结构; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.data.structure=MERKLE_TREE | |||
#账本的当前共识参与方的ID; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.id=3 | |||
#账本的当前共识参与方的名字; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.name=d.com | |||
#账本的当前共识参与方的私钥文件的保存路径; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk-path= | |||
#账本的当前共识参与方的私钥内容(Base58编码);如果指定了,优先选用此属性,其次是 pk-path 属性; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pk=177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns | |||
#账本的当前共识参与方的私钥文件的读取口令;可为空;如果为空时,节点的启动过程中需要手动从控制台输入; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.pwd=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY | |||
#账本的当前共识参与方地址 | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.parti.address=LdeNekdXMHqyz9Qxc2jDSBnkvvZLbty6pRDdP | |||
#账本的存储数据库的连接字符串; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.uri=memory://local/3 | |||
#账本的存储数据库的连接口令; | |||
binding.6BCg5vgU57ykY6g2CpyUnt5ZMgdxfD1b3qXxQrRyfiXTQ.db.pwd= |
@@ -1,76 +0,0 @@ | |||
#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取; | |||
ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe | |||
#账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; | |||
ledger.name=sample-ledger | |||
#声明的账本创建时间;格式为 “yyyy-MM-dd HH:mm:ss.SSSZ”,表示”年-月-日 时:分:秒:毫秒时区“;例如:“2019-08-01 14:26:58.069+0800”,其中,+0800 表示时区是东8区 | |||
created-time=2019-08-01 14:26:58.069+0800 | |||
#共识服务提供者;必须; | |||
consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||
#共识服务的参数配置;必须; | |||
consensus.conf=classpath:testnet/bftsmart.config | |||
#密码服务提供者列表,以英文逗点“,”分隔;必须; | |||
crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ | |||
com.jd.blockchain.crypto.service.sm.SMCryptoService | |||
#账本数据底层结构,分为:MERKLE_TREE, KV两种,默认MERKLE_TREE | |||
ledger.data.structure=MERKLE_TREE | |||
#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; | |||
cons_parti.count=4 | |||
#第0个参与方的名称; | |||
cons_parti.0.name=a.com | |||
#第0个参与方的公钥文件路径; | |||
cons_parti.0.pubkey-path= | |||
#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | |||
cons_parti.0.pubkey=7VeRLdGtSz1Y91gjLTqEdnkotzUfaAqdap3xw6fQ1yKHkvVq | |||
#第0个参与方的账本初始服务的主机; | |||
cons_parti.0.initializer.host=127.0.0.1 | |||
#第0个参与方的账本初始服务的端口; | |||
cons_parti.0.initializer.port=9800 | |||
#第0个参与方的账本初始服务是否开启安全连接; | |||
cons_parti.0.initializer.secure=false | |||
#第1个参与方的名称; | |||
cons_parti.1.name=b.com | |||
#第1个参与方的公钥文件路径; | |||
cons_parti.1.pubkey-path= | |||
#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | |||
cons_parti.1.pubkey=7VeRBsHM2nsGwP8b2ufRxz36hhNtSqjKTquzoa4WVKWty5sD | |||
#第1个参与方的账本初始服务的主机; | |||
cons_parti.1.initializer.host=127.0.0.1 | |||
#第1个参与方的账本初始服务的端口; | |||
cons_parti.1.initializer.port=9810 | |||
#第1个参与方的账本初始服务是否开启安全连接; | |||
cons_parti.1.initializer.secure=false | |||
#第2个参与方的名称; | |||
cons_parti.2.name=c.com | |||
#第2个参与方的公钥文件路径; | |||
cons_parti.2.pubkey-path= | |||
#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | |||
cons_parti.2.pubkey=7VeRAr3dSbi1xatq11ZcF7sEPkaMmtZhV9shonGJWk9T4pLe | |||
#第2个参与方的账本初始服务的主机; | |||
cons_parti.2.initializer.host=127.0.0.1 | |||
#第2个参与方的账本初始服务的端口; | |||
cons_parti.2.initializer.port=9820 | |||
#第2个参与方的账本初始服务是否开启安全连接; | |||
cons_parti.2.initializer.secure=false | |||
#第3个参与方的名称; | |||
cons_parti.3.name=c.com | |||
#第3个参与方的公钥文件路径; | |||
cons_parti.3.pubkey-path= | |||
#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; | |||
cons_parti.3.pubkey=7VeRKoM5RE6iFXr214Hsiic2aoqCQ7MEU1dHQFRnjXQcReAS | |||
#第3个参与方的账本初始服务的主机; | |||
cons_parti.3.initializer.host=127.0.0.1 | |||
#第3个参与方的账本初始服务的端口; | |||
cons_parti.3.initializer.port=9830 | |||
#第3个参与方的账本初始服务是否开启安全连接; | |||
cons_parti.3.initializer.secure=false |
@@ -1,175 +0,0 @@ | |||
package com.jdchain.samples.sdk; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.ledger.AccountState; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesDataList; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.transaction.ContractEventSendOperationBuilder; | |||
import com.jd.blockchain.transaction.ContractReturnValue; | |||
import com.jd.blockchain.transaction.GenericValueHolder; | |||
import com.jdchain.samples.contract.SampleContract; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import utils.io.BytesUtils; | |||
import utils.io.FileUtils; | |||
import java.util.UUID; | |||
/** | |||
* 合约相关操作示例: | |||
* 合约部署,合约调用 | |||
*/ | |||
public class ContractSample extends SampleBase { | |||
/** | |||
* 有两种方式部署合约: | |||
* 1. contract-samples模块下,配置好pom里面的参数,执行 mvn clean deploy 即可 | |||
* 2. 打包contract-samples项目生成 car包,参考testDeploy测试代码部署 | |||
*/ | |||
@Test | |||
public void testDeploy() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 生成合约账户 | |||
BlockchainKeypair contractAccount = BlockchainKeyGenerator.getInstance().generate(); | |||
System.out.println("合约地址:" + contractAccount.getAddress()); | |||
// 部署合约 | |||
txTemp.contracts().deploy(contractAccount.getIdentity(), FileUtils.readBytes("src/main/resources/contract-samples-1.6.0.RELEASE.car")); | |||
// 准备交易 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 有两种方式更新合约代码: | |||
* 1. contract-samples模块下,配置好pom里面的参数,其中contractAddress设置为已部署上链合约公钥信息,执行 mvn clean deploy 即可 | |||
* 2. 打包contract-samples项目生成 car包,参考testUpdate测试代码部署 | |||
*/ | |||
@Test | |||
public void testUpdate() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 解析合约身份信息 | |||
BlockchainIdentity contractIdentity = new BlockchainIdentityData(KeyGenUtils.decodePubKey("7VeRCfSaoBW3uRuvTqVb26PYTNwvQ1iZ5HBY92YKpEVN7Qht")); | |||
System.out.println("合约地址:" + contractIdentity.getAddress()); | |||
// 部署合约 | |||
txTemp.contracts().deploy(contractIdentity, FileUtils.readBytes("src/main/resources/contract-samples-1.6.0.RELEASE.car")); | |||
// 准备交易 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 基于动态代理方式合约调用,需要依赖合约接口 | |||
*/ | |||
@Test | |||
public void testExecuteByProxy() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 运行前,填写正确的合约地址 | |||
// 一次交易中可调用多个(多次调用)合约方法 | |||
// 调用合约的 registerUser 方法 | |||
SampleContract sampleContract = txTemp.contract("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye", SampleContract.class); | |||
GenericValueHolder<String> userAddress = ContractReturnValue.decode(sampleContract.registerUser(UUID.randomUUID().toString())); | |||
// 准备交易 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
// 获取返回值 | |||
System.out.println(userAddress.get()); | |||
} | |||
/** | |||
* 非动态代理方式合约调用,不需要依赖合约接口及实现 | |||
*/ | |||
@Test | |||
public void testExecuteWithArgus() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
ContractEventSendOperationBuilder builder = txTemp.contract("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye"); | |||
// 运行前,填写正确的合约地址,数据账户地址等参数 | |||
// 一次交易中可调用多个(多次调用)合约方法 | |||
// 调用合约的 registerUser 方法,传入合约地址,合约方法名,合约方法参数列表 | |||
builder.invoke("registerUser", | |||
new BytesDataList(new TypedValue[]{ | |||
TypedValue.fromText(UUID.randomUUID().toString()) | |||
}) | |||
); | |||
// 准备交易 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
Assert.assertEquals(1, response.getOperationResults().length); | |||
// 解析合约方法调用返回值 | |||
for (int i = 0; i < response.getOperationResults().length; i++) { | |||
BytesValue content = response.getOperationResults()[i].getResult(); | |||
switch (content.getType()) { | |||
case TEXT: | |||
System.out.println(content.getBytes().toUTF8String()); | |||
break; | |||
case INT64: | |||
System.out.println(BytesUtils.toLong(content.getBytes().toBytes())); | |||
break; | |||
case BOOLEAN: | |||
System.out.println(BytesUtils.toBoolean(content.getBytes().toBytes()[0])); | |||
break; | |||
default: // byte[], Bytes | |||
System.out.println(content.getBytes().toBase58()); | |||
break; | |||
} | |||
} | |||
} | |||
/** | |||
* 更新合约状态 | |||
*/ | |||
@Test | |||
public void updateContractState() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 合约状态分为:NORMAL(正常) FREEZE(冻结) REVOKE(销毁) | |||
// 冻结合约 | |||
txTemp.contract("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye").state(AccountState.FREEZE); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 更新合约权限 | |||
*/ | |||
@Test | |||
public void updateDPermission() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 配置合约权限 | |||
// 如下配置表示仅有 ROLE 角色用户才有调用 LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye 权限 | |||
txTemp.contract("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye").permission().mode(70).role("ROLE"); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
} |
@@ -1,98 +0,0 @@ | |||
package com.jdchain.samples.sdk; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import utils.Bytes; | |||
/** | |||
* 数据账户相关操作示例: | |||
* 创建数据账户,写入KV数据 | |||
*/ | |||
public class DataAccountSample extends SampleBase { | |||
/** | |||
* 注册数据账户 | |||
*/ | |||
@Test | |||
public void testRegisterDataAccount() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 生成数据账户 | |||
BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); | |||
System.out.println("数据账户地址:" + dataAccount.getAddress()); | |||
// 注册数据账户 | |||
txTemp.dataAccounts().register(dataAccount.getIdentity()); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 设置KV | |||
*/ | |||
@Test | |||
public void testSetKV() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 请正确填写数据账户地址 | |||
// expVersion是针对此key的插入更新操作次数严格递增,初始为-1,再次运行本测试用例请修改该值,否则服务端将报版本冲突异常。 | |||
txTemp.dataAccount(Bytes.fromBase58("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye")) | |||
.setText("key1", "value1", -1) | |||
.setInt64("key2", 1, -1) | |||
.setJSON("key3", "{}", -1) | |||
.setBytes("key4", Bytes.fromInt(2), -1); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 注册数据账户的同时设置KV,一个事务内 | |||
*/ | |||
@Test | |||
public void testRegisterDataAccountAndSetKV() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 生成数据账户 | |||
BlockchainKeypair dataAccount = BlockchainKeyGenerator.getInstance().generate(); | |||
System.out.println("数据账户地址:" + dataAccount.getAddress()); | |||
// 注册数据账户 | |||
txTemp.dataAccounts().register(dataAccount.getIdentity()); | |||
// 设置KV | |||
txTemp.dataAccount(dataAccount.getAddress()) | |||
.setText("key", "value", -1); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 更新数据账户权限 | |||
*/ | |||
@Test | |||
public void updateDPermission() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 配置数据账户权限 | |||
// 如下配置表示仅有 ROLE 角色用户才有写入 LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye 权限 | |||
txTemp.dataAccount("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye").permission().mode(70).role("ROLE"); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
} |
@@ -1,149 +0,0 @@ | |||
package com.jdchain.samples.sdk; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.Event; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.SystemEvent; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import utils.Bytes; | |||
import utils.io.BytesUtils; | |||
import java.util.concurrent.CountDownLatch; | |||
/** | |||
* 事件账户相关操作示例: | |||
* 事件账户创建,事件发布,事件监听 | |||
*/ | |||
public class EventSample extends SampleBase { | |||
/** | |||
* 事件监听 | |||
*/ | |||
@Test | |||
public void testEventListen() { | |||
// 事件监听会创建子线程,为阻止子线程被直接关闭,加入等待 | |||
CountDownLatch cdl = new CountDownLatch(1); | |||
// 监听系统事件,目前仅有新区快产生事件 | |||
blockchainService.monitorSystemEvent(ledger, | |||
SystemEvent.NEW_BLOCK_CREATED, 0, (eventMessages, eventContext) -> { | |||
for (Event eventMessage : eventMessages) { | |||
// content中存放的是当前链上最新高度 | |||
System.out.println("New block:" + eventMessage.getSequence() + ":" + BytesUtils.toLong(eventMessage.getContent().getBytes().toBytes())); | |||
} | |||
}); | |||
// 监听用户自定义事件 | |||
blockchainService.monitorUserEvent(ledger, "LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye", "sample-event", 0, (eventMessage, eventContext) -> { | |||
BytesValue content = eventMessage.getContent(); | |||
switch (content.getType()) { | |||
case TEXT: | |||
case XML: | |||
case JSON: | |||
System.out.println(eventMessage.getName() + ":" + eventMessage.getSequence() + ":" + content.getBytes().toUTF8String()); | |||
break; | |||
case INT64: | |||
case TIMESTAMP: | |||
System.out.println(eventMessage.getName() + ":" + eventMessage.getSequence() + ":" + BytesUtils.toLong(content.getBytes().toBytes())); | |||
break; | |||
default: // byte[], Bytes | |||
System.out.println(eventMessage.getName() + ":" + eventMessage.getSequence() + ":" + content.getBytes().toBase58()); | |||
break; | |||
} | |||
}); | |||
try { | |||
cdl.await(); | |||
} catch (InterruptedException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
/** | |||
* 注册事件账户 | |||
*/ | |||
@Test | |||
public void testRegisterEventAccount() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 生成事件账户 | |||
BlockchainKeypair eventAccount = BlockchainKeyGenerator.getInstance().generate(); | |||
System.out.println("事件账户地址:" + eventAccount.getAddress()); | |||
// 注册事件账户 | |||
txTemp.eventAccounts().register(eventAccount.getIdentity()); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 发布事件 | |||
*/ | |||
@Test | |||
public void testPublishEvent() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 请正确填写数据账户地址 | |||
// sequence是针对此消息name的插入更新操作次数严格递增,初始为-1,再次运行本测试用例请修改该值,否则服务端将报版本冲突异常。 | |||
txTemp.eventAccount(Bytes.fromBase58("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye")) | |||
.publish("topic1", "content1", -1) | |||
.publish("topic1", "content2", 0) | |||
.publish("topic1", "content3", 1) | |||
.publish("topic2", "content", -1) | |||
.publish("topic3", 1, -1) | |||
.publish("topic4", Bytes.fromInt(1), -1); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 注册事件账户的同时发布事件,一个事务内 | |||
*/ | |||
@Test | |||
public void testRegisterEventAccountAndPublishEvent() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 生成事件账户 | |||
BlockchainKeypair eventAccount = BlockchainKeyGenerator.getInstance().generate(); | |||
System.out.println("事件账户地址:" + eventAccount.getAddress()); | |||
// 注册事件账户 | |||
txTemp.eventAccounts().register(eventAccount.getIdentity()); | |||
// 发布事件 | |||
txTemp.eventAccount(eventAccount.getAddress()).publish("topic", "content", -1); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 更新事件账户权限 | |||
*/ | |||
@Test | |||
public void updateDPermission() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 配置事件账户权限 | |||
// 如下配置表示仅有 ROLE 角色用户才有写入 LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye 权限 | |||
txTemp.eventAccount("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye").permission().mode(70).role("ROLE"); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
} |
@@ -1,133 +0,0 @@ | |||
package com.jdchain.samples.sdk; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.http.HttpResponse; | |||
import org.apache.http.client.HttpClient; | |||
import org.apache.http.client.entity.UrlEncodedFormEntity; | |||
import org.apache.http.client.methods.HttpPost; | |||
import org.apache.http.impl.client.HttpClients; | |||
import org.apache.http.message.BasicNameValuePair; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import com.jd.httpservice.converters.JsonResponseConverter; | |||
import com.jd.httpservice.utils.web.WebResponse; | |||
import utils.codec.Base58Utils; | |||
import utils.crypto.classic.SHA256Utils; | |||
import utils.security.ShaUtils; | |||
/** | |||
* 参与方节点相关操作示例: | |||
* 注册/激活/移除参与方操作 | |||
* <p> | |||
* 本样例无法直接运行,请用户务必参照共识节点相关操作文档步骤完成各种前置操作,然后根据实际配置修改本样例各方法内参数 | |||
*/ | |||
public class ParticipantSample extends SampleBase { | |||
// 注册参与方 | |||
@Test | |||
public void registerParticipant() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 生成用户信息 | |||
BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); | |||
String pwd = Base58Utils.encode(SHA256Utils.hash("1".getBytes())); | |||
System.out.println("参与方私钥:" + KeyGenUtils.encodePrivKey(user.getPrivKey(), pwd)); | |||
System.out.println("参与方私钥密码:" + pwd); | |||
System.out.println("参与方公钥:" + KeyGenUtils.encodePubKey(user.getPubKey())); | |||
System.out.println("参与方地址:" + user.getAddress()); | |||
// 注册参与方 | |||
txTemp.participants().register("new peer node", user.getIdentity()); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 激活参与方 | |||
* 执行前请确保新节点已注册,且已经参照共识节点相关操作文档创建并启动新节点!!! | |||
* 然后根据实际情况修改请求参数 | |||
* | |||
* @throws Exception | |||
*/ | |||
@Test | |||
public void activeParticipant() throws Exception { | |||
// 新节点API服务IP和端口 | |||
String newNodeIp = "127.0.0.1"; | |||
String newNodeApiPort = "12040"; | |||
// 账本信息 | |||
String ledgerHash = ledger.toString(); | |||
// 新节点共识配置 | |||
String newNodeConsensusHost = "127.0.0.1"; | |||
String newNodeConsensusPot = "8950"; | |||
// 区块高度最新的节点API服务IP和端口,用于区块同步 | |||
String syncNodeHost = "127.0.0.1"; | |||
String syncNodePort = "12000"; | |||
// 发送POST请求执行节点激活操作 | |||
HttpPost httpPost = new HttpPost(String.format("http://%s:%s/management/delegate/activeparticipant", newNodeIp, newNodeApiPort)); | |||
List<BasicNameValuePair> params = new ArrayList<>(); | |||
params.add(new BasicNameValuePair("ledgerHash", ledgerHash)); | |||
params.add(new BasicNameValuePair("consensusHost", newNodeConsensusHost)); | |||
params.add(new BasicNameValuePair("consensusPort", newNodeConsensusPot)); | |||
params.add(new BasicNameValuePair("remoteManageHost", syncNodeHost)); | |||
params.add(new BasicNameValuePair("remoteManagePort", syncNodePort)); | |||
params.add(new BasicNameValuePair("shutdown", "false")); | |||
httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); | |||
HttpClient httpClient = HttpClients.createDefault(); | |||
HttpResponse response = httpClient.execute(httpPost); | |||
JsonResponseConverter jsonConverter = new JsonResponseConverter(WebResponse.class); | |||
WebResponse webResponse = (WebResponse) jsonConverter.getResponse(null, response.getEntity().getContent(), null); | |||
Assert.assertTrue(webResponse.isSuccess()); | |||
} | |||
/** | |||
* 移除参与方 | |||
* 执行前请确保新节点已启动且出于参与共识状态!!! | |||
* 然后根据实际情况修改请求参数 | |||
* | |||
* @throws Exception | |||
*/ | |||
@Test | |||
public void removeParticipant() throws Exception { | |||
// 待移除节点API服务IP和端口 | |||
String nodeIp = "127.0.0.1"; | |||
String nodeApiPort = "12030"; | |||
// 账本信息 | |||
String ledgerHash = ledger.toString(); | |||
// 待移除节点地址 | |||
String participantAddress = "LdeNekdXMHqyz9Qxc2jDSBnkvvZLbty6pRDdP"; | |||
// 区块高度最新的节点API服务IP和端口,用于区块同步 | |||
String syncNodeHost = "127.0.0.1"; | |||
String syncNodePort = "12000"; | |||
// 发送POST请求执行节点移除操作 | |||
HttpPost httpPost = new HttpPost(String.format("http://%s:%s/management/delegate/deactiveparticipant", nodeIp, nodeApiPort)); | |||
List<BasicNameValuePair> params = new ArrayList<>(); | |||
params.add(new BasicNameValuePair("ledgerHash", ledgerHash)); | |||
params.add(new BasicNameValuePair("participantAddress", participantAddress)); | |||
params.add(new BasicNameValuePair("remoteManageHost", syncNodeHost)); | |||
params.add(new BasicNameValuePair("remoteManagePort", syncNodePort)); | |||
httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); | |||
HttpClient httpClient = HttpClients.createDefault(); | |||
HttpResponse response = httpClient.execute(httpPost); | |||
JsonResponseConverter jsonConverter = new JsonResponseConverter(WebResponse.class); | |||
WebResponse webResponse = (WebResponse) jsonConverter.getResponse(null, response.getEntity().getContent(), null); | |||
Assert.assertTrue(webResponse.isSuccess()); | |||
} | |||
} |
@@ -1,848 +0,0 @@ | |||
package com.jdchain.samples.sdk; | |||
import com.jd.blockchain.contract.OnLineContractProcessor; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ConsensusSettingsUpdateOperation; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.DataAccountInfo; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.Event; | |||
import com.jd.blockchain.ledger.EventAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.EventPublishOperation; | |||
import com.jd.blockchain.ledger.KVDataVO; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInfo; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.Operation; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.ParticipantRegisterOperation; | |||
import com.jd.blockchain.ledger.PrivilegeSet; | |||
import com.jd.blockchain.ledger.RolesConfigureOperation; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionResult; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.UserAuthorizeOperation; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.ledger.UserPrivilegeSet; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import utils.Property; | |||
import utils.codec.Base58Utils; | |||
import utils.io.BytesUtils; | |||
import java.util.Arrays; | |||
/** | |||
* 查询样例 | |||
*/ | |||
public class QuerySample extends SampleBase { | |||
HashDigest sampleHash = Crypto.resolveAsHashDigest(Base58Utils.decode("j5sTuEAWmLWKFwXgpdUCxbQN1XmZfkQdC94UT2AqQEt7hp")); | |||
String sampleUserAddress = "LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye"; | |||
String sampleDataAccountAddress = "LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye"; | |||
String sampleContractAddress = "LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye"; | |||
String sampleEventAddress = "LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye"; | |||
String sampleKey = "sample-key"; | |||
String sampleEvent = "sample-event"; | |||
long sampleVersion = 0; | |||
String sampleRoleName = "SAMPLE-ROLE"; | |||
/** | |||
* 查询账本列表 | |||
*/ | |||
@Test | |||
public void getLedgerHashs() { | |||
HashDigest[] digests = blockchainService.getLedgerHashs(); | |||
for (HashDigest digest : digests) { | |||
System.out.println(digest); | |||
} | |||
} | |||
/** | |||
* 查询账本信息,区块hash,区块高度 | |||
*/ | |||
@Test | |||
public void getLedger() { | |||
LedgerInfo ledgerInfo = blockchainService.getLedger(ledger); | |||
// 账本哈希 | |||
System.out.println(ledgerInfo.getHash()); | |||
// 最新区块哈希 | |||
System.out.println(ledgerInfo.getLatestBlockHash()); | |||
// 最新区块高度 | |||
System.out.println(ledgerInfo.getLatestBlockHeight()); | |||
} | |||
/** | |||
* 查询账本信息,元数据,参与方,账本配置等 | |||
*/ | |||
@Test | |||
public void getLedgerAdminInfo() { | |||
LedgerAdminInfo adminInfo = blockchainService.getLedgerAdminInfo(ledger); | |||
System.out.println(adminInfo.getParticipantCount()); | |||
} | |||
/** | |||
* 查询共识参与方 | |||
*/ | |||
@Test | |||
public void getConsensusParticipants() { | |||
ParticipantNode[] nodes = blockchainService.getConsensusParticipants(ledger); | |||
for (ParticipantNode node : nodes) { | |||
System.out.println("ID: " + node.getId()); | |||
System.out.println("Address: " + node.getAddress().toString()); | |||
System.out.println("PubKey: " + node.getPubKey().toString()); | |||
System.out.println("State: " + node.getParticipantNodeState()); | |||
} | |||
} | |||
/** | |||
* 查询账本的元数据 | |||
*/ | |||
@Test | |||
public void getLedgerMetadata() { | |||
LedgerMetadata metadata = blockchainService.getLedgerMetadata(ledger); | |||
System.out.println(Base58Utils.encode(metadata.getSeed())); | |||
System.out.println(metadata.getParticipantsHash().toBase58()); | |||
System.out.println(metadata.getSettingsHash().toBase58()); | |||
} | |||
/** | |||
* 根据高度查询区块 | |||
*/ | |||
@Test | |||
public void getBlockByHeight() { | |||
LedgerBlock block1 = blockchainService.getBlock(ledger, -1); | |||
// 账本哈希 | |||
System.out.println(block1.getLedgerHash()); | |||
// 区块高度 | |||
System.out.println(block1.getHeight()); | |||
// 区块时间 | |||
System.out.println(block1.getTimestamp()); | |||
// 区块哈希 | |||
System.out.println(block1.getHash()); | |||
// 上一区块哈希 | |||
System.out.println(block1.getPreviousHash()); | |||
// 交易数据集根哈希 | |||
System.out.println(block1.getTransactionSetHash()); | |||
// 用户角色权限数据集根哈希 | |||
System.out.println(block1.getAdminAccountHash()); | |||
// 合约数据集根哈希 | |||
System.out.println(block1.getContractAccountSetHash()); | |||
// 数据账户集根哈希 | |||
System.out.println(block1.getDataAccountSetHash()); | |||
// 系统时间集根哈希 | |||
System.out.println(block1.getSystemEventSetHash()); | |||
// 用户账户集根哈希 | |||
System.out.println(block1.getUserAccountSetHash()); | |||
// 用户事件账户根哈希 | |||
System.out.println(block1.getUserEventSetHash()); | |||
LedgerBlock block2 = blockchainService.getBlock(ledger, Integer.MAX_VALUE); | |||
Assert.assertNotNull(block1); | |||
Assert.assertEquals(block1.getHash(), block2.getHash()); | |||
LedgerBlock block3 = blockchainService.getBlock(ledger, 0); | |||
Assert.assertTrue(block1.getHeight() >= block3.getHeight()); | |||
} | |||
/** | |||
* 根据hash查询区块 | |||
*/ | |||
@Test | |||
public void getBlockByHash() { | |||
LedgerBlock block = blockchainService.getBlock(ledger, sampleHash); | |||
Assert.assertNull(block); | |||
} | |||
/** | |||
* 查询某一高度(包括)之前所有交易数 | |||
*/ | |||
@Test | |||
public void getTransactionCountByHeight() { | |||
long count = blockchainService.getTransactionCount(ledger, -1); | |||
Assert.assertEquals(0, count); | |||
count = blockchainService.getTransactionCount(ledger, 1); | |||
Assert.assertNotEquals(0, count); | |||
} | |||
/** | |||
* 查询某一区块(包括)之前所有交易数 | |||
*/ | |||
@Test | |||
public void getTransactionCountByHash() { | |||
long count = blockchainService.getTransactionCount(ledger, sampleHash); | |||
Assert.assertEquals(0, count); | |||
} | |||
/** | |||
* 查询交易总数 | |||
*/ | |||
@Test | |||
public void getTransactionTotalCount() { | |||
long count = blockchainService.getTransactionTotalCount(ledger); | |||
Assert.assertNotEquals(0, count); | |||
} | |||
/** | |||
* 查询某一高度(包括)之前数据账户数 | |||
*/ | |||
@Test | |||
public void getDataAccountCountByHeight() { | |||
long count = blockchainService.getDataAccountCount(ledger, 0); | |||
Assert.assertEquals(0, count); | |||
} | |||
/** | |||
* 查询某一区块(包括)之前数据账户数 | |||
*/ | |||
@Test | |||
public void getDataAccountCountByHash() { | |||
long count = blockchainService.getDataAccountCount(ledger, sampleHash); | |||
Assert.assertEquals(0, count); | |||
} | |||
/** | |||
* 查询数据账户总数 | |||
*/ | |||
@Test | |||
public void getDataAccountTotalCount() { | |||
long count = blockchainService.getDataAccountTotalCount(ledger); | |||
System.out.println("Total DataAccount count: " + count); | |||
} | |||
/** | |||
* 查询某一高度(包括)之前用户数 | |||
*/ | |||
@Test | |||
public void getUserCountByHeight() { | |||
long count = blockchainService.getUserCount(ledger, 0); | |||
Assert.assertEquals(4, count); | |||
} | |||
/** | |||
* 查询某一区块(包括)之前用户数 | |||
*/ | |||
@Test | |||
public void getUserCountByHash() { | |||
long count = blockchainService.getUserCount(ledger, sampleHash); | |||
Assert.assertEquals(0, count); | |||
} | |||
/** | |||
* 查询用户总数 | |||
*/ | |||
@Test | |||
public void getUserTotalCount() { | |||
long count = blockchainService.getUserTotalCount(ledger); | |||
System.out.println("Total User count: " + count); | |||
} | |||
/** | |||
* 查询某一高度(包括)之前合约数 | |||
*/ | |||
@Test | |||
public void getContractCountByHeight() { | |||
long count = blockchainService.getContractCount(ledger, 0); | |||
Assert.assertEquals(0, count); | |||
} | |||
/** | |||
* 查询某一区块(包括)之前合约数 | |||
*/ | |||
@Test | |||
public void getContractCountByHash() { | |||
long count = blockchainService.getContractCount(ledger, sampleHash); | |||
Assert.assertEquals(0, count); | |||
} | |||
/** | |||
* 查询合约总数 | |||
*/ | |||
@Test | |||
public void getContractTotalCount() { | |||
long count = blockchainService.getContractTotalCount(ledger); | |||
System.out.println("Total Contract count: " + count); | |||
} | |||
/** | |||
* 分页查询交易某一高度(包括)之前的所有交易 | |||
*/ | |||
@Test | |||
public void getTransactionsByHeight() { | |||
LedgerTransaction[] txs = blockchainService.getTransactions(ledger, 0, 0, 1); | |||
Assert.assertEquals(1, txs.length); | |||
} | |||
/** | |||
* 分页查询交易某一区块(包括)之前的所有交易 | |||
*/ | |||
@Test | |||
public void getTransactionsByHash() { | |||
LedgerTransaction[] txs = blockchainService.getTransactions(ledger, | |||
sampleHash, 0, 1); | |||
Assert.assertNull(txs); | |||
} | |||
/** | |||
* 分页查询某一高度中的交易 | |||
*/ | |||
@Test | |||
public void getAdditionalTransactionsByHeight() { | |||
LedgerTransaction[] txs = blockchainService.getAdditionalTransactions(ledger, 0, 0, 1); | |||
Assert.assertEquals(1, txs.length); | |||
for (LedgerTransaction tx : txs) { | |||
/** | |||
* 交易执行结果 | |||
*/ | |||
TransactionResult result = tx.getResult(); | |||
// 交易最终状态 | |||
System.out.println(result.getExecutionState()); | |||
// 交易所在区块高度 | |||
System.out.println(result.getBlockHeight()); | |||
/** | |||
* 交易请求解析 | |||
*/ | |||
TransactionRequest request = tx.getRequest(); | |||
// 交易哈希 | |||
System.out.println(request.getTransactionHash()); | |||
// 终端用户签名信息 | |||
DigitalSignature[] endpointSignatures = request.getEndpointSignatures(); | |||
for (DigitalSignature signature : endpointSignatures) { | |||
// 签名 | |||
System.out.println(signature.getDigest()); | |||
// 公钥 | |||
System.out.println(signature.getPubKey()); | |||
} | |||
// 网关签名信息 | |||
DigitalSignature[] nodeSignatures = request.getNodeSignatures(); | |||
for (DigitalSignature signature : nodeSignatures) { | |||
// 签名 | |||
System.out.println(signature.getDigest()); | |||
// 公钥 | |||
System.out.println(signature.getPubKey()); | |||
} | |||
// 请求内容 | |||
TransactionContent transactionContent = request.getTransactionContent(); | |||
transactionContent.getTimestamp(); // 请求时间(客户端提交上来的时间) | |||
Operation[] operations = transactionContent.getOperations(); // 操作列表 | |||
for (Operation operation : operations) { | |||
if (operation instanceof UserRegisterOperation) { // 注册用户 | |||
UserRegisterOperation userRegisterOperation = (UserRegisterOperation) operation; | |||
// 地址 | |||
System.out.println(userRegisterOperation.getUserID().getAddress()); | |||
//公钥 | |||
System.out.println(userRegisterOperation.getUserID().getPubKey()); | |||
} else if (operation instanceof DataAccountRegisterOperation) { // 注册数据账户 | |||
DataAccountRegisterOperation dataAccountRegisterOperation = (DataAccountRegisterOperation) operation; | |||
// 地址 | |||
System.out.println(dataAccountRegisterOperation.getAccountID().getAddress()); | |||
// 公钥 | |||
System.out.println(dataAccountRegisterOperation.getAccountID().getPubKey()); | |||
} else if (operation instanceof ContractCodeDeployOperation) { // 部署合约 | |||
ContractCodeDeployOperation contractCodeDeployOperation = (ContractCodeDeployOperation) operation; | |||
// 地址 | |||
System.out.println(contractCodeDeployOperation.getContractID().getAddress()); | |||
// 公钥 | |||
System.out.println(contractCodeDeployOperation.getContractID().getPubKey()); | |||
// 合约代码 | |||
System.out.println(OnLineContractProcessor.getInstance().decompileEntranceClass(contractCodeDeployOperation.getChainCode())); | |||
// 合约版本 | |||
System.out.println(contractCodeDeployOperation.getChainCodeVersion()); | |||
} else if (operation instanceof EventAccountRegisterOperation) { // 注册事件账户 | |||
EventAccountRegisterOperation eventAccountRegisterOperation = (EventAccountRegisterOperation) operation; | |||
// 地址 | |||
System.out.println(eventAccountRegisterOperation.getEventAccountID().getAddress()); | |||
// 公钥 | |||
System.out.println(eventAccountRegisterOperation.getEventAccountID().getPubKey()); | |||
} else if (operation instanceof DataAccountKVSetOperation) { // 写入kv | |||
DataAccountKVSetOperation kvSetOperation = (DataAccountKVSetOperation) operation; | |||
// 数据账户地址 | |||
System.out.println(kvSetOperation.getAccountAddress()); | |||
// 写入kv数据 | |||
DataAccountKVSetOperation.KVWriteEntry[] kvs = kvSetOperation.getWriteSet(); | |||
for (DataAccountKVSetOperation.KVWriteEntry kv : kvs) { | |||
// key | |||
System.out.println(kv.getKey()); | |||
// 预期的上一个数据版本 | |||
System.out.println(kv.getExpectedVersion()); | |||
// value | |||
BytesValue value = kv.getValue(); | |||
switch (value.getType()) { | |||
case TEXT: | |||
case XML: | |||
case JSON: | |||
System.out.println(value.getBytes().toString()); | |||
break; | |||
case INT64: | |||
case TIMESTAMP: | |||
System.out.println(BytesUtils.toLong(value.getBytes().toBytes())); | |||
break; | |||
default: // byte[], Bytes, IMG | |||
System.out.println(value.getBytes()); | |||
break; | |||
} | |||
} | |||
} else if (operation instanceof ContractEventSendOperation) { // 调用合约 | |||
ContractEventSendOperation contractEventSendOperation = (ContractEventSendOperation) operation; | |||
// 合约地址 | |||
System.out.println(contractEventSendOperation.getContractAddress()); | |||
// 合约方法 | |||
System.out.println(contractEventSendOperation.getEvent()); | |||
// 合约参数 | |||
for (BytesValue arg : contractEventSendOperation.getArgs().getValues()) { | |||
switch (arg.getType()) { | |||
case TEXT: | |||
System.out.println(BytesUtils.toString(arg.getBytes().toBytes())); | |||
break; | |||
case INT64: | |||
System.out.println(BytesUtils.toLong(arg.getBytes().toBytes())); | |||
break; | |||
case BOOLEAN: | |||
System.out.println(BytesUtils.toBoolean(arg.getBytes().toBytes()[0])); | |||
break; | |||
case BYTES: | |||
System.out.println(arg.getBytes().toBytes()); | |||
default: | |||
break; | |||
} | |||
} | |||
} else if (operation instanceof EventPublishOperation) { // 发布事件 | |||
EventPublishOperation eventPublishOperation = (EventPublishOperation) operation; | |||
// 事件账户地址 | |||
System.out.println(eventPublishOperation.getEventAddress()); | |||
// 数据 | |||
EventPublishOperation.EventEntry[] events = eventPublishOperation.getEvents(); | |||
for (EventPublishOperation.EventEntry event : events) { | |||
// topic | |||
System.out.println(event.getName()); | |||
// 预期的上一个数据序列 | |||
System.out.println(event.getSequence()); | |||
// 内容 | |||
BytesValue value = event.getContent(); | |||
switch (value.getType()) { | |||
case TEXT: | |||
case XML: | |||
case JSON: | |||
System.out.println(value.getBytes().toString()); | |||
break; | |||
case INT64: | |||
case TIMESTAMP: | |||
System.out.println(BytesUtils.toLong(value.getBytes().toBytes())); | |||
break; | |||
default: // byte[], Bytes, IMG | |||
System.out.println(value.getBytes()); | |||
break; | |||
} | |||
} | |||
} else if (operation instanceof ConsensusSettingsUpdateOperation) { // 更新共识信息 | |||
ConsensusSettingsUpdateOperation consensusSettingsUpdateOperation = (ConsensusSettingsUpdateOperation) operation; | |||
Property[] properties = consensusSettingsUpdateOperation.getProperties(); | |||
for (Property property : properties) { | |||
System.out.println(property.getName()); | |||
System.out.println(property.getValue()); | |||
} | |||
} else if (operation instanceof LedgerInitOperation) { // 账本初始化 | |||
LedgerInitOperation ledgerInitOperation = (LedgerInitOperation) operation; | |||
// 共识参与方的列表 | |||
ledgerInitOperation.getInitSetting().getConsensusParticipants(); | |||
// 密码算法配置 | |||
ledgerInitOperation.getInitSetting().getCryptoSetting(); | |||
// 账本的种子 | |||
ledgerInitOperation.getInitSetting().getLedgerSeed(); | |||
// ... | |||
} else if (operation instanceof ParticipantRegisterOperation) { // 注册参与方 | |||
ParticipantRegisterOperation participantRegisterOperation = (ParticipantRegisterOperation) operation; | |||
// 参与方地址 | |||
System.out.println(participantRegisterOperation.getParticipantID().getAddress()); | |||
// 参与方公钥 | |||
System.out.println(participantRegisterOperation.getParticipantID().getPubKey()); | |||
// 参与方名称 | |||
System.out.println(participantRegisterOperation.getParticipantName()); | |||
} else if (operation instanceof RolesConfigureOperation) { // 角色配置 | |||
RolesConfigureOperation rolesConfigureOperation = (RolesConfigureOperation) operation; | |||
// 角色列表 | |||
RolesConfigureOperation.RolePrivilegeEntry[] roles = rolesConfigureOperation.getRoles(); | |||
for (RolesConfigureOperation.RolePrivilegeEntry role : roles) { | |||
// 角色名称 | |||
System.out.println(role.getRoleName()); | |||
// 拥有的账本权限 | |||
System.out.println(Arrays.toString(role.getEnableLedgerPermissions())); | |||
// 禁止的账本权限 | |||
System.out.println(Arrays.toString(role.getDisableLedgerPermissions())); | |||
// 拥有的交易权限 | |||
System.out.println(Arrays.toString(role.getEnableTransactionPermissions())); | |||
// 禁止的交易权限 | |||
System.out.println(Arrays.toString(role.getDisableTransactionPermissions())); | |||
} | |||
} else if (operation instanceof UserAuthorizeOperation) { // 权限配置 | |||
UserAuthorizeOperation userAuthorizeOperation = (UserAuthorizeOperation) operation; | |||
// 用户角色 | |||
UserAuthorizeOperation.UserRolesEntry[] userRoles = userAuthorizeOperation.getUserRolesAuthorizations(); | |||
for (UserAuthorizeOperation.UserRolesEntry userRole : userRoles) { | |||
// 用户地址 | |||
System.out.println(Arrays.toString(userRole.getUserAddresses())); | |||
// 多角色权限策略 | |||
System.out.println(userRole.getPolicy()); | |||
// 授权的角色清单 | |||
System.out.println(Arrays.toString(userRole.getAuthorizedRoles())); | |||
// 取消授权的角色清单 | |||
System.out.println(Arrays.toString(userRole.getUnauthorizedRoles())); | |||
} | |||
} else { | |||
System.out.println("todo"); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* 分页查询某一区块中的交易 | |||
*/ | |||
@Test | |||
public void getAdditionalTransactionsByHash() { | |||
LedgerTransaction[] txs = blockchainService.getAdditionalTransactions(ledger, sampleHash, 0, 1); | |||
Assert.assertNull(txs); | |||
} | |||
/** | |||
* 根据交易hash查询交易详情 | |||
*/ | |||
@Test | |||
public void getTransactionByContentHash() { | |||
LedgerTransaction tx = blockchainService.getTransactionByContentHash(ledger, sampleHash); | |||
Assert.assertNull(tx); | |||
} | |||
/** | |||
* 根据交易hash查询交易状态 | |||
*/ | |||
@Test | |||
public void getTransactionStateByContentHash() { | |||
TransactionState state = blockchainService.getTransactionStateByContentHash(ledger, sampleHash); | |||
Assert.assertNull(state); | |||
} | |||
/** | |||
* 根据地址查询用户信息 | |||
*/ | |||
@Test | |||
public void getUser() { | |||
UserInfo user = blockchainService.getUser(ledger, sampleUserAddress); | |||
if (null != user) { | |||
System.out.println(user.getAddress().toString()); | |||
} | |||
} | |||
/** | |||
* 根据地址查询数据账户 | |||
*/ | |||
@Test | |||
public void getDataAccount() { | |||
DataAccountInfo dataAccount = blockchainService.getDataAccount(ledger, sampleDataAccountAddress); | |||
if (null != dataAccount) { | |||
System.out.println(dataAccount.getAddress().toString()); | |||
} | |||
} | |||
/** | |||
* 根据地址和键查询KV信息(只包含最高数据版本) | |||
*/ | |||
@Test | |||
public void getDataEntriesByKey() { | |||
TypedKVEntry[] kvs = blockchainService.getDataEntries(ledger, sampleDataAccountAddress, sampleKey); | |||
for (TypedKVEntry kv : kvs) { | |||
System.out.println(kv.getKey() + ":" + kv.getVersion() + ":" + kv.getValue()); | |||
} | |||
} | |||
/** | |||
* 根据地址和指定键及数据版本查询KV信息 | |||
*/ | |||
@Test | |||
public void getDataEntriesWithKeyAndVersion() { | |||
TypedKVEntry[] kvs = blockchainService.getDataEntries(ledger, sampleDataAccountAddress, new KVInfoVO(new KVDataVO[]{new KVDataVO(sampleKey, new long[]{0})})); | |||
for (TypedKVEntry kv : kvs) { | |||
System.out.println(kv.getKey() + ":" + kv.getVersion() + ":" + kv.getValue()); | |||
} | |||
} | |||
/** | |||
* 查询数据账户KV总数 | |||
*/ | |||
@Test | |||
public void getDataEntriesTotalCount() { | |||
long count = blockchainService.getDataEntriesTotalCount(ledger, sampleDataAccountAddress); | |||
System.out.println(count); | |||
} | |||
/** | |||
* 分页查询指定数据账户KV数据 | |||
*/ | |||
@Test | |||
public void getDataEntries() { | |||
TypedKVEntry[] kvs = blockchainService.getDataEntries(ledger, sampleDataAccountAddress, 0, 1); | |||
for (TypedKVEntry kv : kvs) { | |||
System.out.println(kv.getKey() + ":" + kv.getVersion() + ":" + kv.getValue()); | |||
} | |||
} | |||
/** | |||
* 查询合约信息 | |||
*/ | |||
@Test | |||
public void getContract() { | |||
ContractInfo contract = blockchainService.getContract(ledger, sampleContractAddress); | |||
if (null != contract) { | |||
// 合约地址 | |||
System.out.println(contract.getAddress()); | |||
// 合约代码 | |||
System.out.println(BytesUtils.toString(contract.getChainCode())); | |||
System.out.println(OnLineContractProcessor.getInstance().decompileEntranceClass(contract.getChainCode())); | |||
} | |||
} | |||
/** | |||
* 分页查询指定系统事件名下所有消息 | |||
*/ | |||
@Test | |||
public void getSystemEvents() { | |||
Event[] events = blockchainService.getSystemEvents(ledger, sampleEvent, 0, 1); | |||
Assert.assertTrue(null == events || events.length == 0); | |||
} | |||
/** | |||
* 查询系统事件名总数 | |||
*/ | |||
@Test | |||
public void getSystemEventNameTotalCount() { | |||
long count = blockchainService.getSystemEventNameTotalCount(ledger); | |||
Assert.assertEquals(0, count); | |||
} | |||
/** | |||
* 分页查询系统事件名 | |||
*/ | |||
@Test | |||
public void getSystemEventNames() { | |||
String[] names = blockchainService.getSystemEventNames(ledger, 0, 1); | |||
Assert.assertEquals(0, names.length); | |||
} | |||
/** | |||
* 查询指定系统事件名最新事件 | |||
*/ | |||
@Test | |||
public void getLatestEvent() { | |||
Event event = blockchainService.getLatestSystemEvent(ledger, sampleEvent); | |||
Assert.assertNull(event); | |||
} | |||
/** | |||
* 获取指定系统事件名下所有事件 | |||
*/ | |||
@Test | |||
public void getSystemEventsTotalCount() { | |||
long count = blockchainService.getSystemEventsTotalCount(ledger, sampleEvent); | |||
Assert.assertEquals(0, count); | |||
} | |||
/** | |||
* 分页查询用户事件账户 | |||
* | |||
* @return | |||
*/ | |||
@Test | |||
public void getUserEventAccounts() { | |||
BlockchainIdentity[] ids = blockchainService.getUserEventAccounts(ledger, 0, 1); | |||
System.out.println(ids.length); | |||
} | |||
/** | |||
* 获取用户事件账户 | |||
*/ | |||
@Test | |||
public void getUserEventAccount() { | |||
BlockchainIdentity id = blockchainService.getUserEventAccount(ledger, sampleEventAddress); | |||
if (null != id) { | |||
System.out.println(id.getAddress().toString()); | |||
} | |||
} | |||
/** | |||
* 获取用户事件账户总数 | |||
*/ | |||
@Test | |||
public void getUserEventAccountTotalCount() { | |||
long count = blockchainService.getUserEventAccountTotalCount(ledger); | |||
System.out.println(count); | |||
} | |||
/** | |||
* 获取指定用户事件账户下事件名数 | |||
*/ | |||
@Test | |||
public void getUserEventNameTotalCount() { | |||
long count = blockchainService.getUserEventNameTotalCount(ledger, sampleEventAddress); | |||
System.out.println(count); | |||
} | |||
/** | |||
* 分页查询指定用户事件账户下事件名 | |||
*/ | |||
@Test | |||
public void getUserEventNames() { | |||
String[] names = blockchainService.getUserEventNames(ledger, sampleEventAddress, 0, 1); | |||
for (String name : names) { | |||
System.out.println(name); | |||
} | |||
} | |||
/** | |||
* 获取指定用户事件账户指定事件名下最新事件 | |||
*/ | |||
@Test | |||
public void getLatestUserEvent() { | |||
Event event = blockchainService.getLatestUserEvent(ledger, sampleEventAddress, sampleEvent); | |||
if (null != event) { | |||
BytesValue content = event.getContent(); | |||
switch (content.getType()) { | |||
case TEXT: | |||
case XML: | |||
case JSON: | |||
System.out.println(event.getName() + ":" + event.getSequence() + ":" + content.getBytes().toUTF8String()); | |||
break; | |||
case INT64: | |||
case TIMESTAMP: | |||
System.out.println(event.getName() + ":" + event.getSequence() + ":" + BytesUtils.toLong(content.getBytes().toBytes())); | |||
break; | |||
default: // byte[], Bytes | |||
System.out.println(event.getName() + ":" + event.getSequence() + ":" + content.getBytes().toBase58()); | |||
break; | |||
} | |||
} | |||
} | |||
/** | |||
* 获取指定用户事件账户指定事件名下事件总数 | |||
*/ | |||
@Test | |||
public void getUserEventsTotalCount() { | |||
long count = blockchainService.getUserEventsTotalCount(ledger, sampleEventAddress, sampleEvent); | |||
System.out.println(count); | |||
} | |||
/** | |||
* 分页查询指定用户事件账户指定事件名下事件 | |||
*/ | |||
@Test | |||
public void getUserEvents() { | |||
Event[] events = blockchainService.getUserEvents(ledger, sampleEventAddress, sampleEvent, 0, 1); | |||
for (Event event : events) { | |||
BytesValue content = event.getContent(); | |||
switch (content.getType()) { | |||
case TEXT: | |||
case XML: | |||
case JSON: | |||
System.out.println(event.getName() + ":" + event.getSequence() + ":" + content.getBytes().toUTF8String()); | |||
break; | |||
case INT64: | |||
case TIMESTAMP: | |||
System.out.println(event.getName() + ":" + event.getSequence() + ":" + BytesUtils.toLong(content.getBytes().toBytes())); | |||
break; | |||
default: // byte[], Bytes | |||
System.out.println(event.getName() + ":" + event.getSequence() + ":" + content.getBytes().toBase58()); | |||
break; | |||
} | |||
} | |||
} | |||
/** | |||
* 获取指定版本合约 | |||
*/ | |||
@Test | |||
public void getContractByAddressAndVersion() { | |||
ContractInfo contract = blockchainService.getContract(ledger, sampleContractAddress, sampleVersion); | |||
if (null != contract) { | |||
System.out.println(contract.getAddress().toString()); | |||
System.out.println(contract.getChainCodeVersion()); | |||
System.out.println(OnLineContractProcessor.getInstance().decompileEntranceClass(contract.getChainCode())); | |||
} | |||
} | |||
/** | |||
* 分页查询用户 | |||
*/ | |||
@Test | |||
public void getUsers() { | |||
BlockchainIdentity[] ids = blockchainService.getUsers(ledger, 0, 1); | |||
Assert.assertEquals(1, ids.length); | |||
} | |||
/** | |||
* 分页查询数据账户 | |||
*/ | |||
@Test | |||
public void getDataAccounts() { | |||
BlockchainIdentity[] ids = blockchainService.getDataAccounts(ledger, 0, 1); | |||
System.out.println(ids.length); | |||
} | |||
/** | |||
* 分页查询合约账户 | |||
*/ | |||
@Test | |||
public void getContractAccounts() { | |||
BlockchainIdentity[] ids = blockchainService.getContractAccounts(ledger, 0, 1); | |||
System.out.println(ids.length); | |||
} | |||
/** | |||
* 查询指定角色权限信息 | |||
*/ | |||
@Test | |||
public void getRolePrivileges() { | |||
PrivilegeSet privilegeSet = blockchainService.getRolePrivileges(ledger, sampleRoleName); | |||
if (null != privilegeSet) { | |||
for (LedgerPermission ledgerpermission : privilegeSet.getLedgerPrivilege().getPrivilege()) { | |||
System.out.println(ledgerpermission); | |||
} | |||
for (TransactionPermission transactionPermission : privilegeSet.getTransactionPrivilege().getPrivilege()) { | |||
System.out.println(transactionPermission); | |||
} | |||
} | |||
} | |||
/** | |||
* 查询指定用户权限信息 | |||
*/ | |||
@Test | |||
public void getUserPrivileges() { | |||
UserPrivilegeSet userPrivileges = blockchainService.getUserPrivileges(ledger, sampleUserAddress); | |||
if (null != userPrivileges) { | |||
for (String role : userPrivileges.getUserRole()) { | |||
System.out.println(role); | |||
} | |||
for (LedgerPermission ledgerpermission : userPrivileges.getLedgerPrivilegesBitset().getPrivilege()) { | |||
System.out.println(ledgerpermission); | |||
} | |||
for (TransactionPermission transactionPermission : userPrivileges.getTransactionPrivilegesBitset().getPrivilege()) { | |||
System.out.println(transactionPermission); | |||
} | |||
} | |||
} | |||
} |
@@ -1,63 +0,0 @@ | |||
package com.jdchain.samples.sdk; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.sdk.BlockchainService; | |||
import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||
import utils.codec.Base58Utils; | |||
import java.util.Properties; | |||
public class SampleBase { | |||
// 交易签名用户 | |||
protected static BlockchainKeypair userKey; | |||
// 网关IP | |||
protected static String gatewayHost; | |||
// 网关端口 | |||
protected static int gatewayPort; | |||
// 账本Hash | |||
protected static HashDigest ledger; | |||
// 区块链服务 | |||
protected static BlockchainService blockchainService; | |||
static { | |||
try { | |||
// 读取配置文件 | |||
Properties properties = new Properties(); | |||
properties.load(SampleBase.class.getClassLoader().getResourceAsStream("config.properties")); | |||
// 初始配置交易签名用户信息 | |||
PubKey pubKey = KeyGenUtils.decodePubKey(properties.getProperty("pubkey")); | |||
PrivKey privKey = KeyGenUtils.decodePrivKey(properties.getProperty("privkey"), properties.getProperty("password")); | |||
userKey = new BlockchainKeypair(pubKey, privKey); | |||
// 读取网关配置 | |||
gatewayHost = properties.getProperty("gateway.host"); | |||
gatewayPort = Integer.parseInt(properties.getProperty("gateway.port")); | |||
// 读取账本配置 | |||
String ledgerHash = properties.getProperty("ledger"); | |||
// 初始化区块链服务 | |||
// 此处传入 签名账户 会在提交交易前自动加上此用户的签名信息 | |||
// 此处不传入 签名账户 的话需要提交交易前手动调用签名操作,需要至少加入一个终端用户签名 | |||
blockchainService = GatewayServiceFactory.connect(gatewayHost, gatewayPort, false, userKey).getBlockchainService(); | |||
// 初始配置账本,从配置文件中读取,未设置获取账本列表第一个 | |||
if (!ledgerHash.isEmpty()) { | |||
ledger = Crypto.resolveAsHashDigest(Base58Utils.decode(ledgerHash)); | |||
} else { | |||
ledger = blockchainService.getLedgerHashs()[0]; | |||
} | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} |
@@ -1,120 +0,0 @@ | |||
package com.jdchain.samples.sdk; | |||
import com.jd.blockchain.ledger.AccountState; | |||
import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import utils.Bytes; | |||
/** | |||
* 用户账户相关操作示例: | |||
* 用户注册,角色创建,权限设置 | |||
*/ | |||
public class UserSample extends SampleBase { | |||
/** | |||
* 注册用户 | |||
*/ | |||
@Test | |||
public void registerUser() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 生成用户 | |||
BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); | |||
System.out.println("用户地址:" + user.getAddress()); | |||
// 注册用户 | |||
txTemp.users().register(user.getIdentity()); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 创建角色 | |||
*/ | |||
@Test | |||
public void createRole() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 创建角色 MANAGER ,并设置可以写数据账户,能执行交易 | |||
txTemp.security().roles().configure("MANAGER") | |||
.enable(LedgerPermission.WRITE_DATA_ACCOUNT) | |||
.enable(TransactionPermission.DIRECT_OPERATION); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 配置角色权限 | |||
*/ | |||
@Test | |||
public void configUserRole() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 给用户设置 MANAGER 角色权限 | |||
txTemp.security().authorziations().forUser(Bytes.fromBase58("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye")).authorize("MANAGER"); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 注册用户的同时配置角色权限,同一事务内 | |||
*/ | |||
@Test | |||
public void testRegisterUserAndConfigRole() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 生成用户 | |||
BlockchainKeypair user = BlockchainKeyGenerator.getInstance().generate(); | |||
System.out.println("用户地址:" + user.getAddress()); | |||
// 注册用户 | |||
txTemp.users().register(user.getIdentity()); | |||
// 创建角色 MANAGER | |||
txTemp.security().roles().configure("MANAGER") | |||
.enable(LedgerPermission.WRITE_DATA_ACCOUNT) | |||
.enable(TransactionPermission.DIRECT_OPERATION); | |||
// 设置用户角色权限 | |||
txTemp.security().authorziations().forUser(user.getAddress()).authorize("MANAGER"); | |||
// 交易主恩贝 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
/** | |||
* 更新用户状态 | |||
*/ | |||
@Test | |||
public void updateUserState() { | |||
// 新建交易 | |||
TransactionTemplate txTemp = blockchainService.newTransaction(ledger); | |||
// 用户(证书)状态分为:NORMAL(正常) FREEZE(冻结) REVOKE(销毁) | |||
// 冻结用户(证书) | |||
txTemp.user("LdeNr7H1CUbqe3kWjwPwiqHcmd86zEQz2VRye").state(AccountState.FREEZE); | |||
// 交易准备 | |||
PreparedTransaction ptx = txTemp.prepare(); | |||
// 提交交易 | |||
TransactionResponse response = ptx.commit(); | |||
Assert.assertTrue(response.isSuccess()); | |||
} | |||
} |