6. 数据迁移工具

6.1. 迁移工具设计原理

6.1.1. 迁移工具的目的

迁移工具可以解决的业务需求场景:

  1. 由于业务需求,想要将当前的区块链系统替换为新的区块链系统,同时保留当前区块链系统的原始区块数据,比如

    • Fabric –> Chainmaker

  2. 当前区块链系统无法满足业务需求,想要升级当前区块链系统的版本,但是区块链系统新旧版本之间的区块、读写集等数据结构不兼容,比如

    • Chainmaker 1.x –> Chainmaker 2.x

6.1.2. 迁移方案设计思路

区块链迁移的最直观的想法,就是将不同区块链系统的区块结构体不同字段直接进行赋值,比如chainmaker1.x迁移到chainmaker2.x,将chainmaker1.x的区块重要字段直接赋值给chainmaker2.x的区块,有了chainmaker2.x的区块,给到chainamker2.x的存储模块,直接启动chainmaker2.x的链就可以了

  1. 获取源链的区块:

    • 通过存储模块的方式获取区块,比如拉取chainamaker1.x的区块,transfer-tool通过1.x的存储模块拉取1.x的区块,1.x链的data目录和transfer-tool部署到同一个环境

    • 通过sdk方式获取区块,比如拉取fabric的区块,迁移工具通过fabric-sdk拉取fabric的区块

  2. 将源链区块转换为目标链区块:比如将chainmaker 1.x的区块转换为chainmaker 2.x的区块,区块就是一个结构体,先获得chainmaker 1.x的区块结构体,然后赋值给chainmaker 2.x的区块结构体

  3. 根据生成的目标链区块,启动目标链,将chainmaker2.x的区块放到chainmaker 2.x的链存储目录,并启动chainamker2.x

  4. 目标链chainmaker2.x 只启动一个共识节点,如果后续想增加共识节点,等迁移完成后,可通过配置交易动态增加共识节点

6.1.3. 迁移方案中存在的问题及解决方案

6.1.3.1. 问题1:考虑到同步节点同步区块时,会遇到读写集验证的问题

同步节点在同步共识节点区块的时候,会验证区块,在虚拟机中执行交易的合约,生成读写集,跟共识节点区块头的读写集hash进行对比来验证交易是否被正确执行,如果chainmaker区块中的每笔交易都执行源链的业务合约逻辑会很浪费时间,同时还需要解析源链的合约在chainmaker2.x上执行,可能会不兼容,因此这种方案实现难度大,不太合理

  • 解决方案:换一种思路,不管源链的业务逻辑多复杂,最终业务合约的执行结果在区块链中的表现形式都是kv形式的读写集,因此想到chainmaker2.x的合约不执行源链的业务逻辑,而是将源链的交易读写集直接赋值给chainmaker 2.x区块中交易的读写集

6.1.3.2. 问题2: 考虑交易中存在跨合约调用时的优化

  • 初始方案:比如交易tx1的合约a跨合约调用合约b,a合约中需要判断是否存在跨合约调用,如果存在,跨合约调用b,如果b合约也存在跨合约调用c合约,b合约也需要判断,a、b合约的逻辑相同,都是transfer合约,初始方案的缺点:transfer合约内需要加判断,解决多层次跨合约调用的问题,transfer合约逻辑设计复杂

  • 优化方案:所有调用用户合约的交易,都调用assist合约,由assist合约遍历交易的读写集的合约名,根据不同合约名,分别进行跨合约调用不同的用户合约,不同的用户合约逻辑都相同,都是transfer合约的逻辑,优化方案的优点: 1.由assist合约统一跨合约调用所有transfer合约,transfer合约不再进行跨合约调用,解决了transfer合约内多层次跨合约调用的问题; 2.所有迁移交易都统一调用assist合约,交易中包含assist合约,方便用户区分一笔交易是否是迁移交易

  • 本迁移工具采用优化方案,对交易中存在的跨合约调用场景进行了优化

6.1.4. 迁移方案整体流程图

6.1.5. 迁移工具的核心模块:区块转换实现逻辑

将源链(fabric/chainmaker1.x)的区块转换为目标链chainmaker2.x的区块流程:

  1. chainmaker 2.x的block0

    新链的创始块必须由bc.yml自动生成的,因为新增节点的创世块也是由bc.yml生成的,如果创世块不相同,新节点无法启动

  2. chainmaker 2.x的block1

    1. tx1:创建短证书交易(使用证书的hash代笔证书,降低交易大小)

      • txId:源链没有对应的txid,根据uuid生成

      • 读写集:调用短证书的系统合约相关逻辑,生成对应读写集

    2. tx2:创建迁移辅助合约交易

      • txId:源链没有对应的txid,根据uuid生成

      • 读写集:调用安装合约的系统合约逻辑,生成对应读写集

    3. tx3:来源于源链的block1.txs

      1. 源链的tx如果是用户合约安装的交易

        • 转换成chainmaker2.x相对应的用户合约安装:合约名源链的合约名,合约的内容transfer合约内容,就是写了一个transfer合约,然后重命名成各种用户合约,被安装了n份

      2. 源链的tx如果是系统合约相关交易,比如节点、组织数量、创建短证书等交易

        • 转换为chainmaker2.x 特殊的交易:对源链的原始交易内容序列化,作为2.x交易的kv存起来

      3. 源链的tx如果是正常调用用户合约的交易

        • 转换为chainmaker 2.x相对应的assist合约调用类型的交易:调用的合约名是迁移辅助合约assist,2.x交易的kv保存序列化后的源链的原始的交易和原始读写集,assist合约将1.x原始读写集转换为map,对读写集进行分类,map的key:1.x用户合约名usercontract,value:1.x业务读写集kv,然后根据用户合约名usercontract,跨合约调用该用户合约(合约内容为transfer合约,transfer合约的逻辑,将1.x交易的业务读写集,更新到对应的2.x交易的业务读写集)

    4. tx4:序列化源链的genesisblock.tx1作为chainamker2.x的tx4的kv

  3. chainmaker 2.x的block2、block3、block4 …的处理逻辑,与block1 tx3的处理逻辑相同

6.1.6. 迁移工具设计原理图

6.2. 产品工具迁移

6.2.1. 支持类型

  1. fabric到chainmaker

    • 源链:fabric:1.4.x

    • 目标链:chainmaker:v2.2.1

6.2.2. 迁移工具源链: Fabric

  1. 源链Fabric的版本1.4

  2. 源链示例:比如使用脚本启动一条源链Fabric 1.4.3

    • 使用脚本byfn.sh 快速启动一个Fabric网络

    • channel name是mychannel

    • 源链的证书路径

    fabric/scripts/fabric-samples/first-network/crypto-config
    

6.2.3. 迁移工具目标链Chainmaker 2.x

  1. 目标链Chainmaker的版本:2.2.1

  2. 启动目标链Chainmaker

    • 使用脚本prepare.sh 启动一个共识节点

  3. 目标链Chainmaker证书文件路径

    chainmaker-go/build/release/chainmaker-v2.2.0-wx-org.chainmaker.org/config/wx-org.chainmaker.org
    

6.2.4. 迁移工具产品安装部署

6.2.4.1. 迁移工具产品前端部署

  1. 源码地址

    https://git.chainmaker.org.cn/chainmaker/transfer-front
    
  2. 进入到服务器任意文件里面 执行

    git clone https://git.chainmaker.org.cn/chainmaker/transfer-front
    
  3. 进入migration-web/public/config.js里面,将 http://192.168.0.173:12091 改成自己服务器ip

  4. 退回到migration-web 目录下执行

    docker build -t chainmaker/migration-web:v2.2.0 -f ./Dockerfile .
    
  5. 执行成功

  6. 找个端口号,比如:8000,查看是否被占用

    lsof -i:8000
    
  7. 启动前端docker容器

     docker run --rm --name migration-web -p 8000:80 -d chainmaker/migration-web:v2.2.0
    
  8. 浏览器打开即可

6.2.4.2. 迁移工具产品后端部署

  1. 下载迁移工具产品transfer-web-server的源代码

    #项目网址
    https://git.chainmaker.org.cn/chainmaker/transfer-web-server
    
    #代码分支
    master
    
    #拉取代码
    git clone git@git.chainmaker.org.cn:chainmaker/transfer-web-server.git
    
  2. 编译源代码,生成迁移工具产品可执行文件transfer-web-server

    go build
    
  3. 运行迁移工具产品

    nohup ./transfer-web-server &
    
  4. 查看日志

    vim nohup.out
    vim default.log
    
  5. swagger接口文档 http://服务器ip:12091/swagger/index.html#/

6.2.5. 迁移工具产品使用文档

6.2.5.1. 前端网页地址

http://服务器ip:8000/#/home

6.2.5.2. 新增任务

  1. 任务名称:自定义任务名称

  2. 任务类型:

    • Fabric1.4 to chainmaker 2.2.1

    • chainmaker1.x to chainmaker 2.2.1(暂不支持)

  3. 迁移高度:根据源链的区块高度自定义迁移高度

6.2.5.3. 迁移链信息设置

  1. 迁移链为Fabric

    • 链ID: Fabric的channel名

    • 用户名称:可以访问源链Fabric的用户名

    • 用户证书:可以访问源链Fabric的用户证书,要求必须是zip压缩格式,并且必须在linux环境进行文件压缩,linux环境下zip文件的压缩/解压命令如下:

       //压缩
       zip -r crypto-config.zip crypto-config
       //解压
       unzip crypto-config.zip
      
    • config文件:源链Fabric的sdk配置文件,要求必须是yml格式

    • fabric_sdk_config.yml文件适配,需要更改其中所有的证书路径为标准的证书路径

        ./config_path/迁移任务task_id/origin/用户证书目录
      
    • 为了方便起见,第一次更改为标准证书路径后,对于不同的迁移任务,只需要替换task_id就可以

6.2.5.4. 目标链信息设置

  1. 证书类型:根据目标链chainmaker的证书类型设置

  2. 组织ID:根据目标链chainmaker的组织ID设置

  3. 文件上传:上传目标链chainmaker的证书文件,要求必须为zip格式

  4. wx-org.chainmaker.org.zip文件中,更改chainmaker.yml、bc1.yml文件中的证书路径为标准路径格式,方便迁移工具后端根据task_id管理目标链的证书

  • chainmaker.yml配置文件,存储模块路径修改,为了方便起见,第一次更改为标准证书路径后,对于不同的迁移任务,只需要替换task_id就可以

    ./config_path/迁移任务task_id/target/目标链chainmaker证书目录
    
  • bc1.yml配置文件,证书路径修改,为了方便起见,第一次更改为标准证书路径后,对于不同的迁移任务,只需要替换task_id就可以

    ./config_path/迁移任务task_id/target/目标链chainmaker证书目录
    

6.2.5.5. 执行迁移

  1. 点击开始迁移即可执行迁移任务,迁移完成后,会自动更改迁移状态为迁移完成

  2. 迁移成功后,得到的目标链区块数据data目录

    ./config_path/迁移任务task_id/data
    

6.2.6. 启动目标链并验证是否迁移成功

  1. 将目标链原有的data、log目录删除

    cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org
    rm -rf data
    
  2. 将迁移完成后得到的目标链区块数据data目录,拷贝到chainmaker2.2.1的节点的主目录下

  3. 启动目标链chainmaker的节点

    cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org/bin
    sh start.sh
    
  4. 验证迁移工具是否迁移成功

  5. 通过cmc查看目标链的区块信息

  6. 给目标链添加一个同步节点,通过日志或cmc工具查看同步节点是否成功同步目标链的区块

    • 查询某高度的区块、读写集信息

    • 查出来的读写集的kv,需要用base64解码

    ./cmc query block-by-height 4 \
    --chain-id=chain1 \
    --sdk-conf-path=./testdata/sdk_config.yml
    
  7. 升级目标链上迁移过来的合约,查看是否能够升级成功,并通过目标链上的升级合约操作读写集,查看是否与原链读写集相匹配

6.3. 命令行工具迁移

6.3.1. 支持类型

  1. fabric到chainmaker

    • 源链:fabric:1.4.x

    • 目标链:chainmaker:v2.2.1

  2. chainmaker1.x到chainmaker2.x

    • 源链:chainmaker: v1.1.0、v1.2.x

    • 目标链:chainmaker:v2.2.1

6.3.2. fabric到chainmaker

迁移工具使用流程如下:

  1. 配置迁移工具源链信息

  2. 创建迁移工具目标链

  3. 配置迁移工具目标链

  4. 配置迁移工具合约文件

  5. 启动迁移工具

  6. 启动目标链

6.3.2.1. 配置迁移工具源链信息

  1. 源链:Fabric

  2. fabric的迁移高度,0代表迁移到源链的最新高度

  3. fabric迁移到chainamker,获取fabric的区块只支持通过fabric-sdk来获取

  4. config.yml配置文件

    # 迁移源链信息
    origin_chain:
       transfer_height: 100
       fabric:
          chain_name: "ltzxinchain"   #迁移channel
          user_name: "Admin"  #"User1"
          config_path: "./config_path/dev/chainmaker.yml" #"./config_path/dev/config_test_endpoints.yaml"  # fabric sdk config file path
          peers:
            - peer0
            - peer1
    

6.3.2.2. 创建迁移工具目标链

  1. 目标链初次启动时,chainmaker2.x 目标链的时的要求如下,注意:目标链初次启动时,必须为1个节点,所有迁移区块只需要一个共识节点来处理,这样可以降低迁移工具共识部分处理逻辑,后续迁移成功后,目标链可以通过发交易的方式新增共识节点

  • 版本:: v2.2.1

  • 节点数:1

  • 共识类型:TBFT

  • vm 类型:需要支持docker-go

  1. 创建一个示例chainmaker2.x目标链,操作步骤如下

    # 1.使用chainmaker脚本部署、编译、启动一条chainmaker2.x的目标链
    cd chainmaker-go/scripts
    sh prepare.sh 1 1
    
    sh build_release.sh
    
    sh cluster_quick_start.sh
    
    # 2.停止目标链
    sh cluster_quick_stop.sh
    
    # 3.删除目标链的data目录,后续替换为迁移工具生成的迁移数据,再启动目标链,即可得到一条拥有源链区块数据的目标链
    cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org
    rm -rf data log
    

6.3.2.3. 配置迁移工具目标链

  1. fabric迁移到chainamker只支持证书模式,目标链chainmaker2.x 使用新生成的证书

  2. 在迁移工具config.yml中,配置目标链的创世块配置

    genesis: "./config_path/dev/bc1.yml"
    

6.3.2.4. 配置迁移工具合约文件

  1. 目录:chainmaker-transfer-tool/config_path/contract

  2. 需要配置的两个合约文件

    • assist.7z

    • transfer

  3. 源链为fabric,合约文件目录

    chainmaker-transfer-tool/config_path/contract-fabric
    

6.3.2.5. 启动迁移工具

  1. 启动迁移工具的流程

    #进入命令行迁移工具 
    cd chainmaker-transfer-tool
    
    #编译
    go build
    
    #启动
    ./transfer-tool
    

6.3.2.6. 启动目标链

  1. 将迁移工具生成的区块链数据datav2,重命名为data,复制到目标链的工作目录

    # 进入命令行迁移工具主目录
    cd chainmaker-transfer-tool
    
    #重命名
    mv datav2 data
    
    #目标链存放data的目录
    chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org
    
  2. 启动目标链

    #目标链存放data的目录
    cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org/bin
    
    #启动目标链
    ./start.sh
    
  3. 验证迁移是否成功,可以给共识节点添加一个同步节点,如果同步节点能正常同步区块,证明迁移成功

  4. 如果想新增共识节点,可以通过发交易的方式新增共识节点的数量

6.3.3. chainmaker1.x到chainmaker2.x

迁移工具使用流程如下:

  1. 配置迁移工具源链信息

  2. 创建迁移工具目标链

  3. 配置迁移工具目标链

  4. 配置迁移工具合约文件

  5. 启动迁移工具

  6. 启动目标链

6.3.3.1. 配置迁移工具源链信息

  1. 源链:Chainmaker 1.x,如果源链版本为v1.1.0,需要单独version配置项:v1.1.0

  2. 迁移高度:0代表迁移到源链的最新高度

  3. 迁移工具支持两种方式

    • chainmaker-sdk,配置好chainmaker-sdk的配置文件:sdk_config.yml

    • 源链的存储模块(v1.2.6版本),支持拉取chainmaker1.x所有版本的链,需要将chainmaker1.x源链的data目录复制到transfer工具的同级目录

  4. config.yml配置文件

    # 迁移源链信息
    origin_chain:
       transfer_height: 0
       chain_type: "chainmaker"
       chain_version: "v1.1.0"
    

6.3.3.2. 创建迁移工具目标链

  1. 目标链初次启动时,chainmaker2.x 目标链的时的要求如下,注意:目标链初次启动时,必须为1个节点,所有迁移区块只需要一个共识节点来处理,这样可以降低迁移工具共识部分处理逻辑,后续迁移成功后,目标链可以通过发交易的方式新增共识节点

  • 版本:: v2.2.1

  • 节点数:1

  • 共识类型:TBFT

  • vm 类型:需要支持docker-go

  1. 创建一个示例chainmaker2.x目标链,操作步骤如下

    # 1.使用chainmaker脚本部署、编译、启动一条chainmaker2.x的目标链
    cd chainmaker-go/scripts
    sh prepare.sh 1 1
    
    sh build_release.sh
    
    sh cluster_quick_start.sh
    
    # 2.停止目标链
    sh cluster_quick_stop.sh
    
    # 3.删除目标链的data目录,后续替换为迁移工具生成的迁移数据,再启动目标链,即可得到一条拥有源链区块数据的目标链
    cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org
    rm -rf data log
    

6.3.3.3. 配置迁移工具目标链

  1. 确定目标链是证书模式还是公钥模式

  2. 如果是证书模式,需要判断:

  • 目标链使用源链的证书

  • 目标链使用新生成的证书

  1. 如果目标链使用源链的证书,复制创建的目标链的配置文件,给到迁移工具

    • 目标链证书路径:chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org/config/wx-org.chainmaker.org

    • 迁移工具存放目标链证书的路径:chainmaker-transfer-tool/config_path

  2. 源链证书定义了共识节点的id和组织名,因此目标链的配置文件chainmaker.yml和bc1.yml,也要使用源链的配置文件中相同的共识节点id和组织,目标链的配置文件更改:

    • 迁移工具中,目标链的bc1.yml需要更改根证书的位置

      # Trust roots is used to specify the organizations' root certificates in permessionedWithCert mode.
      # When in permessionedWithKey mode or public mode, it represents the admin users.
      trust_roots:
      # org id and root file path list.
      - org_id: "wx-org1.chainmaker.org"
          root:
            - "./config_path/wx-org1.chainmaker.org/certs/ca/wx-org1.chainmaker.org/ca.crt"
      
  3. 在迁移工具config.yml中,配置目标链的创世块配置

    genesis: "./config_path/dev/bc1.yml"
    

6.3.3.4. 配置迁移工具合约文件

  1. 目录:chainmaker-transfer-tool/config_path/contract

  2. 需要配置的两个合约文件

    • assist.7z

    • transfer

  3. 源链为chainmaker1.x,合约文件目录

    chainmaker-transfer-tool/config_path/contract-cm
    

6.3.3.5. 启动迁移工具

  1. 编译、启动迁移工具的流程

    # 进入命令行迁移工具主目录
    cd chainmaker-transfer-tool
    
    #编译
    go build
    
    #启动
    ./transfer-tool
    
  2. 迁移完成后,生成的目标链区块数据位于迁移工具主目录:chainmaker-transfer-tool/datav2

6.3.3.6. 启动目标链

  1. 将迁移工具生成的区块链数据datav2,重命名为data,复制到目标链的工作目录

    # 进入命令行迁移工具主目录
    cd chainmaker-transfer-tool
    
    #重命名
    mv datav2 data
    
    #目标链存放data的目录
    chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org
    
  2. 启动目标链

    #目标链存放data的目录
    cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org/bin
    
    #启动目标链
    ./start.sh
    
  3. 验证迁移是否成功,可以给共识节点添加一个同步节点,如果同步节点能正常同步区块,证明迁移成功

  4. 如果想新增共识节点,可以通过发交易的方式新增共识节点的数量