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