文章目錄
- 一、前言
- 二、業務場景分析:簡易資產管理系統
- 三、智能合約設計與實現
- 3.1 存儲結構設計
- 3.2 接口設計
- 3.3 完整合約代碼
- 四、合約編譯與Java接口生成
- 五、SDK配置與項目搭建
- 5.1 獲取Java工程項目
- 5.2 項目目錄結構
- 5.3 引入Web3SDK
- 5.4 證書與配置文件
- 六、業務開發:Java客戶端實現
- 6.1 核心類設計:AssetClient
- 6.1.1 初始化
- 6.1.2 合約對象創建
- 6.1.3 接口調用
- 七、項目運行與功能驗證
- 7.1 編譯項目
- 7.2 部署合約
- 7.3 注冊資產
- 7.4 查詢資產
- 7.5 資產轉移
- 八、參考資料
一、前言
在區塊鏈技術快速發展的今天,如何將其應用于實際業務場景成為開發者關注的重點。FISCO BCOS作為國產優秀的聯盟鏈平臺,為企業級區塊鏈應用開發提供了強大支持。本文將跟隨官方教程,詳細記錄基于FISCO BCOS構建第一個區塊鏈應用的全過程,涵蓋從業務分析到最終實現的完整流程。
二、業務場景分析:簡易資產管理系統
區塊鏈技術因其防篡改、可追溯的特性,在金融領域有著天然優勢。本次實踐選擇開發一個簡易的資產管理系統,主要實現以下核心功能:
- 資產注冊:在區塊鏈上登記資產賬戶及初始金額
- 資產轉賬:實現不同賬戶間的資產轉移
- 資產查詢:查詢指定賬戶的資產余額
這個場景雖然簡單,但涵蓋了區塊鏈應用開發的核心流程,非常適合作為入門案例。
三、智能合約設計與實現
3.1 存儲結構設計
FISCO BCOS提供了合約CRUD接口開發模式,允許通過合約創建表結構并進行數據操作。針對資產管理需求,設計了名為t_asset
的表:
account
:資產賬戶,作為主鍵(string類型)asset_value
:資產金額(uint256類型)
該表結構示例如下:
account | asset_value |
---|---|
Alice | 10000 |
Bob | 20000 |
3.2 接口設計
根據業務目標,定義了三個核心接口:
select(string account)
:查詢資產金額register(string account, uint256 amount)
:資產注冊transfer(string from_asset_account, string to_asset_account, uint256 amount)
:資產轉移
3.3 完整合約代碼
pragma solidity ^0.4.24;
import "./Table.sol";contract Asset {// 事件定義,用于記錄關鍵操作event RegisterEvent(int256 ret, string account, uint256 asset_value);event TransferEvent(int256 ret, string from_account, string to_account, uint256 amount);constructor() public {// 構造函數中創建表createTable();}function createTable() private {TableFactory tf = TableFactory(0x1001);// 創建t_asset表,指定主鍵和字段tf.createTable("t_asset", "account", "asset_value");}function openTable() private returns (Table) {TableFactory tf = TableFactory(0x1001);Table table = tf.openTable("t_asset");return table;}// 查詢資產金額function select(string account) public constant returns (int256, uint256) {Table table = openTable();Entries entries = table.select(account, table.newCondition());uint256 asset_value = 0;if (0 == uint256(entries.size())) {return (-1, asset_value);} else {Entry entry = entries.get(0);return (0, uint256(entry.getInt("asset_value")));}}// 資產注冊function register(string account, uint256 asset_value) public returns (int256) {int256 ret_code = 0;int256 ret = 0;uint256 temp_asset_value = 0;(ret, temp_asset_value) = select(account);if (ret != 0) {Table table = openTable();Entry entry = table.newEntry();entry.set("account", account);entry.set("asset_value", int256(asset_value));int count = table.insert(account, entry);if (count == 1) {ret_code = 0;} else {ret_code = -2;}} else {ret_code = -1;}emit RegisterEvent(ret_code, account, asset_value);return ret_code;}// 資產轉移function transfer(string from_account, string to_account, uint256 amount) public returns (int256) {int ret_code = 0;int256 ret = 0;uint256 from_asset_value = 0;uint256 to_asset_value = 0;// 檢查轉出賬戶是否存在(ret, from_asset_value) = select(from_account);if (ret != 0) {ret_code = -1;emit TransferEvent(ret_code, from_account, to_account, amount);return ret_code;}// 檢查轉入賬戶是否存在(ret, to_asset_value) = select(to_account);if (ret != 0) {ret_code = -2;emit TransferEvent(ret_code, from_account, to_account, amount);return ret_code;}// 檢查余額是否充足if (from_asset_value < amount) {ret_code = -3;emit TransferEvent(ret_code, from_account, to_account, amount);return ret_code;}// 檢查金額是否溢出if (to_asset_value + amount < to_asset_value) {ret_code = -4;emit TransferEvent(ret_code, from_account, to_account, amount);return ret_code;}Table table = openTable();Entry entry0 = table.newEntry();entry0.set("account", from_account);entry0.set("asset_value", int256(from_asset_value - amount));int count = table.update(from_account, entry0, table.newCondition());if (count != 1) {ret_code = -5;emit TransferEvent(ret_code, from_account, to_account, amount);return ret_code;}Entry entry1 = table.newEntry();entry1.set("account", to_account);entry1.set("asset_value", int256(to_asset_value + amount));table.update(to_account, entry1, table.newCondition());emit TransferEvent(ret_code, from_account, to_account, amount);return ret_code;}
}
注意:該合約依賴FISCO BCOS提供的系統合約
Table.sol
,實現對表的CRUD操作
四、合約編譯與Java接口生成
Solidity合約無法被Java程序直接調用,需要通過控制臺工具將其編譯為Java類。具體步驟如下:
- 將
Asset.sol
和Table.sol
放在console/contracts/solidity
目錄 - 執行編譯腳本:
# 切換到console目錄
cd ~/fisco/console/
# 編譯合約,指定Java包名
./sol2java.sh org.fisco.bcos.asset.contract
編譯成功后會在console/contracts/sdk
目錄生成:
abi
目錄:存放合約ABI文件bin
目錄:存放合約字節碼文件java
目錄:存放生成的Java合約類
生成的Asset.java
包含了與Solidity合約對應的Java接口:
package org.fisco.bcos.asset.contract;
public class Asset extends Contract {// 轉賬接口public RemoteCall<TransactionReceipt> transfer(String from_account, String to_account, BigInteger amount);// 注冊接口public RemoteCall<TransactionReceipt> register(String account, BigInteger asset_value);// 查詢接口public RemoteCall<Tuple2<BigInteger, BigInteger>> select(String account);// 加載合約public static Asset load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider);// 部署合約public static RemoteCall<Asset> deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider);
}
五、SDK配置與項目搭建
5.1 獲取Java工程項目
# 下載項目壓縮包
cd ~
curl -LO https://github.com/FISCO-BCOS/LargeFiles/raw/master/tools/asset-app.tar.gz
# 解壓項目
tar -zxf asset-app.tar.gz
5.2 項目目錄結構
asset-app/
├── build.gradle # Gradle配置文件
├── gradle/
│ ├── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew # Linux執行腳本
├── gradlew.bat # Windows執行腳本
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── fisco/
│ │ │ └── bcos/
│ │ │ └── asset/
│ │ │ ├── client/ # 客戶端調用類
│ │ │ │ └── AssetClient.java
│ │ │ └── contract/ # 合約Java類
│ │ │ └── Asset.java
│ │ └── resources/
│ │ ├── applicationContext.xml # 項目配置文件
│ │ ├── contract.properties # 合約地址配置
│ │ ├── log4j.properties # 日志配置
│ │ └── contract/
│ │ ├── Asset.sol # Solidity合約
│ │ └── Table.sol
├── tool/
│ └── asset_run.sh # 運行腳本
5.3 引入Web3SDK
項目已在build.gradle
中配置好Web3SDK依賴:
repositories {maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }maven { url "https://dl.bintray.com/ethereum/maven/" }mavenCentral ()
}dependencies {compile('org.fisco-bcos:web3sdk:2.1.0')
}
5.4 證書與配置文件
拷貝區塊鏈節點的SDK證書到項目資源目錄:
cp fisco/nodes/127.0.0.1/sdk/* asset-app/src/test/resources/
六、業務開發:Java客戶端實現
6.1 核心類設計:AssetClient
AssetClient.java
是業務邏輯的核心,負責合約的部署與調用,主要包含以下功能模塊:
6.1.1 初始化
// 初始化Web3j和Credentials對象
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Service service = context.getBean(Service.class);
service.run();ChannelEthereumService channelEthereumService = new ChannelEthereumService();
channelEthereumService.setChannelService(service);
Web3j web3j = Web3j.build(channelEthereumService, 1);Credentials credentials = Credentials.create(Keys.createEcKeyPair());
6.1.2 合約對象創建
// 部署合約
Asset asset = Asset.deploy(web3j, credentials, new StaticGasProvider(gasPrice, gasLimit)).send();// 加載已部署合約
Asset asset = Asset.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));
6.1.3 接口調用
// 查詢資產
Tuple2<BigInteger, BigInteger> result = asset.select(assetAccount).send();// 注冊資產
TransactionReceipt registerReceipt = asset.register(assetAccount, amount).send();// 資產轉賬
TransactionReceipt transferReceipt = asset.transfer(fromAccount, toAccount, amount).send();
七、項目運行與功能驗證
7.1 編譯項目
# 切換到項目目錄
cd ~/asset-app
# 編譯項目
./gradlew build
編譯成功后在dist
目錄生成運行腳本。
7.2 部署合約
cd dist
bash asset_run.sh deploy
# 輸出示例:Deploy Asset successfully, contract address is 0xd09ad04220e40bb8666e885730c8c460091a4775
7.3 注冊資產
bash asset_run.sh register Alice 100000
# 輸出:Register account successfully => account: Alice, value: 100000bash asset_run.sh register Bob 100000
# 輸出:Register account successfully => account: Bob, value: 100000
7.4 查詢資產
bash asset_run.sh query Alice
# 輸出:account Alice, value 100000bash asset_run.sh query Bob
# 輸出:account Bob, value 100000
7.5 資產轉移
bash asset_run.sh transfer Alice Bob 50000
# 輸出:Transfer successfully => from_account: Alice, to_account: Bob, amount: 50000bash asset_run.sh query Alice
# 輸出:account Alice, value 50000bash asset_run.sh query Bob
# 輸出:account Bob, value 150000
八、參考資料
- FISCO BCOS文檔:https://www.bookstack.cn/read/fisco-bcos-2.4-zh