第二章 多服務器分佈式部署——服務器A和服務器B實現羣組1的搭建

基礎底層搭建

  • 目標

    本章的目標是用兩個服務器,實現羣組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;
    }
}

效果圖:
在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章