基礎底層搭建
-
目標
本章的目標是用兩個服務器,實現羣組1的搭建,每個服務器各有兩個節點。
首先準備兩臺測試服務器: -
提示
對服務器裏的內容進行目錄化的管理,可以使用WinSCP軟件,並且本章中所有的命令行都是基於Ubuntu系統的。
下載安裝
下載和安裝在服務器A和服務器B都需要進行相同的操作。
- 下載
cd ~/ && git clone https://github.com/FISCO-BCOS/generator.git
- 安裝
此操作要求用戶具有sudo權限。
cd ~/generator && bash ./scripts/install.sh
檢查是否安裝成功,若成功,會輸出 usage: generator xxx
./generator -h
- 獲取節點二進制
拉取最新fisco-bcos二進制文件到meta中
./generator --download_fisco ./meta
- 檢查二進制版本
若成功,輸出 FISCO-BCOS Version : x.x.x-x
./meta/fisco-bcos -v
初始化鏈證書
初始化鏈證書一個羣組裏只能在一個服務器上進行,這裏採用的是在服務器A進行初始化鏈證書
cd ~/generator
./generator --generate_chain_certificate ./dir_chain_ca
初始化機構A
在服務器A上進行初始化:
./generator --generate_agency_certificate ./dir_agency_ca ./dir_chain_ca agencyA
執行之後,會在 generator/dir_agency_ca/agencyA/目錄中生成機鑰證書和私鑰:
將 generator/dir_agency_ca/agencyA/目錄中的鏈證書、機構證書、機構私鑰複製到 generator/meta/文件中
cp ./dir_agency_ca/agencyA/* ~/generator/meta/
複製後:
複製初始化鏈證書
因爲只有服務器A生成了初始化鏈證書,這裏需要手動複製服務器A上 generator/ 目錄中的 dir_chain_ca,將A中的dir_chain_ca 複製到服務器B上的 generato/目錄下。
初始化機構B
在服務器A上進行初始化:
./generator --generate_agency_certificate ./dir_agency_ca ./dir_chain_ca agencyB
執行之後,會在 generator/dir_agency_ca/agencyB/目錄中生成機鑰證書和私鑰。
將 generator/dir_agency_ca/agencyB/目錄中的鏈證書、機構證書、機構私鑰複製到 generator/meta/文件中
cp ./dir_agency_ca/agencyB/* ~/generator/meta/
複製後:
修改配置文件
手動的方式修改conf文件夾下面node_deployment.ini
p2p_ip地址修改爲該服務器對應的外網ip,其中rpc_ip要修改爲內網ip。
上圖爲服務器A中的node_deployment.ini配置。服務器B中的node_deployment.i也根據服務器ip進行相應的修改。
機構A生成併發送節點信息
機構(服務器)A生成併發送節點信息
./generator --generate_all_certificates ./agencyA_node_info
機構B生成併發送節點信息
./generator --generate_all_certificates ./agencyB_node_info
創世機構收集節點證書
生成創世區塊的機構需要節點證書,本章中是由A機構生成創世區塊,因此B機構需要發送節點證書至機構A。將機構B節點agencyB_node_info文件夾cert_*.crt文件copy到機構A的meta文件夾中。
上圖是將機構B中的兩個節點證書成功拷貝到機構A中的meta,此時meta中共有四個節點證書,兩個爲機構A的,兩個爲機構B的。
各機構節點連接信息相互收集
例如:將機構B中的 peersB.txt 拷貝到機構A的meta文件夾,同時,將機構A中的 peersA.txt 拷貝到機構B的meta文件夾。每個peers*.txt裏都是該機構的節點連接信息。
注:在機構B中,一開始txt的名稱爲peers.txt,需要將其複製重命名爲peerB.txt,然後拷貝到機構A中。機構A中也同理。上面兩張圖中都有peers.txt,這是多餘的,大家在實際操作中是沒有的。
機構A生成羣組1創世區塊
-
將機構A中的generator/conf/conf/group_genesis.ini進行手動修改,配置成如圖:
其中node0-node3這四個節點,分別爲兩個服務器上節點的外網ip+端口。 -
執行命令 生成group_genesis.ini 配置的羣組創世區塊:
./generator --create_group_genesis ./group
- 分發羣組1創世區塊至機構B
手動複製 機構A中的 ./group/group.1.genesis文件到機構B的meta文件夾下。
機構A生成所屬節點
執行:
./generator --build_install_package ./meta/peersB.txt ./nodeA
機構B生成所屬節點
執行:
./generator --build_install_package ./meta/peersA.txt ./nodeB
各自啓動機構下的節點
- 啓動A機構下的節點:
bash ./nodeA/start_all.sh
- 啓動B機構下的節點:
bash ./nodeB/start_all.sh
注意:如果端口被佔用,可以根據端口查找進程
sudo lsof -i:[port]
然後根據PID殺掉進程
sudo kill [PID]
控制檯部署
在服務器A和服務器B都進行以下的配置。
- 添加ppa源
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
如果報錯:則
add-apt-repository
sudo apt-get install python-software-properties
然後再:
sudo add-apt-repository ppa:webupd8team/java
- 安裝openjdk
sudo apt install openjdk-8-jre-headless
- 配置jdk
下載jkd到電腦上:鏈接:下載jdk網址
新建software文件夾,將jdk壓縮包放置其中
在/usr/lib/ 新建jdk文件夾,在software文件裏執行解壓命令
sudo tar -zxvf jdk-8u231-linux-x64.tar.gz -C /usr/lib/jdk
- 修改配置
sudo vi /etc/profile
export JAVA_HOME=/usr/lib/jdk/jdk1.8.0_231
export JRE_HOME=${JAVA_HOME}/jre
export PATH=${JAVA_HOME}/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib:${JRE_HOME}/lib
執行命令,立即生效:
source /etc/profile
sudo update-alternatives --install /usr/bin/java java /usr/lib/jdk/jdk1.8.0_231/bin/java 300
sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jdk/jdk1.8.0_231/bin/javac 300
- 下載控制檯程序
./generator --download_console ./ --cdn
- 在服務器A中執行
./generator --generate_sdk_certificate ./dir_sdk_ca ./dir_agency_ca/agencyA
- 在服務B中執行
./generator --generate_sdk_certificate ./dir_sdk_ca ./dir_agency_ca/agencyB
以上所有操作執行完,便完成了控制檯的部署。
示例
進入generator/console 後,輸入:
./start.sh
即可進入控制檯。
可以部署簡單的Asset.sol合約,合約代碼:
pragma solidity ^0.4.24;
import "./Table.sol";
contract Asset {
// event
event RegisterEvent(int256 ret, string account, uint256 asset_value);
event TransferEvent(int256 ret, string from_account, string to_account, uint256 amount);
constructor() public {
// 構造函數中創建t_asset表
createTable();
}
function createTable() private {
TableFactory tf = TableFactory(0x1001);
// 資產管理表, key : account, field : asset_value
// | 資產賬戶(主鍵) | 資產金額 |
// |-------------------- |-------------------|
// | account | asset_value |
// |---------------------|-------------------|
//
// 創建表
tf.createTable("t_asset", "account", "asset_value");
}
function openTable() private returns(Table) {
TableFactory tf = TableFactory(0x1001);
Table table = tf.openTable("t_asset");
return table;
}
/*
描述 : 根據資產賬戶查詢資產金額
參數 :
account : 資產賬戶
返回值:
參數一: 成功返回0, 賬戶不存在返回-1
參數二: 第一個參數爲0時有效,資產金額
*/
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")));
}
}
/*
描述 : 資產註冊
參數 :
account : 資產賬戶
amount : 資產金額
返回值:
0 資產註冊成功
-1 資產賬戶已存在
-2 其他錯誤
*/
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;
}
/*
描述 : 資產轉移
參數 :
from_account : 轉移資產賬戶
to_account : 接收資產賬戶
amount : 轉移金額
返回值:
0 資產轉移成功
-1 轉移資產賬戶不存在
-2 接收資產賬戶不存在
-3 金額不足
-4 金額溢出
-5 其他錯誤
*/
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;
}
}
效果圖: