記一下使用 WeBASE 搭建自己的聯盟鏈過程


使用寶塔搭建自己的區塊鏈私鏈

不要裝到 root 文件夾下面!

使用 WeBASE 一鍵部署可直接跳到第二節

0x00 虛擬機上的安裝寶塔

建議使用 xshell 和 xftp 進行輔助搭建,具體使用教程請自行百度。

在虛擬機上部署寶塔環境,這里我用的是 CentOS 7 版本,安裝命令如下:

yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh

其他版本的系統參見 寶塔官網

安裝完成后會出現

image-20210405204742359

此時,就可以使用相應的網址在瀏覽器中訪問寶塔的面板了,初次會需要登錄,賬號密碼如上圖所示

image-20210405204848915

0x01 搭建 FISCO BCOS 區塊鏈網絡

這里主要摘要 CentOS 版本系統的安裝命令,其他版本系統簡潔明了詳細的參考文檔 FISCO BCOS中文文檔 ,這里的一切都是基於未安裝過 FISCO BCOS 的條件完成的,如果是想要升級版本的話,請移步官方文檔。

1、搭建單節點聯盟鏈

1.1 搭建 FISCO BCOS 環境

使用命令 sudo yum install -y openssl openssl-devel 安裝依賴

image-20210405211919472

創建操作目錄,下載安裝腳本文件,雖然名字任意,但是還是建議命名為 fisco

## 創建操作目錄
cd ~ && mkdir -p fisco && cd fisco

## 下載腳本
curl -#LO https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/v2.7.2/build_chain.sh && chmod u+x build_chain.sh

image-20210405211950254

如果因為網絡問題導致長時間無法下載build_chain.sh腳本,請嘗試 curl -#LO https://osp-1257653870.cos.ap-guangzhou.myqcloud.com/FISCO-BCOS/FISCO-BCOS/releases/v2.7.2/build_chain.sh && chmod u+x build_chain.sh

在 fisco 目錄下執行下面的指令,生成一條單群組4節點的 FISCO 鏈。請確保機器的30300~30303,20200~20203,8545~8548端口沒有被占用。

bash build_chain.sh -l 127.0.0.1:4 -p 30300,20200,8545

image-20210405212039510

成功后會提示 All completed。

啟動 FISCO BCOS 鏈

bash nodes/127.0.0.1/start_all.sh

image-20210405212224919

## 檢查進程是否成功
## 正常情況會有類似下面的輸出; 如果進程數不為4,則進程沒有啟動(一般是端口被占用導致的)
ps -ef | grep -v grep | grep fisco-bcos

## 檢查日志輸出
## 正常情況會不停地輸出連接信息,從輸出可以看出node0與另外3個節點有連接。
tail -f nodes/127.0.0.1/node0/log/log*  | grep connected

## 檢查是否在共識
## 正常情況會不停輸出++++Generating seal,表示共識正常。
tail -f nodes/127.0.0.1/node0/log/log*  | grep +++

image-20210405212405446

2、配置及使用控制台

2.1 配置控制台

安裝 java

#centos系統安裝java
sudo yum install -y java java-devel

獲取控制台並回到 fisco 目錄

cd ~/fisco && curl -LO https://github.com/FISCO-BCOS/console/releases/download/v2.7.2/download_console.sh && bash download_console.sh

## 速度慢的話用這個 
cd ~/fisco && curl -#LO https://gitee.com/FISCO-BCOS/console/raw/master/tools/download_console.sh

image-20210405213631932

拷貝控制台配置文件

## 最新版本控制台使用如下命令拷貝配置文件
## 若節點未采用默認端口,請將文件中的20200替換成節點對應的channel端口。
cp -n console/conf/config-example.toml console/conf/config.toml

配置控制台證書

cp -r nodes/127.0.0.1/sdk/* console/conf/

2.2 使用控制台

## 啟動
cd ~/fisco/console && bash start.sh

image-20210405214301704

輸出這樣就算成功

## 查看版本
getNodeVersion

## 查看節點
getPeers

image-20210405214501870

0x02 WeBase 的安裝配置

WeBASE 的運行原理

1、環境安裝

需要的環境

環境 版本
Java JDK 8 至JDK 14
MySQL MySQL-5.6及以上
Python Python3.6及以上
PyMySQL
  1. Java 剛才我們已經安裝了

  2. MySQL 可以在寶塔的面板里直接快捷安裝

    image-20210405235144940

    image-20210406121320731

  3. Python 3 命令行形式安裝

  4. PyMySQL 安裝

    sudo yum -y install python36-pip
    sudo pip3 install PyMySQL
    

2、WeBASE 的部署

新建一個文件夾用於存放 WeBASE

mkdir webase

獲取部署安裝包:

# 建議直接掛個梯子在本機上下好后拖進虛擬機,不然可能會很慢,快的話當我沒說
wget https://github.com/WeBankFinTech/WeBASELargeFiles/releases/download/v1.4.3/webase-deploy.zip

解壓安裝包:

unzip webase-deploy.zip

進入目錄:

cd webase-deploy

解壓剛才下好的壓縮包

unzip webase-deploy.zip

進入解壓后的目錄

cd webase-deploy

Nginx 修改參見第三節,務必修改完畢再部署!

修改 common.properties 文件 vi common.properties

# 服務端口不能小於 1024
# WeBASE子系統的最新版本(v1.1.0或以上版本)
webase.web.version=v1.4.3
webase.mgr.version=v1.4.3
webase.sign.version=v1.4.3
webase.front.version=v1.4.3

# 節點管理子系統mysql數據庫配置
# 將設置里的 user 和 password 改成自己的
mysql.ip=127.0.0.1
mysql.port=3306
mysql.user=dbUsername
mysql.password=dbPassword
mysql.database=webasenodemanager

# 簽名服務子系統mysql數據庫配置
sign.mysql.ip=localhost
sign.mysql.port=3306
sign.mysql.user=dbUsername
sign.mysql.password=dbPassword
sign.mysql.database=webasesign

# 節點前置子系統h2數據庫名和所屬機構
front.h2.name=webasefront
front.org=fisco

# WeBASE管理平台服務端口
web.port=5000
# 節點管理子系統服務端口
mgr.port=5001
# 節點前置子系統端口
front.port=5002
# 簽名服務子系統端口
sign.port=5004


# 節點監聽Ip
node.listenIp=127.0.0.1
# 節點p2p端口
node.p2pPort=30300
# 節點鏈上鏈下端口
node.channelPort=20200
# 節點rpc端口
node.rpcPort=8545

# Encrypt type (0: standard, 1: guomi)
encrypt.type=0
# ssl encrypt type (0: standard ssl, 1: guomi ssl)
# only guomi type support guomi ssl
encrypt.sslType=0

# 是否使用已有的鏈(yes/no)
if.exist.fisco=no

# 使用已有鏈時需配置
# 已有鏈的路徑,start_all.sh腳本所在路徑
# 路徑下要存在sdk目錄
# 當使用非國密鏈,或者使用國密鏈,但是sdk和節點使用非國密ssl連接時,sdk目錄里存放非國密sdk證書(ca.crt、node.crt和node.key)
# 當使用國密鏈,並且sdk和節點使用國密ssl連接時,需在sdk目錄里創建gm目錄,gm目錄存放國密sdk證書(gmca.crt、gmsdk.crt、gmsdk.key、gmensdk.crt和gmensdk.key)
fisco.dir=/data/app/nodes/127.0.0.1
# 前置所連接節點的絕對路徑
# 路徑下要存在conf文件夾,conf里存放節點證書(ca.crt、node.crt和node.key)
node.dir=/data/app/nodes/127.0.0.1/node0

# 搭建新鏈時需配置
# FISCO-BCOS版本
fisco.version=2.7.0
# 搭建節點個數(默認兩個)
node.counts=nodeCounts

配置完成后執行 installAll 命令,部署服務將自動部署FISCO BCOS節點,並部署 WeBASE 中間件服務,包括簽名服務(sign)、節點前置(front)、節點管理服務(node-mgr)、節點管理前端(web)

  • 部署腳本會拉取相關安裝包進行部署,需保持網絡暢通
  • 首次部署需要下載編譯包和初始化數據庫,重復部署時可以根據提示不重復操作
  • 部署過程中出現報錯時,可根據錯誤提示進行操作,或根據本文檔中的常見問題進行排查
  • 不要用sudo執行腳本,例如sudo python3 deploy.py installAll(sudo會導致無法獲取當前用戶的環境變量如JAVA_HOME),如果沒有用 sudo 命令還是出現了無法獲取 JAVA_HOME 環境變量的情況,請參見 Linux 下無法獲取 JAVA_HOME 環境變量的解決方案
# 部署並啟動所有服務
python3 deploy.py installAll

執行過程中可能會報錯端口正在被占用,那么只需要執行命令 vi common.properties 進行相應的端口更換即可,全部部署完畢后

image-20210406124925876

后續使用命令

# 一鍵部署
部署並啟動所有服務        python3 deploy.py installAll
停止一鍵部署的所有服務    python3 deploy.py stopAll
啟動一鍵部署的所有服務    python3 deploy.py startAll
# 各子服務啟停
啟動FISCO-BCOS節點:      python3 deploy.py startNode
停止FISCO-BCOS節點:      python3 deploy.py stopNode
啟動WeBASE-Web:          python3 deploy.py startWeb
停止WeBASE-Web:          python3 deploy.py stopWeb
啟動WeBASE-Node-Manager: python3 deploy.py startManager
停止WeBASE-Node-Manager: python3 deploy.py stopManager
啟動WeBASE-Sign:        python3 deploy.py startSign
停止WeBASE-Sign:        python3 deploy.py stopSign
啟動WeBASE-Front:        python3 deploy.py startFront
停止WeBASE-Front:        python3 deploy.py stopFront
# 可視化部署
部署並啟動可視化部署的所有服務  python3 deploy.py installWeBASE
停止可視化部署的所有服務  python3 deploy.py stopWeBASE
啟動可視化部署的所有服務  python3 deploy.py startWeBASE

3、檢查執行

執行命令

$ ps -ef | grep node

image-20210406125219705

$ ps -ef | grep webase.front 

image-20210406125322186

## 檢查節點管理服務 webase-node-manager 的進程
$ ps -ef  | grep webase.node.mgr

image-20210406125429497

。。。。其余的參照官網上的進行檢查

0x03 Nginx 的問題

當我們使用寶塔安裝 Nginx 后,需要在 webase-deploy/comm/temp.conf 中修改 /etc/nginx/mime.types 的文件位置為我們自己的nginx 目錄,一般來說用寶塔安裝的都在根目錄下的 www 文件夾下

image-20210406170137039

在 webase-deploy/comm/ 文件夾下執行命令 vi temp.conf 進行更改

image-20210406170400209

之后回到 webase-deploy 目錄下執行命令 python3 deploy.py installAll 重新安裝部署整個項目

之后若無問題應該就可以直接訪問了,初始賬號為 admin ,密碼為 Abcd1234

image-20210406170744298

之后的配置就參見官方文檔了 WeBASE使用手冊

0x04 智能合約的部署及應用

1、新建合約

image-20210408190157786

pragma solidity>=0.4.24 <0.6.11;
 
 
// 導入 kv 表的合約 
import "./Table.sol";
 
 
 
contract Modeus {
 
event SetResult(int256 count);
 
 
 
KVTableFactory tableFactory;
 
string constant TABLE_NAME = "t_proof";
 
 
 
constructor() public {
 
//The fixed address is 0x1010 for KVTableFactory
 
tableFactory = KVTableFactory(0x1010);
 
// the parameters of createTable are tableName,keyField,"vlaueFiled1,vlaueFiled2,vlaueFiled3,..."
// 創建 kv 表單,id:序號,sid:數據庫所做修改對應的 id ,base 修改前,newbase 修改后
 
tableFactory.createTable(TABLE_NAME, "id", "sid,base,newbase");
 
}
 
 
 
// 獲取鏈上的信息
 
function get(string memory id) public view returns (bool, string memory, string memory,string memory) {
 
KVTable table = tableFactory.openTable(TABLE_NAME);
 
bool ok = false;
 
Entry entry;
 
(ok, entry) = table.get(id);
 
string memory sid;
 
string memory base;
 
string memory newbase;
 
if (ok) {
 
sid= entry.getString("sid");
 
base = entry.getString("base");
 
newbase = entry.getString("newbase");
 
}
 
return (ok, sid, base,newbase);
 
}
 
 
 
// 數據庫的修改上鏈
 
function set(string memory id, string memory sid, string memory base,string memory newbase)
 
public
 
returns (int256)
 
{
 
KVTable table = tableFactory.openTable(TABLE_NAME);
 
Entry entry = table.newEntry();
 
// the length of entry's field value should < 16MB
 
entry.set("id", id);
 
entry.set("sid", sid);
 
entry.set("base", base);
 
entry.set("newbase", newbase);
 
// the first parameter length of set should <= 255B
 
int256 count = table.set(id, entry);
 
emit SetResult(count);
 
return count;
 
}
 
}

官方的 table.sol 代碼如下:

contract TableFactory {
 
function openTable(string memory) public view returns (Table) {} //open table
 
function createTable(string memory, string memory, string memory) public returns (int256) {} //create table
 
}
 
 
 
//select condition
 
contract Condition {
 
function EQ(string memory, int256) public {}
 
function EQ(string memory, string memory) public {}
 
 
 
function NE(string memory, int256) public {}
 
function NE(string memory, string memory) public {}
 
 
 
function GT(string memory, int256) public {}
 
function GE(string memory, int256) public {}
 
 
 
function LT(string memory, int256) public {}
 
function LE(string memory, int256) public {}
 
 
 
function limit(int256) public {}
 
function limit(int256, int256) public {}
 
}
 
 
 
//one record
 
contract Entry {
 
function getInt(string memory) public view returns (int256) {}
 
function getUInt(string memory) public view returns (int256) {}
 
function getAddress(string memory) public view returns (address) {}
 
function getBytes64(string memory) public view returns (bytes1[64] memory) {}
 
function getBytes32(string memory) public view returns (bytes32) {}
 
function getString(string memory) public view returns (string memory) {}
 
 
 
function set(string memory, int256) public {}
 
function set(string memory, uint256) public {}
 
function set(string memory, string memory) public {}
 
function set(string memory, address) public {}
 
}
 
 
 
//record sets
 
contract Entries {
 
function get(int256) public view returns (Entry) {}
 
function size() public view returns (int256) {}
 
}
 
 
 
//Table main contract
 
contract Table {
 
function select(string memory, Condition) public view returns (Entries) {}
 
function insert(string memory, Entry) public returns (int256) {}
 
function update(string memory, Entry, Condition) public returns (int256) {}
 
function remove(string memory, Condition) public returns (int256) {}
 
 
 
function newEntry() public view returns (Entry) {}
 
function newCondition() public view returns (Condition) {}
 
}
 
 
 
contract KVTableFactory {
 
function openTable(string memory) public view returns (KVTable) {}
 
function createTable(string memory, string memory, string memory) public returns (int256) {}
 
}
 
 
 
//KVTable per permiary key has only one Entry
 
contract KVTable {
 
function get(string memory) public view returns (bool, Entry) {}
 
function set(string memory, Entry) public returns (int256) {}
 
function newEntry() public view returns (Entry) {}
 
}

編寫完成后進行編譯,編譯成功后進行部署

image-20210408190304555

部署完成后進行本地測試

image-20210408190424192

交易發起后去首頁查看是否有交易記錄,若有則成功

2、智能合約的本地調用

這里我們選擇使用 rest api 來調用智能合約,使用 post 方式接口 http://localhost:5002/WeBASE-Front/trans/handleWithSign

這里可以看一下官方文檔中的相關部分接口文檔 handleWithSign 文檔

1)參數表

序號 中文 參數名 類型 最大長度 必填 說明
1 用戶地址 user String 用戶地址,可通過/privateKey接口創建
2 合約名稱 contractName String
3 合約地址 contractAddress String
4 方法名 funcName String
5 合約編譯后生成的abi文件內容 contractAbi List 合約中單個函數的ABI,若不存在同名函數可以傳入整個合約ABI,格式:JSONArray
6 方法參數 funcParam List JSON數組,多個參數以逗號分隔(參數為數組時同理),如:["str1",["arr1","arr2"]],根據所調用的合約方法判斷是否必填
7 群組ID groupId int 默認為1
8 合約路徑 contractPath int
9 是否使用cns調用 useCns bool
10 cns名稱 cnsName String CNS名稱,useCns為true時不能為空
11 cns版本 version String CNS版本,useCns為true時不能為空

然后去構建參數列表,格式為:

{
    "groupId" :1,
    "signUserId": "458ecc77a08c486087a3dcbc7ab5a9c3",
    "contractAbi":[{"constant":true,"inputs":[],"name":"getVersion","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getStorageCell","outputs":[{"name":"","type":"string"},{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"n","type":"string"}],"name":"setVersion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"storageHash","type":"string"},{"name":"storageInfo","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}],
    "contractAddress":"0x14d5af9419bb5f89496678e3e74ce47583f8c166",
    "funcName":"set",
    "funcParam":["test"],
    "useCns":false
}

其中的 signUserId 在私鑰管理中可以查詢到,如果沒有私鑰的話新建一個

image-20210408191335510

contractAbicontractAddress(合約地址) 可以在 合約管理 -> 合約列表 中查詢到。

將模板中的 funcParam 更換為自己編寫的智能合約中的參數列表對應的數據。使用 postman 進行測試

image-20210408191949547

如圖,測試成功。

3、在應用中使用智能合約

編寫工具類 BlockChainUtils

package utils;

import cn.hutool.http.HttpUtil;

public class BlockChainUtils {
    //    public static long id = 1;
    public static String set(String id ,String sid,String base,String newBase){
        String body="{\n" +

            " \n" +

            " \"groupId\" :1,\n" +

            " \"signUserId\": \"bbc341c4e982xxxxxxxxxxx76167f00ab4842e\",\n" +

            " \"contractAbi\":[{\"constant\":true,\"inputs\":[{\"name\":\"id\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"},{\"name\":\"\",\"type\":\"int256\"},{\"name\":\"\",\"type\":\"string\"},{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"sid\",\"type\":\"int256\"},{\"name\":\"nickname\",\"type\":\"string\"},{\"name\":\"content\",\"type\":\"string\"}],\"name\":\"set\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"count\",\"type\":\"int256\"}],\"name\":\"SetResult\",\"type\":\"event\"}],\n" +

            " \"contractAddress\":\"0xef860c2xxxx24b38bxxe1b317ad2\",\n" +

            " \"funcName\":\"set\",\n" +

            " \"funcParam\":[\""+comment.getId()+"\","+comment.getSid()+",\""+comment.getNickname()+"\",\""+comment.getContent()+"\"]\n" +

            "\n" +

            "}";
        System.out.println(body);
        String url = "http://xxxxxxxxx:5002/WeBASE-Front/trans/handleWithSign";

        String res = HttpUtil.post(url,body);
        return res;

        //        id ++;
    }

    public static void get(){}

}

然后在其他地方調用 set 方法就行了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM