Merge pull request #370 from meshplus/docs/refactor-and-add-deployment-documents
add some deployment documents
This commit is contained in:
commit
98c9d08875
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
|
@ -0,0 +1,251 @@
|
|||
# 中继链部署
|
||||
|
||||
中继链用于应用链的跨链管理,以及跨链交易的可信验证与可靠路由,是一种实现IBTP协议的开放许可链。部署中继链节点主要是三个步骤:安装包获取(准备)、配置文件修改和程序启动。下面依次来进行说明。
|
||||
|
||||
## 安装包获取
|
||||
|
||||
#### 源码下载编译
|
||||
|
||||
您可以自行拉取BitXHub项目的源码,然后在本地编译bitxhub及插件的二进制文件,具体操作步骤可参考如下:
|
||||
|
||||
```
|
||||
# 1. 首先拉取bitxhub项目源代码
|
||||
git clone https://github.com/meshplus/bitxhub.git
|
||||
# 2. 进入bitxhub目录,切换到指定的分支或版本后编译bitxhub二进制
|
||||
cd bitxhub && git checkout ${TAG} && make build
|
||||
# 注意⚠️:首次编译需要在build之前先执行 make prepare 完成依赖安装
|
||||
# 编译完成后可以在项目的bin目录下看到刚刚生成的bitxhub二进制文件
|
||||
# 3. 接下来需要编译共识插件,进入到 internal/plugins 目录进行编译
|
||||
cd internal/plugins && make plugins
|
||||
# 编译完成后可以在项目的internal/plugins/build目录下看到刚刚生成的共识插件文件,raft.so和solo.so
|
||||
```
|
||||
|
||||
**提示:在bitxhub v1.7.0及以上的版本,我们也提供了一键生成部署所需的文件包的make命令:make release-binary,执行完成后可以在项目的dist目录看到符合您系统的压缩包,解压即可使用。**
|
||||
|
||||
经过以上的步骤,相信您已经编译出了部署中继链节点所需的二进制文件,中继链节点运行还需要外部依赖库,均在项目build目录下(Macos使用libwasmer.dylib,Linux使用libwasmer.so),建议将得到的二进制和适配的依赖库文件拷贝到同一目录,方便之后的操作。
|
||||
|
||||
#### 二进制直接下载
|
||||
|
||||
除了源码编译外,我们也提供了直接下载BitXHub二进制的方式,下载地址链接如下:[BitXHub二进制包下载](https://github.com/meshplus/bitxhub/releases),链接中已经包含了所需的二进制和依赖库,您只需跟据实际情况选择合适的版本和系统下载即可。
|
||||
|
||||
## 配置文件修改
|
||||
|
||||
获取到安装包后,接下来要根据您的实际情况修改配置文件。如果您是在本地编译的二进制包,您也可以在项目根目录执行`make cluster`一键启动四节点raft共识的BitXHub集群。本章主要是介绍普适的配置方法,所以接下来将从生成、修改、检查配置文件等步骤进行详细说明。
|
||||
|
||||
#### 生成BitXHub配置文件
|
||||
|
||||
BitXHub提供了生成初始配置文件的命令行,执行步骤可参考如下:
|
||||
|
||||
```
|
||||
# 1. 新建节点启动目录(下面以node1为例)
|
||||
mkdir -p node1
|
||||
# 2. 在上一步新建的node1目录中生成初始配置
|
||||
./bitxhub --repo ./node1 init
|
||||
# 注意⚠️:如果执行失败提示依赖库找不到,可以将上一章中以libwasmer开头的文件加入到PATH中,并执行 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PATH
|
||||
# 3. 将bitxhub和共识插件的二进制分别拷贝到node1和node1/plugins目录
|
||||
cp bitxhub ./node1
|
||||
cp *.so ./node1/plugins
|
||||
# 4. 在node1目录生成当前节点的管理员私钥并转换成json格式
|
||||
./bitxhub key gen --target ./node1 --name key
|
||||
./bitxhub key convert --priv ./node1/key.priv
|
||||
# 注意⚠️:需要手动将上一步输出的内容保存为key.json文件
|
||||
# 5. 在node1目录生成当前节点的网络通信私钥
|
||||
./bitxhub cert priv gen --name node --target ./node1
|
||||
```
|
||||
|
||||
执行完后可以在node1目录下看到新生成的初始配置文件:
|
||||
|
||||
<img src="../../assets/treeForNode1.png" alt="image-20210413151432472" style="zoom:50%;" />
|
||||
|
||||
中继链节点主要包括bitxhub.toml、network.tom和order.toml配置文件,分别代表节点本身、节点网络以及节点共识方面的配置,其中order.toml一般使用默认配置即可,其它两个文件均需要根据实际部署情况进行修改,接下来我们以node1为例进行说明。
|
||||
|
||||
#### bitxhub.toml文件配置修改
|
||||
|
||||
bitxhub.toml文件是BitXHub节点启动的主要配置文件。各配置项说明如下:
|
||||
|
||||
| 配置项 | 说明 |
|
||||
| -------------- | ------------------------------------- |
|
||||
| **solo** | 是否按照单节点模式启动BitXHub |
|
||||
| **[port]** | gateway、grpc、pprof和monitor服务端口 |
|
||||
| **[pprof]** | 性能剖析配置 |
|
||||
| **[monitor]** | 监控服务配置 |
|
||||
| **[gateway]** | 跨域配置 |
|
||||
| **[ping]** | ping集群节点功能 |
|
||||
| **[security]** | 证书体系 |
|
||||
| **[limiter]** | 流量控制配置 |
|
||||
| **[log]** | 日志输出相关设置 |
|
||||
| **[cert]** | 是否开启认证节点p2p通信证书 |
|
||||
| **[order]** | 共识模块,作为插件进行加载 |
|
||||
| **[executor]** | 执行引擎类型 |
|
||||
| **[genesis]** | 创世节点配置 |
|
||||
|
||||
**在实际部署过程中,需要修改的配置一般只有port、order和genesis的信息,其它配置默认即可。** 以下为示例参考
|
||||
|
||||
1. 根据您机器实际分配的端口进行变更:
|
||||
|
||||
```javascript
|
||||
[port]
|
||||
gateway = 9091
|
||||
grpc = 60011
|
||||
pprof = 53121
|
||||
monitor = 40011
|
||||
```
|
||||
|
||||
2. 共识算法类型选择(开源版本目前支持raft和solo):
|
||||
|
||||
```shell
|
||||
[order]
|
||||
plugin = "plugins/raft.so"
|
||||
```
|
||||
|
||||
3. 修改genesis的节点管理员地址和投票权重,根据初始节点配置对应地址:
|
||||
|
||||
```shell
|
||||
[genesis]
|
||||
[[genesis.admins]]
|
||||
address = "0xc7F999b83Af6DF9e67d0a37Ee7e900bF38b3D013"
|
||||
weight = 1
|
||||
[[genesis.admins]]
|
||||
address = "0x79a1215469FaB6f9c63c1816b45183AD3624bE34"
|
||||
weight = 1
|
||||
[[genesis.admins]]
|
||||
address = "0x97c8B516D19edBf575D72a172Af7F418BE498C37"
|
||||
weight = 1
|
||||
[[genesis.admins]]
|
||||
address = "0xc0Ff2e0b3189132D815b8eb325bE17285AC898f8"
|
||||
weight = 1
|
||||
```
|
||||
|
||||
**说明:以上初始节点的address字段可以通过以下命令获取:**
|
||||
|
||||
```
|
||||
./bitxhub key address --path ./node1/key.priv
|
||||
# 示例输出:0x6F7BA26056bBC332AC132afF7AD107F7e45E5613
|
||||
```
|
||||
|
||||
#### network.toml文件配置修改
|
||||
|
||||
network.toml文件是BitXHub节点网络配置文件,各配置项说明如下:
|
||||
|
||||
| 配置项 | 说明 |
|
||||
| ----------- | -------------------------- |
|
||||
| **N** | 集群节点数量 |
|
||||
| **id** | 当前节点标识 |
|
||||
| **new** | 判断当前节点是新加入的节点 |
|
||||
| **[nodes]** | 集群节点信息 |
|
||||
| **account** | 节点验证者地址 |
|
||||
| **hosts** | 节点网络地址 |
|
||||
| **id** | 节点标识 |
|
||||
| **pid** | p2p网络唯一标识 |
|
||||
|
||||
**在实际部署过程中,需要修改的配置一般是节点数量、nodes的信息,其它配置默认即可。** 以下为示例参考
|
||||
|
||||
1. 配置当前节点集群的数量以及自身的id:
|
||||
|
||||
```
|
||||
id = 1 # self id
|
||||
n = 4 # the number of vp nodes
|
||||
new = false # track whether the node is a new node
|
||||
```
|
||||
|
||||
2. 配置集群中各个节点的信息
|
||||
|
||||
```shell
|
||||
[[nodes]]
|
||||
account = "0xc7F999b83Af6DF9e67d0a37Ee7e900bF38b3D013"
|
||||
hosts = ["/ip4/127.0.0.1/tcp/4001/p2p/"]
|
||||
id = 1
|
||||
pid = "QmXi58fp9ZczF3Z5iz1yXAez3Hy5NYo1R8STHWKEM9XnTL"
|
||||
```
|
||||
|
||||
**说明:上面 account就是上一节中bitxhub节点的address地址,hosts中一般就改变ip地址即可,节点的pid信息可以通过如下命令获取:**
|
||||
|
||||
```javascript
|
||||
./bitxhub cert priv pid --path ./node1/key.priv
|
||||
# 示例输出:QmWAaFDQ3p2Hj383WsBGU2nLMtsJk1aT9obXXXxL5UyUuA
|
||||
```
|
||||
|
||||
#### order.toml文件配置修改
|
||||
|
||||
order.toml文件是bitxhub共识配置文件。各配置项说明如下:
|
||||
|
||||
| 配置项 | 说明 |
|
||||
| ------ | ------------- |
|
||||
| [raft] | raft 相关配置 |
|
||||
| [rbft] | rbft 相关配置 |
|
||||
| [solo] | solo相关配置 |
|
||||
|
||||
配置示例如下(无特殊情况不要修改此配置):
|
||||
|
||||
```javascript
|
||||
[raft]
|
||||
batch_timeout = "0.3s" # Block packaging time period.
|
||||
tick_timeout = "0.1s" # TickTimeout is the internal logical clock for the Node by a single tick, Election timeouts and heartbeat timeouts are in units of ticks.
|
||||
election_tick = 10 # ElectionTick is the number of Node.Tick invocations that must pass between elections.
|
||||
heartbeat_tick = 1 # HeartbeatTick is the number of Node.Tick invocations that must pass between heartbeats.
|
||||
max_size_per_msg = 1048576 # 1024*1024, MaxSizePerMsg limits the max size of each append message.
|
||||
max_inflight_msgs = 500 # MaxInflightMsgs limits the max number of in-flight append messages during optimistic replication phase.
|
||||
check_quorum = true # Leader steps down when quorum is not active for an electionTimeout.
|
||||
pre_vote = true # PreVote prevents reconnected node from disturbing network.
|
||||
disable_proposal_forwarding = true # This prevents blocks from being accidentally proposed by followers.
|
||||
|
||||
[raft.mempool]
|
||||
batch_size = 200 # How many transactions should the primary pack.
|
||||
pool_size = 50000 # How many transactions could the txPool stores in total.
|
||||
tx_slice_size = 10 # How many transactions should the node broadcast at once
|
||||
tx_slice_timeout = "0.1s" # Node broadcasts transactions if there are cached transactions, although set_size isn't reached yet
|
||||
|
||||
[raft.syncer]
|
||||
sync_blocks = 1 # How many blocks should the behind node fetch at once
|
||||
snapshot_count = 1000 # How many apply index(blocks) should the node trigger at once
|
||||
|
||||
[rbft] #RBFT configurations
|
||||
set_size = 25 # How many transactions should the node broadcast at once
|
||||
batch_size = 500 # How many transactions should the primary pack before sending pre-prepare
|
||||
pool_size = 50000 # How many transactions could the txPool stores in total
|
||||
vc_period = 0 # After how many checkpoint periods( Blocks = 10 * vcperiod ) the primary gets cycled automatically. ( Set 0 to disable )
|
||||
check_interval = "3m" # interval of the check loop
|
||||
tolerance_time = "5m" # The max tolerance time duration (in seconds) of out-of-date
|
||||
batch_mem_limit = false # Indicates whether limit batch mem size or not
|
||||
batch_max_mem = 10000 # The max memory size of one batch
|
||||
|
||||
[rbft.timeout]
|
||||
sync_state = "3s" # How long to wait quorum sync state response
|
||||
sync_interval = "1m" # How long to restart sync state process
|
||||
recovery = "15s" # How long to wait before recovery finished(This is for release1.2)
|
||||
first_request = "30s" # How long to wait before first request should come
|
||||
batch = "0.5s"# Primary send a pre-prepare if there are pending requests, although batchsize isn't reached yet,
|
||||
request = "6s" # How long may a request(transaction batch) take between reception and execution, must be greater than the batch timeout
|
||||
null_request = "9s" # Primary send it to inform aliveness, must be greater than request timeout
|
||||
viewchange = "8s" # How long may a view change take
|
||||
resend_viewchange = "10s" # How long to wait for a view change quorum before resending (the same) view change
|
||||
clean_viewchange = "60s" # How long to clean out-of-data view change message
|
||||
update = "4s" # How long may a update-n take
|
||||
set = "0.1s" # Node broadcasts transactions if there are cached transactions, although set_size isn't reached yet
|
||||
|
||||
[rbft.syncer]
|
||||
sync_blocks = 1 # How many blocks should the behind node fetch at once
|
||||
|
||||
[solo]
|
||||
batch_timeout = "0.3s" # Block packaging time period.
|
||||
|
||||
[solo.mempool]
|
||||
batch_size = 200 # How many transactions should the primary pack.
|
||||
pool_size = 50000 # How many transactions could the txPool stores in total.
|
||||
tx_slice_size = 10 # How many transactions should the node broadcast at once
|
||||
tx_slice_timeout = "0.1s" # Node broadcasts transactions if there are cached transactions, although set_size isn't reached yet
|
||||
```
|
||||
|
||||
## 启动中继链节点
|
||||
|
||||
启动bitxhub节点只需要一条命令
|
||||
|
||||
```
|
||||
cd node1
|
||||
./bitxhub --repo ./ start
|
||||
```
|
||||
|
||||
待节点集群打印出bitxhub的LOGO,表示bitxhub集群开始正常工作
|
||||
|
||||
![](../../assets/bitxhub.png)
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
# 跨链网关部署--接入Ethereum
|
||||
|
||||
跨链网关Pier能够支持业务所在区块链(以下简称 应用链)便捷、快速的接入到跨链平台BitXHub中来,从而实现和其他业务区块链的跨链操作。跨链网关的部署需要提前确定应用链类型(对应不同的插件和配置),也需要提前在对应的应用链上部署跨链合约,为了符合用户的部署流程和提升操作体验,我们按接入应用链的类型来分别介绍说明跨链网关Pier的部署流程,主要分为在应用链上部署跨链合约、获取和修改Pier部署文件、注册应用链、部署验证规则和节点程序启动这五个章节。
|
||||
|
||||
## 在Ethereum应用链上部署跨链合约
|
||||
|
||||
**注意:在此操作之前,您需要确认已经部署或可接入的Ethereum应用链**, 在Ethereum上部署跨链合约的过程本质上和部署其它合约没有区别,只是合约名称和代码文件需要替换。在Ethereum上部署合约的工具有很多,您可以使[Remix](https://remix.ethereum.org/)进行合约的编译和部署,这里关键的是跨链合约的获取。
|
||||
|
||||
1. 下载pier-client-ethereum源码
|
||||
|
||||
```
|
||||
git clone https://github.com/meshplus/pier-client-ethereum.git
|
||||
```
|
||||
|
||||
2. 需要部署的合约文件就在example目录下,后缀名是.sol,注意切换到与Pier一致的分支或版本
|
||||
|
||||
3. 部署broker、transfer和data_swapper合约的过程不再赘述,需要特别说明的是在安装完broker合约后,需要将返回的合约地址填入transfer和data_swapper合约中`BrokerAddr`字段,这样业务合约才能正确跨链调用。此外,与Fabric一样,业务合约需要broker管理合约审计后,才能进行跨链交易。
|
||||
|
||||
## 获取和修改Pier部署文件
|
||||
|
||||
#### 安装包获取
|
||||
|
||||
##### 源码下载编译
|
||||
|
||||
部署跨链网关需要应用链插件,所以从源码安装的话还需要编译相应的应用链插件的二进制。
|
||||
|
||||
```shell
|
||||
# 编译跨链网关本身
|
||||
cd $HOME
|
||||
git clone https://github.com/meshplus/pier.git
|
||||
cd pier && git checkout {VERSION}
|
||||
make prepare && make build
|
||||
|
||||
# 编译Fabric 插件
|
||||
cd $HOME
|
||||
git clone https://github.com/meshplus/pier-client-ethereum.git
|
||||
cd pier-client-fabric && git checkout {VERSION}
|
||||
make eth
|
||||
|
||||
# 说明:1.ethereum插件编译之后会在项目目录的之下的build目录生成相应的文件;2.pier编译之后会在项目bin目录生成相应的文件。
|
||||
```
|
||||
|
||||
经过以上的步骤,相信您已经编译出了部署Pier节点(对接ethereum应用链)所需的二进制文件,Pier节点运行还需要外部依赖库,均在项目build目录下(Macos使用libwasmer.dylib,Linux使用libwasmer.so),建议将得到的二进制和适配的依赖库文件拷贝到同一目录,方便之后的操作。
|
||||
|
||||
##### 二进制直接下载
|
||||
|
||||
除了源码编译外,我们也提供了直接下载Pier及其插件二进制的方式,下载地址链接如下:[Pier二进制包下载](https://github.com/meshplus/pier/releases) 和 [ethereum插件二进制包下载](https://github.com/meshplus/pier-client-ethereum/releases)链接中已经包含了所需的二进制程序和依赖库,您只需跟据实际情况选择合适的版本和系统下载即可。
|
||||
|
||||
#### 修改配置文件
|
||||
|
||||
##### 修改Pier的配置
|
||||
|
||||
在进行应用链注册、验证规则部署等步骤之前,需要初始化跨链网关的配置目录,以用户目录下的pier为例:
|
||||
|
||||
```shell
|
||||
pier --repo=~/.pier init
|
||||
```
|
||||
|
||||
该命令会生成跨链网关的一些基础配置文件模板,使用 tree 命令可查看目录信息:
|
||||
|
||||
```text
|
||||
tree -L 1 ~/.pier
|
||||
|
||||
├── api
|
||||
├── certs
|
||||
├── key.json
|
||||
├── node.priv
|
||||
└── pier.toml
|
||||
|
||||
1 directory, 4 files
|
||||
```
|
||||
|
||||
导入fabric插件二进制文件
|
||||
|
||||
```
|
||||
mkdir -p ~/.pier/plugins
|
||||
cp eth-client ~/.pier/plugins
|
||||
```
|
||||
|
||||
pier.toml 描述链跨链网关启动的必要配置,也是Pier的主要配置,具体的配置项和说明如下:
|
||||
|
||||
| 配置项 | 说明 |
|
||||
| -------------- | ------------------------------------------------ |
|
||||
| **[port]** | http、grpc服务端口 |
|
||||
| **[log]** | 日志输出相关设置 |
|
||||
| **[mode]** | 连接的中继链配置,包括relay\direct\union三种模式 |
|
||||
| **[security]** | Tls配置 |
|
||||
| **[HA]** | 主备高可用配置 |
|
||||
| **[appchain]** | 对接的应用链的基础配置信息 |
|
||||
|
||||
主要需要修改的是端口信息、中继链的信息、应用链的信息
|
||||
|
||||
- 修改端口信息
|
||||
|
||||
```none
|
||||
[port]
|
||||
# 如果不冲突的话,可以不用修改
|
||||
http = 8987
|
||||
pprof = 44555
|
||||
```
|
||||
|
||||
- 修改中继链信息
|
||||
|
||||
```none
|
||||
[mode]
|
||||
type = "relay" # relay or direct
|
||||
[mode.relay]
|
||||
addrs = ["localhost:60011", "localhost:60012", "localhost:60013", "localhost:60014"]
|
||||
quorum = 2
|
||||
validators = [
|
||||
"0x000f1a7a08ccc48e5d30f80850cf1cf283aa3abd",
|
||||
"0xe93b92f1da08f925bdee44e91e7768380ae83307",
|
||||
"0xb18c8575e3284e79b92100025a31378feb8100d6",
|
||||
"0x856E2B9A5FA82FD1B031D1FF6863864DBAC7995D",
|
||||
]
|
||||
```
|
||||
|
||||
- 修改应用链信息
|
||||
|
||||
```none
|
||||
[appchain]
|
||||
# 所连接的应用链对应的Plugin文件在跨链网关配置文件夹下的相对路径
|
||||
plugin = "eth-client"
|
||||
# 所连接的应用链的配置文件夹在跨链网关配置文件夹下的相对路径
|
||||
config = "ether"
|
||||
```
|
||||
|
||||
##### 修改ethereum插件配置
|
||||
|
||||
Ethereum插件配置的模板在`pier-client-ethereum`项目中,并且已经在GitHub上进行开源,所以直接在GitHub上下载代码即可
|
||||
|
||||
```shell
|
||||
# 转到pier-client-ethereum项目路径下
|
||||
git clone https://github.com/meshplus/pier-client-ethereum.git && cd pier-client-ethereum
|
||||
cp ./config $HOME/.pier/ether
|
||||
```
|
||||
|
||||
重要配置如下:
|
||||
|
||||
```shell
|
||||
├── account.key
|
||||
├── ether.validators
|
||||
├── ether.toml
|
||||
├── password
|
||||
└── validating.wasm
|
||||
```
|
||||
|
||||
主要修改ethereum.toml文件,需要根据应用链实际情况填写,示例如下:
|
||||
|
||||
```
|
||||
[ether]
|
||||
addr = "wss://kovan.infura.io/ws/v3/cc512c8c74c94938aef1c833e1b50b9a"
|
||||
name = "ether-kovan"
|
||||
## 此处合约地址需要替换成变量代表的实际字符串
|
||||
contract_address = "$brokerAddr-kovan"
|
||||
abi_path = "broker.abi"
|
||||
key_path = "account.key"
|
||||
password = "password"
|
||||
```
|
||||
|
||||
## 注册Ethereum应用链
|
||||
|
||||
在启动跨链网关Pier之前,需要先注册应用链并部署绑定验证规则,这些操作均是Pier命令行发起,这一章我们介绍注册Ethereum应用链的操作步骤。需要注意的是,在v1.6.0及以上的版本,注册应用链需要中继链BitXHub节点管理员进行投票,投票通过之后才能接入。
|
||||
|
||||
1. Pier命令行发起应用链注册
|
||||
|
||||
```
|
||||
# 以用户目录下的pier为例
|
||||
pier --repo=~/.pier appchain register --name=ethereum --type=ether --consensusType POS --validators=~/.pier1/ether/ether.validators --desc="ethereum appchain for test" --version=1.0.0
|
||||
# 发起注册后会打印出应用链id和提案id
|
||||
appchain register successfully, chain id is 0xcb33b10104cd217aAB4b302e9BbeEd1957EDaA31, proposal id is 0xcb33b10104cd217aAB4b302e9BbeEd1957EDaA31-0
|
||||
```
|
||||
|
||||
2. 中继链节点依次投票
|
||||
|
||||
```
|
||||
# 进入bitxhub节点的安装目录,用上一步得到的提案id进行投票
|
||||
bitxhub --repo ../node1 client governance vote --id 0xcb33b10104cd217aAB4b302e9BbeEd1957EDaA31-0 --info approve --reason approve
|
||||
# 投票完后会打印:vote successfully!
|
||||
```
|
||||
|
||||
当BitXHub集群超过半数的管理员投票通过后,应用链注册成功(如果BitXHub是solo模式,则只需要一票同意即可),可以通过如下命令查询提案状态:`bitxhub --repo ../node1 client governance proposals --type AppchainMgr `
|
||||
|
||||
## 部署Ethereum验证规则
|
||||
|
||||
应用链只有在可用状态下可以部署验证规则,即需要应用链注册成功后才可以进行规则部署。提前准备好验证规则文件validating.wasm,使用以下Pier命令行进行部署。
|
||||
|
||||
```
|
||||
#以用户目录下的pier为例
|
||||
pier --repo=~/.pier rule deploy --path=~/.pier/ether/validating.wasm
|
||||
```
|
||||
|
||||
## 启动跨链网关节点
|
||||
|
||||
在完成以上步骤之后,可以启动跨链网关节点了
|
||||
|
||||
```
|
||||
#以用户目录下的pier为例
|
||||
pier --repo=~/.pier start
|
||||
```
|
||||
|
||||
观察日志信息没有报错信息,可以正常同步到中继链上的区块信息,即说明pier启动成功
|
||||
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
# 跨链网关部署--接入Fabric
|
||||
|
||||
跨链网关Pier能够支持业务所在区块链(以下简称 应用链)便捷、快速的接入到跨链平台BitXHub中来,从而实现和其他业务区块链的跨链操作。跨链网关的部署需要提前确定应用链类型(对应不同的插件和配置),也需要提前在对应的应用链上部署跨链合约,为了符合用户的部署流程和提升操作体验,我们按接入应用链的类型来分别介绍说明跨链网关Pier的部署流程,主要分为在应用链上部署跨链合约、获取和修改Pier部署文件、注册应用链、部署验证规则和节点程序启动这五个章节。
|
||||
|
||||
## 在Fabric应用链上部署跨链合约
|
||||
|
||||
**注意:在此操作之前,您需要确认已经部署好Fabric1.4版本的应用链(推荐使用[官方的部署脚本](https://github.com/hyperledger/fabric-samples/tree/release-1.4))**, 在fabric上部署跨链合约的过程本质上和部署其它合约没有区别,只是合约名称和代码文件需要替换,以下的操作可供参考。
|
||||
|
||||
1. 安装部署合约的工具fabric-cli(fabric官方提供)
|
||||
|
||||
```
|
||||
go get github.com/securekey/fabric-examples/fabric-cli/cmd/fabric-cli
|
||||
```
|
||||
|
||||
2. 获取需要部署的合约文件并解压(需要与pier的版本一致,下面的{VERSION}根据实际情况更改,例如 v1.6.0)
|
||||
|
||||
```
|
||||
wget https://github.com/meshplus/pier-client-fabric/raw/{VERSION}/example/contracts.zip
|
||||
#解压
|
||||
unzip -q contracts.zip
|
||||
```
|
||||
|
||||
3. 部署broker、transfer和data_swapper合约
|
||||
|
||||
```
|
||||
#安装和示例化broker合约(必需)
|
||||
fabric-cli chaincode install --gopath ./contracts --ccp broker --ccid broker --config "${CONFIG_YAML}" --orgid org2 --user Admin --cid mychannel
|
||||
fabric-cli chaincode instantiate --ccp broker --ccid broker --config "${CONFIG_YAML}" --orgid org2 --user Admin --cid mychannel
|
||||
|
||||
#安装和示例化transfer合约(可选)
|
||||
fabric-cli chaincode install --gopath ./contracts --ccp transfer --ccid transfer --config "${CONFIG_YAML}" --orgid org2 --user Admin --cid mychannel
|
||||
fabric-cli chaincode instantiate --ccp transfer --ccid transfer --config "${CONFIG_YAML}" --orgid org2 --user Admin --cid mychannel
|
||||
|
||||
#安装和示例化data_swapper合约(可选)
|
||||
fabric-cli chaincode install --gopath ./contracts --ccp data_swapper --ccid data_swapper --config "${CONFIG_YAML}" --orgid org2 --user Admin --cid mychannel
|
||||
fabric-cli chaincode instantiate --ccp data_swapper --ccid data_swapper --config "${CONFIG_YAML}" --orgid org2 --user Admin --cid mychannel
|
||||
|
||||
#业务合约需要broker管理合约审计后,才能进行跨链交易
|
||||
fabric-cli chaincode invoke --cid mychannel --ccid=broker \
|
||||
--args='{"Func":"audit", "Args":["mychannel", "transfer", "1"]}' \
|
||||
--user Admin --orgid org2 --payload --config "${CONFIG_YAML}"
|
||||
fabric-cli chaincode invoke --cid mychannel --ccid=broker \
|
||||
--args='{"Func":"audit", "Args":["mychannel", "data_swapper", "1"]}' \
|
||||
--user Admin --orgid org2 --payload --config "${CONFIG_YAML}"
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 获取和修改Pier部署文件
|
||||
|
||||
#### 安装包获取
|
||||
|
||||
##### 源码下载编译
|
||||
|
||||
部署跨链网关需要应用链插件,所以从源码安装的话还需要编译相应的应用链插件的二进制。
|
||||
|
||||
```shell
|
||||
# 编译跨链网关本身
|
||||
cd $HOME
|
||||
git clone https://github.com/meshplus/pier.git
|
||||
cd pier && git checkout {VERSION}
|
||||
make prepare && make build
|
||||
|
||||
# 编译Fabric 插件
|
||||
cd $HOME
|
||||
git clone https://github.com/meshplus/pier-client-fabric.git
|
||||
cd pier-client-fabric && git checkout {VERSION}
|
||||
make fabric1.4
|
||||
|
||||
# 说明:1.fabric插件编译之后会在项目目录的之下的build目录生成相应的文件;2.pier编译之后会在项目bin目录生成相应的文件。
|
||||
```
|
||||
|
||||
经过以上的步骤,相信您已经编译出了部署Pier节点(对接fabric应用链)所需的二进制文件,Pier节点运行还需要外部依赖库,均在项目build目录下(Macos使用libwasmer.dylib,Linux使用libwasmer.so),建议将得到的二进制和适配的依赖库文件拷贝到同一目录,方便之后的操作。
|
||||
|
||||
##### 二进制直接下载
|
||||
|
||||
除了源码编译外,我们也提供了直接下载Pier及其插件二进制的方式,下载地址链接如下:[Pier二进制包下载](https://github.com/meshplus/pier/releases) 和 [fabric插件二进制包下载](https://github.com/meshplus/pier-client-fabric/releases)链接中已经包含了所需的二进制程序和依赖库,您只需跟据实际情况选择合适的版本和系统下载即可。
|
||||
|
||||
#### 修改配置文件
|
||||
|
||||
##### 修改Pier的配置
|
||||
|
||||
在进行应用链注册、验证规则部署等步骤之前,需要初始化跨链网关的配置目录,以用户目录下的pier为例:
|
||||
|
||||
```shell
|
||||
pier --repo=~/.pier init
|
||||
```
|
||||
|
||||
该命令会生成跨链网关的一些基础配置文件模板,使用 tree 命令可查看目录信息:
|
||||
|
||||
```text
|
||||
tree -L 1 ~/.pier
|
||||
|
||||
├── api
|
||||
├── certs
|
||||
├── key.json
|
||||
├── node.priv
|
||||
└── pier.toml
|
||||
|
||||
1 directory, 4 files
|
||||
```
|
||||
|
||||
导入fabric插件二进制文件
|
||||
|
||||
```
|
||||
mkdir -p ~/.pier/plugins
|
||||
cp fabric-client ~/.pier/plugins
|
||||
```
|
||||
|
||||
pier.toml 描述链跨链网关启动的必要配置,也是Pier的主要配置,具体的配置项和说明如下:
|
||||
|
||||
| 配置项 | 说明 |
|
||||
| -------------- | ------------------------------------------------ |
|
||||
| **[port]** | http、grpc服务端口 |
|
||||
| **[log]** | 日志输出相关设置 |
|
||||
| **[mode]** | 连接的中继链配置,包括relay\direct\union三种模式 |
|
||||
| **[security]** | Tls配置 |
|
||||
| **[HA]** | 主备高可用配置 |
|
||||
| **[appchain]** | 对接的应用链的基础配置信息 |
|
||||
|
||||
主要需要修改的是端口信息、中继链的信息、应用链的信息
|
||||
|
||||
- 修改端口信息
|
||||
|
||||
```none
|
||||
[port]
|
||||
# 如果不冲突的话,可以不用修改
|
||||
http = 8987
|
||||
pprof = 44555
|
||||
```
|
||||
|
||||
- 修改中继链信息
|
||||
|
||||
```none
|
||||
[mode]
|
||||
type = "relay" # relay or direct
|
||||
[mode.relay]
|
||||
addrs = ["localhost:60011", "localhost:60012", "localhost:60013", "localhost:60014"]
|
||||
quorum = 2
|
||||
validators = [
|
||||
"0x000f1a7a08ccc48e5d30f80850cf1cf283aa3abd",
|
||||
"0xe93b92f1da08f925bdee44e91e7768380ae83307",
|
||||
"0xb18c8575e3284e79b92100025a31378feb8100d6",
|
||||
"0x856E2B9A5FA82FD1B031D1FF6863864DBAC7995D",
|
||||
]
|
||||
```
|
||||
|
||||
- 修改应用链信息
|
||||
|
||||
```none
|
||||
[appchain]
|
||||
# 所连接的应用链对应的Plugin文件在跨链网关配置文件夹下的相对路径
|
||||
plugin = "fabric-client"
|
||||
# 所连接的应用链的配置文件夹在跨链网关配置文件夹下的相对路径
|
||||
config = "fabric"
|
||||
```
|
||||
|
||||
##### 修改fabric插件配置
|
||||
|
||||
Fabric插件配置的模板在`pier-client-fabric`项目中,并且已经在GitHub上进行开源,所以直接在GitHub上下载代码即可
|
||||
|
||||
```shell
|
||||
# 转到pier-client-fabric项目路径下
|
||||
git clone https://github.com/meshplus/pier-client-fabric.git && cd pier-client-fabric
|
||||
cp ./config $HOME/.pier/fabric
|
||||
```
|
||||
|
||||
配置目录结构
|
||||
|
||||
```shell
|
||||
├── crypto-config/
|
||||
├── config.yaml
|
||||
├── fabric.toml
|
||||
└── fabric.validators
|
||||
```
|
||||
|
||||
主要修改Fabric网络配置,验证证书,跨链合约设置:
|
||||
|
||||
- **Fabric证书配置**
|
||||
|
||||
启动Fabric网络时,会生成所有节点(包括Order、peer等)的证书信息,并保存在 crypto-config文件夹中,Fabric插件和Fabric交互时需要用到这些证书。
|
||||
|
||||
```
|
||||
# 复制您所部署的Fabric所产生的crypto-config文件夹
|
||||
cp -r /path/to/crypto-config $HOME/.pier1/fabric/
|
||||
|
||||
# 复制Fabric上验证人证书
|
||||
cp $HOME/.pier1/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp/signcerts/peer1.org2.example.com-cert.pem $HOME/.pier1/fabric/fabric.validators
|
||||
```
|
||||
|
||||
- **修改Plugin配置文件 config.yaml **
|
||||
|
||||
`config.yaml`文件记录的Fabric网络配置(用您的网络拓扑配置文件替换这个样例文件),需要使用绝对路径,把所有的路径都修改为 `crypto-config`文件夹所在的绝对路径
|
||||
|
||||
```
|
||||
path: {CONFIG_PATH}/fabric/crypto-config => path: /home/alex/.pier/fabric/crypto-config
|
||||
```
|
||||
|
||||
替换为您部署的Fabric网络的拓扑设置文件即可,同时需要修改所有的Fabric 的IP地址,如:
|
||||
|
||||
```
|
||||
url: grpcs://localhost:7050 => url: grpcs://10.1.16.48:7050
|
||||
```
|
||||
|
||||
- **修改Plugin配置文件 fabric.toml**
|
||||
|
||||
配置项和说明:
|
||||
|
||||
| 配置项 | 说明 |
|
||||
| ---------------- | ----------------------------------- |
|
||||
| **addr** | Fabric 区块链所在的服务器地址和端口 |
|
||||
| **event_filter** | 跨链合约中抛出的跨链事件的名称 |
|
||||
| **username** | Fabric用户名称 |
|
||||
| **ccid** | 所部署的跨链合约名称 |
|
||||
| **channel_id** | 部署的跨链合约所在的channel |
|
||||
| **org** | 部署的跨链合约所在的org |
|
||||
|
||||
示例配置
|
||||
|
||||
```
|
||||
addr = "localhost:7053" // 若Fabric部署在服务器上,该为服务器地址
|
||||
event_filter = "interchain-event-name"
|
||||
username = "Admin"
|
||||
ccid = "broker" // 若部署跨链broker合约名字不是broker需要修改
|
||||
channel_id = "mychannel"
|
||||
org = "org2"
|
||||
```
|
||||
|
||||
- **修改Plugin配置文件fabric.validators**
|
||||
|
||||
fabric.validators 是Fabric验证人的证书,配置示例:
|
||||
|
||||
```
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICKTCCAc+gAwIBAgIRAIBO31aZaSZoEYSy2AJuhJcwCgYIKoZIzj0EAwIwczEL
|
||||
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
|
||||
cmFuY2lzY28xGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh
|
||||
Lm9yZzIuZXhhbXBsZS5jb20wHhcNMjAwMjA1MDgyMjAwWhcNMzAwMjAyMDgyMjAw
|
||||
WjBqMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
|
||||
U2FuIEZyYW5jaXNjbzENMAsGA1UECxMEcGVlcjEfMB0GA1UEAxMWcGVlcjEub3Jn
|
||||
Mi5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABG3jszFPTbGm
|
||||
dAYg2BxmHMTDKfQReNw3p9ttMK130qF5lQo5zLBG8Sa3viOCLnvjjg6A/P+yKnwv
|
||||
isI/jEVE8T2jTTBLMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1Ud
|
||||
IwQkMCKAIMVL+daK7nMGr2/AQIXTSPFkdd3UiPVDkWtkh5ujnalEMAoGCCqGSM49
|
||||
BAMCA0gAMEUCIQDMYOQiYeMiQZTxlRkj/3/jjYvwwdCcX5AWuFmraiHkugIgFkX/
|
||||
6uiTSD0lz8P+wwlLf24cIABq2aZyi8q4gj0YfwA=
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
## 注册Fabric应用链
|
||||
|
||||
在启动跨链网关Pier之前,需要先注册应用链并部署绑定验证规则,这些操作均是Pier命令行发起,这一章我们介绍注册Fabric应用链的操作步骤。需要注意的是,在v1.6.0及以上的版本,注册应用链需要中继链BitXHub节点管理员进行投票,投票通过之后才能接入。
|
||||
|
||||
1. Pier命令行发起应用链注册
|
||||
|
||||
```
|
||||
# 以用户目录下的pier为例
|
||||
pier --repo=~/.pier appchain register --name=fabric --type=fabric --consensusType raft --validators=~/.pier1/fabric/fabric.validators --desc="fabric appchain for test" --version=1.4.3
|
||||
# 发起注册后会打印出应用链id和提案id
|
||||
appchain register successfully, chain id is 0xcb33b10104cd217aAB4b302e9BbeEd1957EDaA31, proposal id is 0xcb33b10104cd217aAB4b302e9BbeEd1957EDaA31-0
|
||||
```
|
||||
|
||||
2. 中继链节点依次投票
|
||||
|
||||
```
|
||||
# 进入bitxhub节点的安装目录,用上一步得到的提案id进行投票
|
||||
bitxhub --repo ../node1 client governance vote --id 0xcb33b10104cd217aAB4b302e9BbeEd1957EDaA31-0 --info approve --reason approve
|
||||
# 投票完后会打印:vote successfully!
|
||||
```
|
||||
|
||||
当BitXHub集群超过半数的管理员投票通过后,应用链注册成功(如果BitXHub是solo模式,则只需要一票同意即可),可以通过如下命令查询提案状态:`bitxhub --repo ../node1 client governance proposals --type AppchainMgr `
|
||||
|
||||
## 部署Fabric验证规则
|
||||
|
||||
应用链只有在可用状态下可以部署验证规则,即需要应用链注册成功后才可以进行规则部署。提前准备好验证规则文件validating.wasm,使用以下Pier命令行进行部署。
|
||||
|
||||
```
|
||||
#以用户目录下的pier为例
|
||||
pier --repo=~/.pier rule deploy --path=~/.pier/fabric/validating.wasm
|
||||
```
|
||||
|
||||
## 启动跨链网关节点
|
||||
|
||||
在完成以上步骤之后,可以启动跨链网关节点了
|
||||
|
||||
```
|
||||
#以用户目录下的pier为例
|
||||
pier --repo=~/.pier start
|
||||
```
|
||||
|
||||
观察日志信息没有报错信息,可以正常同步到中继链上的区块信息,即说明pier启动成功
|
||||
|
||||
|
|
@ -1,32 +1,37 @@
|
|||
# 硬件环境
|
||||
## 服务器
|
||||
# 环境准备
|
||||
|
||||
| 服务器| 配置要求
|
||||
---|---
|
||||
CPU | 64位8核及其以上
|
||||
存储 | 大于等于500G(需要支持扩容)
|
||||
内存 | 大于等于16GB
|
||||
环境准备是部署和使用BitXHub跨链平台的第一步,主要是说明BitXHub及相关组件运行的硬件配置和软件依赖,您需要在部署BitXHub平台之前确认机器满足下述的要求。
|
||||
|
||||
## 硬件
|
||||
|
||||
## 软件环境
|
||||
**操作系统**
|
||||
配置| 推荐配置 | 最低配置
|
||||
---|---|---
|
||||
CPU | 2.4GHz *8核或以上 |1.5GHz *4核
|
||||
内存 | 16GB或以上 | 8GB
|
||||
存储 | 500G或以上(需要支持扩容) |100G
|
||||
带宽 | 10Mb |2Mb
|
||||
|
||||
## 操作系统支持
|
||||
|
||||
目前BitXHub支持的操作系统以及对应版本号如下:
|
||||
|
||||
| 操作系统| 系统版本|系统架构
|
||||
操作系统| 发行版本 | 系统架构
|
||||
---|---|---
|
||||
RHEL | 6或更新 |amd64,386
|
||||
CentOS | 6或更新| amd64,386
|
||||
SLES |11SP3或更新|amd64,386
|
||||
SUSE |11SP3或更新|amd64,386
|
||||
Ubuntu |14.04或更新|amd64,386
|
||||
MacOS |10.8或更新|amd64,386
|
||||
|
||||
## 安装go
|
||||
Go为Mac OS X、Linux和Windows提供二进制发行版。如果您使用的是不同的操作系统,您可以下载Go源代码并从源代码安装。
|
||||
**说明:为了更好的部署安装体验,我们建议您选用CentOS 8.2、Ubuntu 16.04和MacOS 10.15来进行部署安装。**
|
||||
|
||||
在这里下载适用于您的平台的最新版本Go:[下载](https://golang.org/dl/) - 请下载 1.13.x 或更新
|
||||
## 软件依赖
|
||||
|
||||
请按照对应于您的平台的步骤来安装Go环境:[安装Go](https://golang.org/doc/install#install) ,推荐使用默认配置安装。
|
||||
#### Go环境
|
||||
|
||||
BitXHub作为golang项目,需要安装和配置Go环境,您可以在这里下载适用于您的平台的最新版本Go二进制文件:[下载](https://golang.org/dl/) -(请下载 1.13.x 或更新的稳定版本),也可以下载Go源代码并从源代码进行安装,这里不再赘述。
|
||||
|
||||
下载完成后您需要安装Go,可以参考官方文档:[安装Go](https://golang.org/doc/install#install) ,推荐使用默认配置安装即可,
|
||||
|
||||
- 对于Mac OS X 和 Linux操作系统,默认情况下Go会被安装到/usr/local/go/,并且将环境变量GOROOT设置为该路径/usr/local/go.
|
||||
```shell
|
||||
|
@ -34,31 +39,19 @@ export GOROOT=/usr/local/go
|
|||
```
|
||||
|
||||
|
||||
- 同时,请添加路径 GOROOT/bin 到环境变量PATH中,可以使Go工具正常执行。
|
||||
```shell
|
||||
export PATH=$PATH:$GOROOT/bin
|
||||
```
|
||||
|
||||
|
||||
## 设置GOPATH
|
||||
您的Go工作目录 (GOPATH) 是用来存储您的Go代码的地方,您必须要将他跟您的Go安装目录区分开 (GOROOT)。
|
||||
以下命令是用了设置您的GOPATH环境变量的,您也可以参考Go官方文档,来获得更详细的内容: [https://golang.org/doc/code.html](https://golang.org/doc/code.html).
|
||||
|
||||
对于 Mac OS X 和 Linux 操作系统 将 GOPATH 环境变量设置为您的工作路径:
|
||||
```shell
|
||||
export GOPATH=$HOME/go
|
||||
```
|
||||
|
||||
|
||||
同时添加路径 GOPATH/bin 到环境变量PATH中,可以使编译后的Go程序正常执行。
|
||||
```shell
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
```
|
||||
|
||||
|
||||
由于我们将在Go中进行一系列编码,您可以将以下内容添加到您的~/.bashrc文件中:
|
||||
- 同时,由于我们可能将在Go中进行一系列编译操作,还需要设置GOPATH等,您可以将以下内容添加到您的~/.bashrc文件中:
|
||||
```shell
|
||||
export GOROOT=/usr/local/go
|
||||
export GOPATH=$HOME/go
|
||||
export PATH=$PATH:$GOPATH/bin:$GOROOT/bin
|
||||
```
|
||||
|
||||
**说明:以上配置均是参考,您可以根据自己的实际情况进行安装配置。**
|
||||
|
||||
#### Docker
|
||||
|
||||
如果您想使用容器来部署bitxhub平台,则需要提前安装好Docker,推荐安装18.03或更新的稳定版本,具体的安装方法可以参考官方文档:[安装Docker](https://docs.docker.com/engine/install/)
|
||||
|
||||
|
||||
|
||||
恭喜您!环境确认和准备完成,接下来可以愉快地开始部署BitXHub平台啦!!!
|
|
@ -50,9 +50,11 @@ nav:
|
|||
- 跨链事务方案: bitxhub/dev/design/interchain_transaction.md
|
||||
- 跨链网关设计方案: bitxhub/dev/design/pier.md
|
||||
- 隐私保护方案: bitxhub/dev/design/privacy_protection.md
|
||||
- 使用手册:
|
||||
- 硬件环境: bitxhub/usage/env.md
|
||||
- 中继链部署: bitxhub/usage/deploy.md
|
||||
- 部署使用:
|
||||
- 环境准备: bitxhub/usage/env.md
|
||||
- 中继链部署: bitxhub/usage/deploy_bitxhub.md
|
||||
- 跨链网关部署--接入Fabric: bitxhub/usage/deploy_pier_access_fabric.md
|
||||
- 跨链网关部署--接入Ethereum: bitxhub/usage/deploy_pier_access_ethereum.md
|
||||
- 中继跨链部署: bitxhub/usage/inter_relay_deploy.md
|
||||
- 跨链网关直连模式部署: bitxhub/usage/pier_direct_mode_deploy.md
|
||||
- 版本发布记录:
|
||||
|
|
1
go.sum
1
go.sum
|
@ -917,6 +917,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
|||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
|
|
Loading…
Reference in New Issue