• 记一下使用 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="{
    " +
    
                " 
    " +
    
                " "groupId" :1,
    " +
    
                " "signUserId": "bbc341c4e982xxxxxxxxxxx76167f00ab4842e",
    " +
    
                " "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"}],
    " +
    
                " "contractAddress":"0xef860c2xxxx24b38bxxe1b317ad2",
    " +
    
                " "funcName":"set",
    " +
    
                " "funcParam":[""+comment.getId()+"","+comment.getSid()+",""+comment.getNickname()+"",""+comment.getContent()+""]
    " +
    
                "
    " +
    
                "}";
            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 方法就行了。

  • 相关阅读:
    Python写的简陋版一对一聊天工具,全双工
    Python函数的循环调用
    Python多进程
    正则表达式
    Python-urllib学习记录
    Android学习笔记8:使用HttpClient接口实现网络通信
    Java抽象类和接口的区别(好长时间没看这种文章了)
    Android笔记:bitmap转换与处理相关工具类,Bitmap与DrawAble与byte[]与InputStream之间的转换
    first work
    Android学习笔记7:使用SQLite方式存储数据
  • 原文地址:https://www.cnblogs.com/Constantin/p/14634435.html
Copyright © 2020-2023  润新知