@@ -15,7 +15,6 @@ | |||||
<module>core</module> | <module>core</module> | ||||
<module>deploy</module> | <module>deploy</module> | ||||
<module>test</module> | <module>test</module> | ||||
<module>samples</module> | |||||
</modules> | </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()); | |||||
} | |||||
} |