# 可验证数据库开发文档 ## 概述 链下可验证数据库是长安链可扩展性项目的一部分,主要通过Merkle B+树实现链下SQL数据存储和链上验证。链下可验证数据库是独立的存储引擎,支持MySQL生态工具。 本文档主要介绍链下可验证数据库的代码结构以及源码编译和测试方法,便于开发者快速了解存储引擎的具体实现方式。 使用文档请参考[使用文档](./可验证数据库使用文档.md)。 配套的智能合约文档,请参考[合约使用文档](./可验证数据库样例合约使用文档.md)。 技术文档请参考[技术文档](../tech/可验证数据库技术文档.md)。 项目代码地址:[https://git.chainmaker.org.cn/ibpc/verifiable-database](https://git.chainmaker.org.cn/ibpc/verifiable-database) ## 代码结构 ``` │ bplus_tree.h # 数据结构 | bplus_tree.cc # 数据结构 │ CMakeLists.txt # CMackLists │ file_manager.cc # 与文件系统交互 │ file_manager.h # 与文件系统交互 │ ha_mbtree.cc # MySQL插件接口 │ ha_mbtree.h # MySQL插件接口 │ mbt_key.cc # 索引类型 │ mbt_key.h # 索引类型 │ predefined.cc # 基础类和函数 │ predefined.h # 基础类和函数 │ README.md # 项目说明 │ tree_node.h # 树节点类 └─contracts # 智能合约目录 ├─docs # 文档目录 └─tests # 测试文件目录 ``` ## 编译和测试 ### 概述 merkle b+tree可以单独进行编译,也可以集成在MySQL源码中进行编译。 - 独立编译 - 编译完成后作为一个动态链接库,然后通过在MySQL配置文件中指定路径,进行加载。 - 集成编译 - 将项目源码放在MySQL/storage目录下,然后编译MySQL完成后完成加载。 ### 依赖项下载配置 - wget - perl - gcc - gcc-c++ - unzip - cmake > 3.0 - ncurses-devel - psmisc #### 下载MySQL 此处编译不含本项目存储引擎,仅编译MySQL原有组件 ```bash wget https://github.com/mysql/mysql-server/archive/refs/tags/mysql-5.7.30.tar.gz tar xzvf mysql-5.7.30.tar.gz mv mysql-server-mysql-5.7.30 mysql-5.7.30 ``` #### 下载boost - boost库版本不能高于1.59 ``` wget https://downloads.mysql.com/archives/get/p/23/file/mysql-boost-5.7.30.tar.gz tar xzvf mysql-boost-5.7.30.tar.gz mv mysql-5.7.30/boost /usr/local ``` #### 下载编译openssl - openssl的版本应为1.1.1n - 手动安装(推荐) ``` wget --no-check-certificate 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 & make install mv /usr/bin/openssl /usr/bin/openssl.bak mv /usr/include/openssl /usr/include/openssl.bak ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl ln -s /usr/local/openssl/include/openssl /usr/include/openssl echo "/usr/local/openssl/lib" >> /etc/ld.so.conf ldconfig -v ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so.1.1 ln -s /usr/local/openssl/lib/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1 ln -sf /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so ln -sf /usr/local/openssl/lib/libcrypto.so.1.1 /usr/lib64/libcrypto.so ``` #### 下载编译dbug - dbug为MySQL内部的日志库 - 由于MySQL对dbug进行了一定的修改,因此在非插件模式变异种,无法直接链接MySQL的dbug库,所以需要下载一个原版dbug库,保证独立模式和单元模式的日志功能 - `$MySQL`为MySQL的源码目录,具体见后文 - source_downloads为MySQL的依赖库和源码的下载位置,本项目也使用这个文件夹,如果不存在请先创建 ```bash # https://github.com/jasperswallen/DBUG wget https://github.com/jasperswallen/DBUG/archive/refs/heads/master.zip unzip DBUG-master.zip mv DBUG-master dbug mv dbug mysql-5.7.30/source_downloads cd mysql-5.7.30/source_downloads/dbug mkdir bld cd bld cmake .. make ``` #### 下载编译googletest - googletest为本项目使用的的测试框架 - googletest使用1.8.0版本,和MySQL支持的版本一致,避免重复 - 安装方法 ```bash # https://github.com/google/googletest/tree/release-1.8.0 wget https://github.com/google/googletest/archive/refs/tags/release-1.8.0.zip unzip googletest-release-1.8.0.zip mv googletest-release-1.8.0 mysql-5.7.30/source_downloads/ cd mysql-5.7.30/source_downloads/googletest-release-1.8.0 # 仅需要用到googletest,不需要googlemock cd googletest mkdir bld cd bld cmake .. make ``` #### 编译MySQL ``` cd mysql-server-mysql-5.7.30 mkdir bld cd bld cmake .. -DDOWNLOAD_BOOST=1 -DWITH_BOOST=/usr/local/boost/ -DWITH_SSL=/usrl/local/openssl/ make ``` ### 依赖项配置 #### 下载项目源码 [项目源码链接](https://git.chainmaker.org.cn/ibpc/verifiable-database/-/releases)。下载最新的release版本源码的压缩包,例如,`verifiable-database-v1.2.0.zip`。然后解压缩并将目录重命名为`mbtree`,命令如下: ``` unzip verifiable-database-v1.2.0.zip mv verifiable-database-v1.2.0 mbtree ``` #### CMakelist.txt 本项目需要根据宿主机的环境对cmakelist.txt中配置项进行修改,需要修改项如下 - MYSQL_DIR: MySQL源码目录 - OPENSSL_ROOT_DIR: openssl安装目录(默认为/usr/local/openssl) #### mbt_store.cc mbt_store为独立模式下的程序入口,需要配置备份表文件和查询结果文件的存储路径 - data_dir_path: mbt_store数据文件路径,可任意指定 - config_path: 备份表管理文件路径,可任意指定 - db_file_dir_path: 备份表文件存储路径,不需要单独配置 - mkp_file_dir_path: 查询结果merkle proof存储路径,不需要单独配置 - search_result_file_dir_path: 查询结果存储路径,不需要单独配置 #### start.sh start.sh为项目测试启动脚本,需要配置以下参数 - build_path: mysql的编译目录,应为~/mysql-5.7.30/bld/ - basedir: mysql的数据库文件的存储目录,应置为/data/mysql_data/data/ - datadir: mysql的表文件存储目录,应为${basedir}data/,不需要单独配置 - mysqld_path: mysqld可执行文件路径,应为${build_path}sql/mysqld,不需要单独配置 - plugin_dir: 编译出的mbtree插件路径,应为${build_path}storage/${项目文件夹名}/,不需要单独配置 - mysqladmin_path: mysqladmin可执行文件路径,应为${build_path}client/mysqladmin,不需要单独配置 - mysql_path: mysql客户端可执行文件路径,应为${build_path}client/mysql,不需要单独配置 - init函数的--user参数置为当前用户 ``` cd mysql-5.7.30/bld make mysql make mysqladmin mkdir /data/mysql_data/data/ mkdir /data/mysql_data/share/ mv ~/mysql-5.7.30/bld/sql/share/english/errmsg.sys /data/mysql_data/share/ ``` #### test_mysql_client.py 本脚本为测试mysql插入和查询的脚本,需要安装pymysql库 #### test_mbtree_client.py 本脚本为测试mbt_store功能的脚本,需要安装pymysql库,并提前创建/data/chainmaker_mbt/mbt_store_data、/data/chainmaker_mbt/mbt_store_data/mbt_db_files、/data/chainmaker_mbt/mbt_store_data/merkle_proofs目录 - base_dir: mysql数据库文件根目录,应和start.sh中的basedir一致 - database_name: 和test_mysql_client中创建的数据库一致,为"test" - table_name: 和test_mysql_client中创建的表一致,为"user" - client_path: 应置为~/mysql-5.7.30/storage/mbtree/bld/mbt_store ### 编译 本项目为支持两种应用场景和单元测试,因此有三种编译模式,分别为插件模式、独立模式和单元测试模式。 #### 插件模式 插件模式会将mbtree编译成一个动态链接库,然后通过在MySQL配置文件中指定路径,进行加载。 步骤如下: 1. 将mbtree源码放在/MySQL/storage目录下 2. 如果mysql没有进行编译,执行依赖项下载中的MySQL部分命令,即可完成MySQL和mbtree插件的编译 3. 如果MySQL已经编译,只需要编译本项目插件,或是需要重新编译插件,在bld目录下运行以下命令: ``` cd mysql-5.7.30/bld cmake .. -DDOWNLOAD_BOOST=1 -DWITH_BOOST=/usr/local/boost/ -DWITH_SSL=/usr/local/openssl/ && make mbtree ``` #### 独立模式 独立模式目的是将本项目编译为mbt_store,作为一个独立的程序运行,不需要MySQL的支持,可管理备份表和查询结果 步骤如下: ``` cd mysql-5.7.30/storage/mbtree mkdir bld cd bld cmake .. -Dis_sole=ON && make ``` #### 单元测试 单元测试在四个文件中bpt_predefined-t.cc/bpt_node-t.cc/bpt_mkp-t.cc/bpt_tree-t.cc 步骤如下: 1. 进入本项目目录,创建目录bld 2. 进入bld目录下后,运行命令 `cmake .. -Din_dev=ON && make` 3. 在bld目录下存在bpt_predefined-t/bpt_node-t/bpt_mkp-t/bpt_tree-t可执行文件 ### 启动和使用 #### 插件模式 插件模式下,mbtree作为一个插件集成到MySQL中,可以通过MySQL的命令行或是SDK进行操作 - 注意事项 - mysql运行需要将errmsg.sys文件放在MySQL的数据目录的share目录下,否则会报错 - start.sh中run函数的debug参数在mysql不用调试模式编译时时不应当打开 - 启动步骤 - 初始化数据库 - 启动mysqld服务 - 链接mysql,启动mysql交互式命令行 - 使用SQL语句进行操作 - 使用start.sh脚本启动 - 脚本中包含了MySQL的启动、停止、初始化、重置密码、连接数据库等功能 - `./start.sh init`初始化数据库 - `./start.sh run`启动mysql - `./start.sh resetpassword`重置root密码为111111 - `./start.sh stop`停止mysql,并清空数据 - 更多的看start.sh的帮助 - 手动启动(与start.sh命令相同,参考start.sh脚本内容) - 使用方式 - 可参考test_mysql_client.py脚本,此脚本为测试插件模式下的插入和查询功能 - `python3 test_mysql_client.py 10 20`,可以插如200条数据,查询10到20范围的数据 #### 独立模式 独立模式下,mbt_store会管理多个备份数据表,可以通过命令行查询历史版本的数据 - 启动步骤 - 启动mbt_store - 使用open命令打开表 - 使用query命令查询数据 - 使用方式 - 具体可参考test_mbtree_client.py脚本,此脚本为测试独立模式下的导入表和查询功能 - `python3 test_mbtree_client.py 10 20`,查询被导入的表中10到20范围的数据,并生成merkle proof #### 单元测试 - 单元测试被编译为四个可执行文件,可直接在命令行运行 ### 集成测试 集成测试为模拟完整的可验证数据库使用流程,步骤为 1. 启动MySQL 2. 向MySQL中插入数据 3. 启动mbt_store,备份MySQL表 4. 查询备份表中数据,生成merkle proof 5. 重复2-3的过程 需要完成插件模式和独立模式的编译,然后运行`./start.sh test2`即可 ## 其他 ### 字段编码方式 当前支持int类型和string类型,编码方式如下 1. int类型占用4个字节 2. string类型,长度为固定长度20个字节,最后以'\0'结尾 使用mbt_store获取记录原始数据时,数据会被编码为hex字符串