8. 数据迁移工具
8.1. 迁移工具设计原理
8.1.1. 迁移工具的目的
迁移工具可以解决的业务需求场景:
由于业务需求,想要将当前的区块链系统替换为新的区块链系统,同时保留当前区块链系统的原始区块数据,比如
Fabric –> Chainmaker
当前区块链系统无法满足业务需求,想要升级当前区块链系统的版本,但是区块链系统新旧版本之间的区块、读写集等数据结构不兼容,比如
Chainmaker 1.x –> Chainmaker 2.x
8.1.2. 迁移方案设计思路
区块链迁移的最直观的想法,就是将不同区块链系统的区块结构体不同字段直接进行赋值,比如chainmaker1.x迁移到chainmaker2.x,将chainmaker1.x的区块重要字段直接赋值给chainmaker2.x的区块,有了chainmaker2.x的区块,给到chainamker2.x的存储模块,直接启动chainmaker2.x的链就可以了
获取源链的区块:
通过存储模块的方式获取区块,比如拉取chainamaker1.x的区块,transfer-tool通过1.x的存储模块拉取1.x的区块,1.x链的data目录和transfer-tool部署到同一个环境
通过sdk方式获取区块,比如拉取fabric的区块,迁移工具通过fabric-sdk拉取fabric的区块
将源链区块转换为目标链区块:比如将chainmaker 1.x的区块转换为chainmaker 2.x的区块,区块就是一个结构体,先获得chainmaker 1.x的区块结构体,然后赋值给chainmaker 2.x的区块结构体
根据生成的目标链区块,启动目标链,将chainmaker2.x的区块放到chainmaker 2.x的链存储目录,并启动chainamker2.x
目标链chainmaker2.x 只启动一个共识节点,如果后续想增加共识节点,等迁移完成后,可通过配置交易动态增加共识节点
8.1.3. 迁移方案中存在的问题及解决方案
8.1.3.1. 问题1:考虑到同步节点同步区块时,会遇到读写集验证的问题
同步节点在同步共识节点区块的时候,会验证区块,在虚拟机中执行交易的合约,生成读写集,跟共识节点区块头的读写集hash进行对比来验证交易是否被正确执行,如果chainmaker区块中的每笔交易都执行源链的业务合约逻辑会很浪费时间,同时还需要解析源链的合约在chainmaker2.x上执行,可能会不兼容,因此这种方案实现难度大,不太合理
解决方案:换一种思路,不管源链的业务逻辑多复杂,最终业务合约的执行结果在区块链中的表现形式都是kv形式的读写集,因此想到chainmaker2.x的合约不执行源链的业务逻辑,而是将源链的交易读写集直接赋值给chainmaker 2.x区块中交易的读写集
8.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合约,方便用户区分一笔交易是否是迁移交易
本迁移工具采用优化方案,对交易中存在的跨合约调用场景进行了优化
8.1.4. 迁移方案整体流程图
8.1.5. 迁移工具的核心模块:区块转换实现逻辑
将源链(fabric/chainmaker1.x)的区块转换为目标链chainmaker2.x的区块流程:
chainmaker 2.x的block0
新链的创始块必须由bc.yml自动生成的,因为新增节点的创世块也是由bc.yml生成的,如果创世块不相同,新节点无法启动
chainmaker 2.x的block1
tx1:创建短证书交易(使用证书的hash代笔证书,降低交易大小)
txId:源链没有对应的txid,根据uuid生成
读写集:调用短证书的系统合约相关逻辑,生成对应读写集
tx2:创建迁移辅助合约交易
txId:源链没有对应的txid,根据uuid生成
读写集:调用安装合约的系统合约逻辑,生成对应读写集
tx3:来源于源链的block1.txs
源链的tx如果是用户合约安装的交易
转换成chainmaker2.x相对应的用户合约安装:合约名源链的合约名,合约的内容transfer合约内容,就是写了一个transfer合约,然后重命名成各种用户合约,被安装了n份
源链的tx如果是系统合约相关交易,比如节点、组织数量、创建短证书等交易
转换为chainmaker2.x 特殊的交易:对源链的原始交易内容序列化,作为2.x交易的kv存起来
源链的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交易的业务读写集)
tx4:序列化源链的genesisblock.tx1作为chainamker2.x的tx4的kv
chainmaker 2.x的block2、block3、block4 …的处理逻辑,与block1 tx3的处理逻辑相同
8.1.6. 迁移工具设计原理图
8.2. 产品工具迁移
8.2.1. 支持类型
fabric到chainmaker
源链:fabric:1.4.x
目标链:chainmaker:v2.2.1
8.2.2. 迁移工具源链: Fabric
源链Fabric的版本1.4
源链示例:比如使用脚本启动一条源链Fabric 1.4.3
使用脚本byfn.sh 快速启动一个Fabric网络
channel name是mychannel
源链的证书路径
fabric/scripts/fabric-samples/first-network/crypto-config
8.2.3. 迁移工具目标链Chainmaker 2.x
目标链Chainmaker的版本:2.2.1
启动目标链Chainmaker
使用脚本prepare.sh 启动一个共识节点
目标链Chainmaker证书文件路径
chainmaker-go/build/release/chainmaker-v2.2.0-wx-org.chainmaker.org/config/wx-org.chainmaker.org
8.2.4. 迁移工具产品安装部署
8.2.4.1. 迁移工具产品前端部署
源码地址
https://git.chainmaker.org.cn/chainmaker/transfer-front
进入到服务器任意文件里面 执行
git clone --depth=1 https://git.chainmaker.org.cn/chainmaker/transfer-front
进入migration-web/public/config.js里面,将 http://192.168.0.173:12091 改成自己服务器ip
退回到migration-web 目录下执行
docker build -t chainmaker/migration-web:v2.2.0 -f ./Dockerfile .
执行成功
找个端口号,比如:8000,查看是否被占用
lsof -i:8000
启动前端docker容器
docker run --rm --name migration-web -p 8000:80 -d chainmaker/migration-web:v2.2.0
浏览器打开即可
8.2.4.2. 迁移工具产品后端部署
下载迁移工具产品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
编译源代码,生成迁移工具产品可执行文件transfer-web-server
go build
运行迁移工具产品
nohup ./transfer-web-server &
查看日志
vim nohup.out vim default.log
swagger接口文档 http://服务器ip:12091/swagger/index.html#/
8.2.5. 迁移工具产品使用文档
8.2.5.1. 前端网页地址
http://服务器ip:8000/#/home
8.2.5.2. 新增任务
任务名称:自定义任务名称
任务类型:
Fabric1.4 to chainmaker 2.2.1
chainmaker1.x to chainmaker 2.2.1(暂不支持)
迁移高度:根据源链的区块高度自定义迁移高度
8.2.5.3. 迁移链信息设置
迁移链为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就可以
8.2.5.4. 目标链信息设置
证书类型:根据目标链chainmaker的证书类型设置
组织ID:根据目标链chainmaker的组织ID设置
文件上传:上传目标链chainmaker的证书文件,要求必须为zip格式
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证书目录
8.2.5.5. 执行迁移
点击开始迁移即可执行迁移任务,迁移完成后,会自动更改迁移状态为迁移完成
迁移成功后,得到的目标链区块数据data目录
./config_path/迁移任务task_id/data
8.2.6. 启动目标链并验证是否迁移成功
将目标链原有的data、log目录删除
cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org rm -rf data
将迁移完成后得到的目标链区块数据data目录,拷贝到chainmaker2.2.1的节点的主目录下
启动目标链chainmaker的节点
cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org/bin sh start.sh
验证迁移工具是否迁移成功
通过cmc查看目标链的区块信息
给目标链添加一个同步节点,通过日志或cmc工具查看同步节点是否成功同步目标链的区块
查询某高度的区块、读写集信息
查出来的读写集的kv,需要用base64解码
./cmc query block-by-height 4 \ --chain-id=chain1 \ --sdk-conf-path=./testdata/sdk_config.yml
升级目标链上迁移过来的合约,查看是否能够升级成功,并通过目标链上的升级合约操作读写集,查看是否与原链读写集相匹配
8.3. 命令行工具迁移
8.3.1. 支持类型
fabric到chainmaker
源链:fabric:1.4.x
目标链:chainmaker:v2.2.1
chainmaker1.x到chainmaker2.x
源链:chainmaker: v1.1.0、v1.2.x
目标链:chainmaker:v2.2.1
8.3.2. fabric到chainmaker
迁移工具使用流程如下:
配置迁移工具源链信息
创建迁移工具目标链
配置迁移工具目标链
配置迁移工具合约文件
启动迁移工具
启动目标链
8.3.2.1. 配置迁移工具源链信息
源链:Fabric
fabric的迁移高度,0代表迁移到源链的最新高度
fabric迁移到chainamker,获取fabric的区块只支持通过fabric-sdk来获取
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
8.3.2.2. 创建迁移工具目标链
目标链初次启动时,chainmaker2.x 目标链的时的要求如下,注意:目标链初次启动时,必须为1个节点,所有迁移区块只需要一个共识节点来处理,这样可以降低迁移工具共识部分处理逻辑,后续迁移成功后,目标链可以通过发交易的方式新增共识节点
版本:: v2.2.1
节点数:1
共识类型:TBFT
vm 类型:需要支持docker-go
创建一个示例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
8.3.2.3. 配置迁移工具目标链
fabric迁移到chainamker只支持证书模式,目标链chainmaker2.x 使用新生成的证书
在迁移工具config.yml中,配置目标链的创世块配置
genesis: "./config_path/dev/bc1.yml"
8.3.2.4. 配置迁移工具合约文件
目录:chainmaker-transfer-tool/config_path/contract
需要配置的两个合约文件
assist.7z
transfer
源链为fabric,合约文件目录
chainmaker-transfer-tool/config_path/contract-fabric
8.3.2.5. 启动迁移工具
启动迁移工具的流程
#进入命令行迁移工具 cd chainmaker-transfer-tool #编译 go build #启动 ./transfer-tool
8.3.2.6. 启动目标链
将迁移工具生成的区块链数据datav2,重命名为data,复制到目标链的工作目录
# 进入命令行迁移工具主目录 cd chainmaker-transfer-tool #重命名 mv datav2 data #目标链存放data的目录 chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org
启动目标链
#目标链存放data的目录 cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org/bin #启动目标链 ./start.sh
验证迁移是否成功,可以给共识节点添加一个同步节点,如果同步节点能正常同步区块,证明迁移成功
如果想新增共识节点,可以通过发交易的方式新增共识节点的数量
8.3.3. chainmaker1.x到chainmaker2.x
迁移工具使用流程如下:
配置迁移工具源链信息
创建迁移工具目标链
配置迁移工具目标链
配置迁移工具合约文件
启动迁移工具
启动目标链
8.3.3.1. 配置迁移工具源链信息
源链:Chainmaker 1.x,如果源链版本为v1.1.0,需要单独version配置项:v1.1.0
迁移高度:0代表迁移到源链的最新高度
迁移工具支持两种方式
chainmaker-sdk,配置好chainmaker-sdk的配置文件:sdk_config.yml
源链的存储模块(v1.2.6版本),支持拉取chainmaker1.x所有版本的链,需要将chainmaker1.x源链的data目录复制到transfer工具的同级目录
config.yml配置文件
# 迁移源链信息 origin_chain: transfer_height: 0 chain_type: "chainmaker" chain_version: "v1.1.0"
8.3.3.2. 创建迁移工具目标链
目标链初次启动时,chainmaker2.x 目标链的时的要求如下,注意:目标链初次启动时,必须为1个节点,所有迁移区块只需要一个共识节点来处理,这样可以降低迁移工具共识部分处理逻辑,后续迁移成功后,目标链可以通过发交易的方式新增共识节点
版本:: v2.2.1
节点数:1
共识类型:TBFT
vm 类型:需要支持docker-go
创建一个示例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
8.3.3.3. 配置迁移工具目标链
确定目标链是证书模式还是公钥模式
如果是证书模式,需要判断:
目标链使用源链的证书
目标链使用新生成的证书
如果目标链使用源链的证书,复制创建的目标链的配置文件,给到迁移工具
目标链证书路径:chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org/config/wx-org.chainmaker.org
迁移工具存放目标链证书的路径:chainmaker-transfer-tool/config_path
源链证书定义了共识节点的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"
在迁移工具config.yml中,配置目标链的创世块配置
genesis: "./config_path/dev/bc1.yml"
8.3.3.4. 配置迁移工具合约文件
目录:chainmaker-transfer-tool/config_path/contract
需要配置的两个合约文件
assist.7z
transfer
源链为chainmaker1.x,合约文件目录
chainmaker-transfer-tool/config_path/contract-cm
8.3.3.5. 启动迁移工具
编译、启动迁移工具的流程
# 进入命令行迁移工具主目录 cd chainmaker-transfer-tool #编译 go build #启动 ./transfer-tool
迁移完成后,生成的目标链区块数据位于迁移工具主目录:chainmaker-transfer-tool/datav2
8.3.3.6. 启动目标链
将迁移工具生成的区块链数据datav2,重命名为data,复制到目标链的工作目录
# 进入命令行迁移工具主目录 cd chainmaker-transfer-tool #重命名 mv datav2 data #目标链存放data的目录 chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org
启动目标链
#目标链存放data的目录 cd chainmaker-go/build/release/chainmaker-v2.2.1-wx-org.chainmaker.org/bin #启动目标链 ./start.sh
验证迁移是否成功,可以给共识节点添加一个同步节点,如果同步节点能正常同步区块,证明迁移成功
如果想新增共识节点,可以通过发交易的方式新增共识节点的数量