FISCO BCOS搭建

zhenxi
2024-04-17 / 0 评论 / 2 阅读 / 正在检测是否收录...

FISCO BCOS搭建

搭建WeBASE

部署文档地址:https://webasedoc.readthedocs.io/zh-cn/latest/docs/WeBASE/install.html

①配置环境

1.1 检查Java

image-20240312140024235

配置JAVA_HOME:

cd /usr/lib/jvm
ls

vim /etc/profile

export JAVA_HOME=/usr/lib/jvm/java-1.11.0-openjdk-amd64 # 此处为自己的jdk版本号
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

source /etc/profile
echo $JAVA_HOME

1.2 检查mysql

Ubuntu安装:

注:这里没有安装官方文档给的mysql 5.7 。因为在安装时发生报错,所以采用了Ubuntu的默认mysql 8版本:

sudo apt update
sudo apt install mysql-server

查看mysql版本:8.0.36-0ubuntu0.22.04.1

image-20240314150058598

初始化root密码:

mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';

设置远程登陆:

mysql -uroot -p
use mysql;
select user,host from user;
update user set host='%' where user='root' and host='localhost';

image-20240312143332377

修改 /etc/mysql/mysql.conf.d/mysqld.cnf 配置文件:

vim /etc/mysql/mysql.conf.d/mysqld.cnf

image-20240313090242724

重启mysql服务:

service mysql restart

尝试远程连接:

image-20240314145711135

image-20240312143415701


1.3 检查python3

// 添加仓库,回车继续
sudo add-apt-repository ppa:deadsnakes/ppa
// 安装python 3.6
sudo apt-get install -y python3.6
sudo apt-get install -y python3-pip
python --version
# python3时
python3 --version

1.4 PyMySQL部署

sudo apt-get install -y python3-pip
sudo pip3 install PyMySQL

②安装WeBASE

2.1 部署WeBASE

获取部署安装包:

wget https://osp-1257653870.cos.ap-guangzhou.myqcloud.com/WeBASE/releases/download/v1.5.5/webase-deploy.zip

解压安装包:

unzip webase-deploy.zip

进入目录:

cd webase-deploy

修改配置:

更改数据库用户以及密码:

image-20240318101244377

设置节点数量为4:

image-20240312144210310

# 部署并启动所有服务
python3 deploy.py installAll

image-20240312144750455

image-20240312150232185

WeBASE管理平台:

  • 一键部署完成后,打开浏览器(Chrome Safari或Firefox)访问
http://{deployIP}:{webPort}
示例:http://localhost:5000

image-20240313095409931

image-20240314141914040


2.2 问题(已解决)(与官网解决方法不一致)

验证码失效问题:在WeBASE官方文档中给出了解决方案:

查WeBASE-Node-Manager后台服务是否已启动成功。若启动成功,检查后台日志:

  • 进入 webase-node-mgr 目录下,执行 bash status.sh 检查服务是否启动,如果服务没有启动,运行 bash start.sh 启动服务;
  • 如果服务已经启动,按照如下修改日志级别
cd webase-node-mgr
bash status.sh

image-20240314142046782

发现确实是5001端口服务没启动。

bash start.sh

image-20240314142127283

启动成功后再次确认是否成功启动,发现还是没有进程号。

image-20240314142257505

查看日志信息,看看报了什么错!告诉我们去看看log

Server com.webank.webase.node.mgr.Application Port 5001 ...PID(4982) [Starting]. Please message check through the log file (default path:./log/).

image-20240314142457083

查看日志:

vim WeBASE-Node-Manager.log

发现问题:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

很熟悉,这不是mysql的错误吗?

查询之后发现是SSL问题,当我们写项目时,配JDBC连接的时候常常出现:

jdbc:mysql://127.0.0.1:3306/yxaqgl?verifyServerCertificate=true&useSSL=False&requireSSL=False

但这个配置文件中并没有连接属性:

# 节点管理子系统mysql数据库配置
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

那就彻底关闭mysql的SSL属性:

先检查一下是否开启了SSL:

mysql -uroot -p

SHOW VARIABLES LIKE '%ssl%';

如下图,SSL确实开启:

image-20240314143732809

使用exit离开,进入mysql的安装目录:

image-20240314144027239

进入mysql.cnf文件发现这只是个引用?

image-20240314144217603

进入mysql.conf.d里面:添加skip_ssl

GIF 2024-3-14 14-45-47

重启服务!(一定要重启)再次查询

service mysql restart

image-20240314144754531

此时SSL已经关闭,再次启动WeBASE尝试是否有问题:

exit

su root 

cd webase-deploy

python3 deploy.py stopAll

python3 deploy.py startAll

image-20240314145229200

image-20240314145205109

image-20240314145430126

image-20240314145453619

image-20240314145502246

填写默认端口:5002

image-20240314145512707

image-20240314145546817

服务部署后,需要对各服务进行启停操作,可以使用以下命令:

# 一键部署
部署并启动所有服务        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.1 编写智能合约

智能合约开发文档地址:https://fisco-bcos-documentation.readthedocs.io/zh-cn/latest/docs/manual/smart_contract.html
注意:以下是本人所需业务而书写的智能合约,请不要和本人一致,请根据你自己的业务来进行命名以及书写相应的方法。

pragma solidity ^0.4.25;
pragma experimental ABIEncoderV2;

import "./Table.sol";

contract Record {
    event InsertResult(int256 count);
    event UpdateResult(int256 count);
    event GetResult(string description,string remark);

    TableFactory tableFactory;
    string constant TABLE_NAME = "record";
    constructor() public {
        tableFactory = TableFactory(0x1001); //The fixed address is 0x1001 for TableFactory
        // the parameters of createTable are tableName,keyField,"vlaueFiled1,vlaueFiled2,vlaueFiled3,..."
        tableFactory.createTable(TABLE_NAME, "recordid", "description,remark");
    }

    //select records
    function getResult(string memory recordid)
    public
    view
    returns (string memory,string memory)
    {
        Table table = tableFactory.openTable(TABLE_NAME);

        Condition condition = table.newCondition();
        condition.EQ("recordid",recordid);

        Entries entries = table.select(recordid, condition);
        
        require(entries.size() > 0, "Record does not exist");
        
        Entry entry = entries.get(0);
        
        string memory description = entry.getString("description");
        
        string memory remark = entry.getString("remark");
        
        emit GetResult(description,remark);
        
        return (description,remark);
    }
    
    //insert records
    function insert(string memory recordid, string memory description, string memory remark)
    public
    returns (int256)
    {
        Table table = tableFactory.openTable(TABLE_NAME);

        Entry entry = table.newEntry();
        entry.set("recordid", recordid);
        entry.set("description",description);
        entry.set("remark", remark);

        int256 count = table.insert(recordid, entry);
        emit InsertResult(count);

        return count;
    }
    //update records
    function update(string memory recordid, string memory description, string memory remark)
    public
    returns (int256)
    {
        Table table = tableFactory.openTable(TABLE_NAME);

        Entry entry = table.newEntry();
        entry.set("description", description);
        entry.set("remark", remark);
        
        Condition condition = table.newCondition();
        condition.EQ("recordid", recordid);

        int256 count = table.update(recordid, entry, condition);
        emit UpdateResult(count);

        return count;
    }
}

智能合约编写完成后,点击部署,将智能合约部署到WeBASE平台:

image-20240318151745557

pragma solidity ^0.4.24;

contract TableFactory {
    /**
     * 打开表,返回Table合约地址
     * @param tableName 表的名称
     * @return 返回Table的地址,当表不存在时,将会返回空地址即address(0x0)
     */
    function openTable(string tableName) public constant returns (Table);

    /**
     * 创建表,返回是否成功
     * @param tableName 表的名称
     * @param key 表的主键名
     * @param valueFields 表的字段名,多个字段名以英文逗号分隔
     * @return 返回错误码,成功为0,错误则为负数
     */
    function createTable(string tableName,string key,string valueFields) public returns(int);
}

// 查询条件
contract Condition {
    //等于
    function EQ(string, int) public;
    function EQ(string, string) public;

    //不等于
    function NE(string, int) public;
    function NE(string, string)  public;

    //大于
    function GT(string, int) public;
    //大于或等于
    function GE(string, int) public;

    //小于
    function LT(string, int) public;
    //小于或等于
    function LE(string, int) public;

    //限制返回记录条数
    function limit(int) public;
    function limit(int, int) public;
}

// 单条数据记录
contract Entry {
    function getInt(string) public constant returns(int);
    function getAddress(string) public constant returns(address);
    function getBytes64(string) public constant returns(byte[64]);
    function getBytes32(string) public constant returns(bytes32);
    function getString(string) public constant returns(string);

    function set(string, int) public;
    function set(string, string) public;
    function set(string, address) public;
}

// 数据记录集
contract Entries {
    function get(int) public constant returns(Entry);
    function size() public constant returns(int);
}

// Table主类
contract Table {
    /**
     *  查询接口                                                                                                                                                                                                                               
     * @param key 查询主键值
     * @param cond 查询条件
     * @return Entries合约地址,合约地址一定存在
     */
    function select(string key, Condition cond) public constant returns(Entries);
    /**
     *  插入接口
     * @param key 插入主键值
     * @param entry 插入字段值
     * @return 插入影响的行数
     */
    function insert(string key, Entry entry) public returns(int);
    /**
     *  更新接口
     * @param key 更新主键值
     * @param entry 更新字段值
     * @param cond 更新条件
     * @return 更新影响的行数
     */
    function update(string key, Entry entry, Condition cond) public returns(int);
    /**
     *  删除接口
     * @param key 删除的主键值
     * @param cond 删除条件
     * @return 删除影响的行数
     */
    function remove(string key, Condition cond) public returns(int);

    function newEntry() public constant returns(Entry);
    function newCondition() public constant returns(Condition);
}

3.2 测试智能合约

点击发交易进行智能合约测试:

image-20240417195216052

①测试insert方法:

image-20240318152038290

image-20240315142317467

image-20240417195337574

②测试查询方法

image-20240318152226519

image-20240315142442835


④调用SDK

4.1 WeBase导出Java项目

导出智能合约:

image-20240318152342110

导出的Java项目如下图所示:

image-20240318152708571

发现导出的项目没有生成Table类!!!于是我们采用配置控制台来获取Table的相关信息。

4.2 配置控制台

cd ~
mkdir fisco
cd ~/fisco && curl -LO https://github.com/FISCO-BCOS/console/releases/download/v2.9.2/download_console.sh && bash download_console.sh
cp -r /root/webase-deploy/nodes/127.0.0.1/sdk/* /root/fisco/console/conf/ 
cd ~/fisco/console && bash start.sh

image-20240926231409111

出现这个问题进入:

image-20240926231542242

根据图中相关命令进行:

image-20240314200009893

image-20240926231612291

4.3 结合若依项目

创建控制台之后:

获取Record.java、Table.java、Record.bin、Table.bin这四个文件:

GIF 2024-4-17 19-46-56

其余文件均可在导出的Java项目中找到:如下,在若依项目中创建相应的文件夹,将所需要的文件统一复制过去。

其中config-example.toml:

若有更新去:https://github.com/FISCO-BCOS/java-sdk/blob/master-2.0/src/test/resources/config-example.toml

[cryptoMaterial]
certPath = "conf"                           # The certification path  

# The following configurations take the certPath by default if commented
# caCert = "conf/ca.crt"                    # CA cert file path
                                            # If connect to the GM node, default CA cert path is ${certPath}/gm/gmca.crt

# sslCert = "conf/sdk.crt"                  # SSL cert file path
                                            # If connect to the GM node, the default SDK cert path is ${certPath}/gm/gmsdk.crt

# sslKey = "conf/sdk.key"                   # SSL key file path
                                            # If connect to the GM node, the default SDK privateKey path is ${certPath}/gm/gmsdk.key

# enSslCert = "conf/gm/gmensdk.crt"         # GM encryption cert file path
                                            # default load the GM SSL encryption cert from ${certPath}/gm/gmensdk.crt

# enSslKey = "conf/gm/gmensdk.key"          # GM ssl cert file path
                                            # default load the GM SSL encryption privateKey from ${certPath}/gm/gmensdk.key

[network]
peers=["127.0.0.1:20200"]    # The peer list to connect


# AMOP configuration
# You can use following two methods to configure as a private topic message sender or subscriber.
# Usually, the public key and private key is generated by subscriber.
# Message sender receive public key from topic subscriber then make configuration.
# But, please do not config as both the message sender and the subscriber of one private topic, or you may send the message to yourself.

# Configure a private topic as a topic message sender.
# [[amop]]
# topicName = "PrivateTopic"
# publicKeys = [ "conf/amop/consumer_public_key_1.pem" ]    # Public keys of the nodes that you want to send AMOP message of this topic to.

# Configure a private topic as a topic subscriber.
# [[amop]]
# topicName = "PrivateTopic"
# privateKey = "conf/amop/consumer_private_key.p12"         # Your private key that used to subscriber verification.
# password = "123456"


[account]
keyStoreDir = "account"         # The directory to load/store the account file, default is "account"
# accountFilePath = ""          # The account file path (default load from the path specified by the keyStoreDir)
accountFileFormat = "pem"       # The storage format of account file (Default is "pem", "p12" as an option)

# accountAddress = ""           # The transactions sending account address
                                # Default is a randomly generated account
                                # The randomly generated account is stored in the path specified by the keyStoreDir

# password = ""                 # The password used to load the account file

[threadPool]
# channelProcessorThreadSize = "16"         # The size of the thread pool to process channel callback
                                            # Default is the number of cpu cores

# receiptProcessorThreadSize = "16"         # The size of the thread pool to process transaction receipt notification
                                            # Default is the number of cpu cores

maxBlockingQueueSize = "102400"             # The max blocking queue size of the thread pool

image-20240318103949699

导入Fisco依赖:

<!--FiSCO依赖-->
<dependency>
    <groupId>org.fisco-bcos.java-sdk</groupId>
    <artifactId>fisco-bcos-java-sdk</artifactId>
    <version>2.9.1</version>
</dependency>

创建测试类:

package com.ruoyi.fisco;

import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.config.Config;
import org.fisco.bcos.sdk.config.ConfigOption;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor;
import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: liuchang
 * @CreateTime: 2024-03-17  11:07
 * @Description: TODO
 * @Version: 1.0
 */
public class RecordTest {
    public final String configFile = "src/main/resources/config-example.toml";

    @Test
    public void testAddRecord() throws Exception {
        ConfigOption configOption = Config.load(configFile);
        // 初始化BcosSDK对象
        BcosSDK sdk = new BcosSDK(configOption);
        // 获取Client对象,此处传入的群组ID为1
        Client client = sdk.getClient(Integer.valueOf(1));
        // 构造AssembleTransactionProcessor对象,需要传入client对象,CryptoKeyPair对象和abi、binary文件存放的路径。abi和binary文件需要在上一步复制到定义的文件夹中。
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();

        AssembleTransactionProcessor transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, "src/main/resources/abi/", "src/main/resources/bin");


        String recordid = "2";
        String description = "{\"name\": \"张三\", \"age\": 24, \"gender\": true}";
        String remark = "2024年3月17 11.22";

        // 创建调用交易函数的参数,此处为传入一个参数
        List<Object> params = new ArrayList<>();
        params.add(recordid);
        params.add(description);
        params.add(remark);
        // 调用HelloWorld合约,合约地址为helloWorldAddress, 调用函数名为『set』,函数参数类型为params
        TransactionResponse transactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("Record", "0x34a9d8a36b69c3a7a9b0fd373385b26886dc8c22", "insert", params);
        List<Object> returnValues = transactionResponse.getReturnObject();
        if (returnValues != null) {
            for (Object value : returnValues) {
                System.out.println("主键返回值:"+value.toString());
            }
        }
    }

    @Test
    public void testSelectRecord() throws Exception {
        ConfigOption configOption = Config.load(configFile);
        // 初始化BcosSDK对象
        BcosSDK sdk = new BcosSDK(configOption);
        // 获取Client对象,此处传入的群组ID为1
        Client client = sdk.getClient(Integer.valueOf(1));
        // 构造AssembleTransactionProcessor对象,需要传入client对象,CryptoKeyPair对象和abi、binary文件存放的路径。abi和binary文件需要在上一步复制到定义的文件夹中。
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();

        AssembleTransactionProcessor transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, "src/main/resources/abi/", "src/main/resources/bin");


        String recordid = "2";
        // 创建调用交易函数的参数,此处为传入一个参数
        List<Object> params = new ArrayList<>();
        params.add(recordid);
        // 调用HelloWorld合约,合约地址为helloWorldAddress, 调用函数名为『set』,函数参数类型为params
        TransactionResponse transactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("Record", "0x34a9d8a36b69c3a7a9b0fd373385b26886dc8c22", "getResult", params);
        List<Object> returnValues = transactionResponse.getReturnObject();
        if (returnValues != null) {
            for (Object value : returnValues) {
                System.out.println("主键返回值:"+value.toString());
            }
        }
    }

    @Test
    public void testUpdateRecord() throws Exception {
        ConfigOption configOption = Config.load(configFile);
        // 初始化BcosSDK对象
        BcosSDK sdk = new BcosSDK(configOption);
        // 获取Client对象,此处传入的群组ID为1
        Client client = sdk.getClient(Integer.valueOf(1));
        // 构造AssembleTransactionProcessor对象,需要传入client对象,CryptoKeyPair对象和abi、binary文件存放的路径。abi和binary文件需要在上一步复制到定义的文件夹中。
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();

        AssembleTransactionProcessor transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, "src/main/resources/abi/", "src/main/resources/bin");


        String recordid = "2";
        String description = "{\"name\": \"张三\", \"age\": 24, \"gender\": true}";
        String remark = "2024年3月17 14:26";

        // 创建调用交易函数的参数,此处为传入一个参数
        List<Object> params = new ArrayList<>();
        params.add(recordid);
        params.add(description);
        params.add(remark);
        // 调用HelloWorld合约,合约地址为helloWorldAddress, 调用函数名为『set』,函数参数类型为params
        TransactionResponse transactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("Record", "0x34a9d8a36b69c3a7a9b0fd373385b26886dc8c22", "update", params);
        List<Object> returnValues = transactionResponse.getReturnObject();
        if (returnValues != null) {
            for (Object value : returnValues) {
                System.out.println("主键返回值:"+value.toString());
            }
        }
    }

}

测试查询:

image-20240317114140676

测试更改:

image-20240317142811197

image-20240317142847757

测试查询:

image-20240317142928606

0

评论

博主关闭了所有页面的评论