10. 可验证数据库使用文档

10.1. 概述

链下可验证数据库是长安链可扩展性项目的一部分,主要通过Merkle B+树实现链下SQL数据存储和长安链的链上验证。链下可验证数据库是独立的存储引擎,支持MySQL生态工具。

本文档主要介绍链下可验证数据库及配套合约的部署和使用方式,便于用户快速上手使用。

开发文档,暨存储引擎的源码编译和测试文档,请参考开发文档

配套的智能合约文档,请参考合约使用文档

技术文档请参考技术文档

项目代码地址:https://git.chainmaker.org.cn/ibpc/verifiable-database

10.2. 快速开始

10.2.1. 安装准备

  1. 安装长安链所需依赖:go, 7zip, docker

    安装go 1.19.9
    参考:https://golang.google.cn/doc/install

    wget https://golang.google.cn/dl/go1.19.9.linux-amd64.tar.gz
    sudo tar -C /usr/local -xzf go1.19.9.linux-amd64.tar.gz
    export PATH=$PATH:/usr/local/go/bin
    go version
    

    国内需配置Go代理

    go env -w GO111MODULE=on
    go env -w GOPROXY=goproxy.cn
    

    安装7zip

    sudo yum -y install epel-release
    sudo yum -y install p7zip p7zip-plugins
    

    安装docker

    sudo yum -y install yum-utils
    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    sudo yum -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    sudo systemctl start docker
    sudo docker run hello-world
    
  2. 安装长安链v2.3.1,参考官方文档

注:此工具兼容长安链版本v2.3.1

  1. 启动长安链Docker VM相关组件,参考官方文档

10.2.2. 安装方法

推荐使用Mysql插件模式安装和使用,也可直接通过mbt_store独立模式使用,但独立模式不支持SQL语句。

  1. 安装Mysql

    下载Mysql 5.7.30社区版

    https://downloads.mysql.com/archives/community/
    Product Version: 5.7.30
    Operating System: Linux - Generic
    OS Version: Linux - Generic (glibc 2.12) (x86, 64-bit)

    wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.30-linux-glibc2.12-x86_64.tar.gz
    tar zxvf mysql-5.7.30-linux-glibc2.12-x86_64.tar.gz
    sudo cp -r mysql-5.7.30-linux-glibc2.12-x86_64 /usr/local/mysql
    

    安装Mysql依赖并创建用户

    sudo yum install -y libaio
    sudo groupadd -g 315 mysql  
    sudo useradd -u 315 -g mysql -d /var/lib/mysql -M mysql
    

    修改/etc/my.cnf,参考:

    [mysqld]
    bind-address=0.0.0.0
    port=3306
    user=mysql
    basedir=/usr/local/mysql
    datadir=/data/mysql
    socket=/tmp/mysql.sock
    
    [mysqld_safe]
    log-error=/var/log/mysql/mysql.err
    pid-file=/var/log/mysql/mysql.pid
    
    #
    # include all files from the config directory
    #
    !includedir /etc/my.cnf.d
    

    根据/etc/my.cnf创建必要目录和文件

    sudo mkdir /var/log/mysql
    sudo touch /var/log/mysql/mysql.err
    sudo touch /var/log/mysql/mysql.pid
    sudo chown -R mysql:mysql /var/log/mysql/
    sudo mkdir -p /data/mysql
    sudo chown -R mysql:mysql /data/mysql/
    
  2. 复制本项目插件到Mysql插件目录并创建必要目录

    sudo cp ha_mbtree.so /usr/local/mysql/lib/plugin
    sudo chmod 755 /usr/local/mysql/lib/plugin/ha_mbtree.so
    sudo mkdir -p /data/chainmaker_mbt/mbt_store_data/mbt_db_files
    sudo mkdir -p /data/chainmaker_mbt/merkle_proofs
    sudo mkdir -p /data/chainmaker_mbt/search_results
    sudo chown -R $USER:$(groups) /data/chainmaker_mbt/
    
  3. /usr/local/mysql/bin/目录启动Mysql并加载本项目插件

    sudo ./mysqld --initialize --user=mysql
    sudo ./mysqld_safe --user=mysql
    ./mysql -uroot -p
    mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
    mysql> INSTALL PLUGIN mbtree SONAME 'ha_mbtree.so';
    mysql> SHOW PLUGINS;
    
  4. 安装OpenSSL 1.1.1n

    • openssl的版本应为1.1.1n

    • 手动安装(推荐)

    wget https://www.openssl.org/source/old/1.1.1/openssl-1.1.1n.tar.gz
    
    tar -zxvf openssl-1.1.1n.tar.gz
    cd openssl-1.1.1n
    
    ./config --prefix=/usr/local/openssl
    
    ./config -t
    
    make & sudo make install
    
    sudo mv /usr/bin/openssl /usr/bin/openssl.bak
    sudo mv /usr/include/openssl /usr/include/openssl.bak
    
    sudo ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl
    sudo ln -s /usr/local/openssl/include/openssl /usr/include/openssl
    
    sudo echo "/usr/local/openssl/lib" >> /etc/ld.so.conf
    sudo ldconfig -v
    
    sudo ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so.1.1
    sudo ln -s /usr/local/openssl/lib/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1
    
    sudo ln -sf /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so
    sudo ln -sf /usr/local/openssl/lib/libcrypto.so.1.1 /usr/lib64/libcrypto.so
    
    openssl version
    

10.2.3. 使用方法

本部分演示使用SQL语句纯链下插入查询数据和使用智能合约链上链下协同插入查询数据两种方式。

  1. 使用SQL语句插入和查询数据

    mysql> CREATE DATABASE IF NOT EXISTS test_db;
    mysql> USE test_db;
    mysql> CREATE TABLE IF NOT EXISTS test_tb (id INT not null, num INT not null, PRIMARY KEY ( id ) ) ENGINE=MBTREE;
    mysql> INSERT INTO test_tb (id, num) VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6,6), (7, 7), (8,8), (9, 9), (10, 10), (11, 11), (12, 12), (13, 13), (14, 14), (15, 15), (16, 16), (17, 17), (18, 18), (19, 19), (20, 20);
    mysql> SELECT id,num FROM test_tb WHERE id >=18 and id <= 22;
    
  2. 部署长安链智能合约

    创建chainmaker-go/tools/cmc/testdata/VerifiableDB目录并将VerifiableDB.go智能合约移动到该目录下,编译智能合约,编译过程中可能需要根据提示go get依赖包

    go build -ldflags="-s -w" -o VerifiableDB
    7z a VerifiableDB VerifiableDB
    

    返回cmc目录,运行以下命令部署智能合约

    ./cmc client contract user create \
    --contract-name=VerifiableDB \
    --runtime-type=DOCKER_GO \
    --byte-code-path=./testdata/VerifiableDB/VerifiableDB.7z \
    --version=1.0 \
    --sdk-conf-path=./testdata/sdk_config.yml \
    --admin-key-file-paths=./testdata/crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.sign.key,./testdata/crypto-config/wx-org2.chainmaker.org/user/admin1/admin1.sign.key,./testdata/crypto-config/wx-org3.chainmaker.org/user/admin1/admin1.sign.key \
    --admin-crt-file-paths=./testdata/crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.sign.crt,./testdata/crypto-config/wx-org2.chainmaker.org/user/admin1/admin1.sign.crt,./testdata/crypto-config/wx-org3.chainmaker.org/user/admin1/admin1.sign.crt \
    --sync-result=true \
    --params="{}"
    
  3. 上传Merkle根到长安链智能合约

    使用mbt_store生成Merkle根,table_path为MySQL数据库中数据库文件位置,后缀为mb,mbt_store中Insert data命令在和插件同时使用时构成链下数据库时不能使用。

    sudo ./mbt_store
    Tables loaded from TXT file: /home/chainmaker_mbt/mbstore_data/config.txt
    1. Create table
    2. Import table
    3. Insert data
    4. Query data
    5. Verify Merkle proof
    6. Duplicate table
    7. Exit
    Enter your choice: 2
    Enter table name:__test_tb
    Enter table version:__1
    Enter table path (if imported enter NULL):__/data/mysql/test_db/test_tb.mb
    Table root hash file: /data/chainmaker_mbt/merkle_proofs/test_tb-1.hash
    Table imported and opened
    

    调用智能合约上传Table root hash file中的Merkle根

    ./cmc client contract user invoke \
    --contract-name=VerifiableDB \
    --method=update_offchain_status \
    --sdk-conf-path=./testdata/sdk_config.yml \
    --params="{\"Time\":\"1\",\"Table\":\"test_tb\",\"Hash\":\"$(cat /data/chainmaker_mbt/merkle_proofs/test_tb-1.hash)\"}" \
    --sync-result=true 
    
  4. 链上查询数据

    使用长安链客户端调用合约,使用merkle1版本查询id>=18且id<=22的数据,执行以下命令:

    ./cmc client contract user invoke \
    --contract-name=VerifiableDB \
    --method=search_from_offchain \
    --sdk-conf-path=./testdata/sdk_config.yml \
    --params="{\"Time\":\"1\",\"Table\":\"test_tb\",\"SK\":\"18\",\"EK\":\"22\",\"SSK\":\"NULL\",\"SEK\":\"NULL\"}" \
    --sync-result=true
    

    使用mbt_store在本地生成查询结果和Proof

    sudo ./mbt_store 
    Tables loaded from TXT file: /data/chainmaker_mbt/mbt_store_data/config.txt
    1. Create table
    2. Import table
    3. Insert data
    4. Query data
    5. Verify Merkle proof
    6. Duplicate table
    7. Exit
    Enter your choice: 2
    Enter table name:__test_tb
    Enter table version:__1
    Enter table path (if imported enter NULL):__/data/mysql/test_db/test_tb.mb
    Table root hash file: /data/chainmaker_mbt/merkle_proofs/test_tb-1.hash
    Table imported and opened
    1. Create table
    2. Import table
    3. Insert data
    4. Query data
    5. Verify Merkle proof
    6. Duplicate table
    7. Exit
    Enter your choice: 4
    Enter table name:__test_tb
    Enter table version:__1
    Enter query left value:__18
    Enter query right value:__22
    Search result: 
    [result]18 | 1200000012000000
    [result]19 | 1300000013000000
    [result]20 | 1400000014000000
    Range Merkle Proof saved at: /data/chainmaker_mbt/merkle_proofs/test_tb-1-18-22.rmkp
    Search result saved at: /data/chainmaker_mbt/search_results/test_tb-1-18-22.res
    

    订阅长安链上事件,contracts目录下已提供基础版本的订阅程序,如需通过其他合约调用或者其他程序调用可以参考subscribe.go实现。subscribe.go需先复制到SDK指定目录后再运行。

    cd ~
    git clone git@git.chainmaker.org.cn:chainmaker/sdk-go.git
    mkdir -p ~/sdk-go/examples/VerifiableDB
    cp subscribe.go ~/sdk-go/examples/VerifiableDB
    cp ~/chainmaker-go/tools/cmc/testdata/sdk_config.yml ~/sdk-go/examples/sdk_configs/sdk_config_org1_client1.yml
    cd ~/sdk-go/examples/VerifiableDB
    mkdir testdata
    cp -r ~/chainmaker-go/build/crypto-config/ ~/sdk-go/examples/VerifiableDB/testdata/
    go run subscribe.go
    

    使用长安链客户端调用合约,获取查询结果和验证结果

    ./cmc client contract user invoke \
    --contract-name=VerifiableDB \
    --method=get_status_and_result \
    --sdk-conf-path=./testdata/sdk_config.yml \
    --params="{\"SearchId\":\"1\"}" \
    --sync-result=true