Zhuang's Diary

言之有物,持之以恒

文档链接=>https://hyperledger.github.io/burrow/

github链接=>https://github.com/hyperledger/burrow/

接前文《体验Hyperledger-Burrow-1》,启动4个节点如下:

1
2
3
4
5
6
➜  script ps aux | grep burrow
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
will 21409 2.1 0.8 133268 66036 pts/1 SNl 08:52 1:02 ./burrow start --config=burrow000.toml
will 21410 1.9 0.7 133268 59212 pts/1 SNl 08:52 0:56 ./burrow start --config=burrow001.toml
will 21411 2.0 0.8 133268 65924 pts/1 SNl 08:52 0:59 ./burrow start --config=burrow002.toml
will 21416 2.0 0.7 133268 63416 pts/1 SNl 08:52 1:01 ./burrow start --config=burrow003.toml

制作增加节点的配置文件

1
./burrow spec -v1 | ./burrow configure -s- > burrow_add.toml

运行完成后,增加公私钥文档如下:

1
2
3
4
5
6
7
8
➜  data pwd
/home/will/documents/burrow/script/.keys/data
➜ data cat 035B1B192A16FF8086C36304024010502CEB2DE0.json
{"CurveType":"ed25519","Address":"5ECA9967F5D363F21C4606CC971710200A64C5BC","PublicKey":"4F3530024CF75A7AFC4D168CF2975C285D03CEBB1CBE82E21AD9C76531A63128","AddressHash":"go-crypto-0.5.0","PrivateKey":{"Crypto":"none","Plain":"486059FB274248423F92B7522D5A237AB99B38C80F84D46F720EAE1506D8E2DF4F3530024CF75A7AFC4D168CF2975C285D03CEBB1CBE82E21AD9C76531A63128"}}
➜ names pwd
/home/will/documents/burrow/script/.keys/names
➜ names cat Validator_0
035B1B192A16FF8086C36304024010502CEB2DE0

修改burrow_add.toml配置:
1.删除GenesisDoc的内容,因为genesis.json中已经包含了节点们的GenesisDoc;
2.增加PersistentPeers,PersistentPeers在burrow000.toml中可以找到;
3关闭grpc端口,关闭rpc.info等,否则会跟已有的4个节点端口冲突

发出增加validator的Tx

制作增加validator Tx 交易的文件:

1
2
3
4
5
6
jobs:
- name: AddValidator
update-account:
target: 4F3530024CF75A7AFC4D168CF2975C285D03CEBB1CBE82E21AD9C76531A63128
power: 222222
permissions: [root, send, call, createContract, createAccount, bond, name, proposal, input, batch, identify, hasBase, setBase, unsetBase, setGlobal, hasRole, addRole, removeRole]

其中4F3530024CF75A7AFC4D168CF2975C285D03CEBB1CBE82E21AD9C76531A63128 是新节点的publickey。

执行交易命令(DCF0F3BD45EA59B2D471729EC22838DF7B119012 是增加节点前已经启动的4个节点中的Full Account节点。),即在已经启动的节点上执行本交易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
./burrow deploy -c 127.0.0.1:10997 --mempool-signing=true --address=DCF0F3BD45EA59B2D471729EC22838DF7B119012 deploy.yaml
log_channel=Info message="Using chain" Chain=127.0.0.1:10997 Signer=
log_channel=Info message="Loading Playbook File."
log_channel=Info message="Loading playbook file" path=/home/will/documents/burrow/script filename=/home/will/documents/burrow/script/deploy.yaml
log_channel=Info message="*****Executing Job*****" JobName=defaultAddr Type=Account
log_channel=Info message="Setting Account" account=DCF0F3BD45EA59B2D471729EC22838DF7B119012
log_channel=Info message="*****Executing Job*****" JobName=AddValidator Type=UpdateAccount
log_channel=Info message=GovTx account="unsupported value type"
log_channel=Info message="Using mempool signing since no keyClient set, pass --keys to sign locally or elsewhere"
log_channel=Info message="Using mempool signing"
log_channel=Info message="Tx Return" TransactionHash=5a1a57e975e5ead5079c12c63c473e1c04c59cf82fe9974f191faaf1d8aeb8b8 BlockHeight=18
log_channel=Info message="Job Vars" name=input value=DCF0F3BD45EA59B2D471729EC22838DF7B119012
log_channel=Info message="Job Vars" name=native value=
log_channel=Info message="Job Vars" name=power value=222222
log_channel=Info message="Job Vars" name=sequence value=
log_channel=Info message="Job Vars" name=address value=
log_channel=Info message="Job Vars" name=publicKey value=D90E05FAD677699B4FEE56B567F85D3A90438B4B627C27CED0D4C850BDC97876
log_channel=Info message="Writing to current directory" output=/home/will/documents/burrow/script/deploy.output.json
log_channel=Info message="JOBS THAT SUCCEEEDED" count=1
log_channel=Info message="Playbook result" jobNo=0 file=deploy.yaml time=230.744184ms

注意:新创建的validator没有余额。

启动新增加的节点

1
./burrow start --config=burrow_add.toml --genesis=genesis.json --address=5ECA9967F5D363F21C4606CC971710200A64C5BC

5ECA9967F5D363F21C4606CC971710200A64C5BC 是被增加节点的地址(address)。

1
2
3
4
5
6
7
➜  script ps aux | grep burrow
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
will 21409 2.1 0.8 133268 66036 pts/1 SNl 08:52 1:02 ./burrow start --config=burrow000.toml
will 21410 1.9 0.7 133268 59212 pts/1 SNl 08:52 0:56 ./burrow start --config=burrow001.toml
will 21411 2.0 0.8 133268 65924 pts/1 SNl 08:52 0:59 ./burrow start --config=burrow002.toml
will 21416 2.0 0.7 133268 63416 pts/1 SNl 08:52 1:01 ./burrow start --config=burrow003.toml
will 21505 2.2 0.7 133268 58864 pts/1 Sl+ 08:55 1:01 ./burrow start --config=burrow_add.toml --genesis=genesis.json --address=DCF0F3BD45EA59B2D471729EC22838DF7B119012

ed25519是tendermint选择的加密曲线,secp256k1是ethereum选择的加密曲线。

两者都可以在./burrow keys list 中看到账户地址和名称。在web3.getAccounts中只能够看到secp256k1曲线下生成的账户地址,metamask和remix也是如此。

burrow keys gen -n -t secp256k1 --name zhuang 如果不指定 -n 的话,需要输入密码。

发送转账交易

创建转账交易 deploy_sendToken.yaml

1
2
3
4
5
jobs:
- name: sendTxTest1
send:
destination: 0DE8C14FE07FA693D3A6F65D826647D39E9A3BB0
amount: 2000

发起

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
➜  script ./burrow keys gen -n -t secp256k1 --name zhuang1
0DE8C14FE07FA693D3A6F65D826647D39E9A3BB0
➜ script ./burrow deploy --address CCC93802D38A33B636D8B2B74218021A571CF252 deploy_sendToken.yaml
log_channel=Info message="Using chain" Chain=127.0.0.1:10997 Signer=
log_channel=Info message="Loading Playbook File."
log_channel=Info message="Loading playbook file" path=/home/will/documents/burrow/script filename=/home/will/documents/burrow/script/deploy_sendToken.yaml
log_channel=Info message="*****Executing Job*****" JobName=defaultAddr Type=Account
log_channel=Info message="Setting Account" account=CCC93802D38A33B636D8B2B74218021A571CF252
log_channel=Info message="*****Executing Job*****" JobName=sendTxTest1 Type=Send
log_channel=Info message="Sending Transaction" source=CCC93802D38A33B636D8B2B74218021A571CF252 destination=0DE8C14FE07FA693D3A6F65D826647D39E9A3BB0 amount=2000
log_channel=Info message=SendTx send="unsupported value type"
log_channel=Info message="Using mempool signing since no keyClient set, pass --keys to sign locally or elsewhere"
log_channel=Info message="Using mempool signing"
log_channel=Info message="Tx Return" TransactionHash=a0abda87ea4751beaeae04d5ac67c35114b9f068720db6e1795ec7083c4a872e BlockHeight=27
log_channel=Info message="Writing to current directory" output=/home/will/documents/burrow/script/deploy_sendToken.output.json
log_channel=Info message="JOBS THAT SUCCEEEDED" count=1
log_channel=Info message="Playbook result" jobNo=0 file=deploy_sendToken.yaml time=347.234362ms

文档链接=>https://hyperledger.github.io/burrow/

github链接=>https://github.com/hyperledger/burrow/

Burrow是一个权限控制较为严格、以太坊EVM和WASM虚拟机支持、运行于Tendermint共识之上的区块链客户端。其主要由Monax贡献,并由Monax 和英特尔赞助。

其强调的设计理念包括:

  1. 防篡改的Merkle状态—Tamper-resistant merkle state
  2. PoS支持
  3. 链上治理原生支持
  4. 以太坊账户一览
  5. 可以根据每个帐户设置代码执行权限
  6. 事件流支持
  7. 智能合约事件弹出至SQL表记录
  8. GRPC和Protobuf支持
  9. Javascript SDK支持,客户端库可以生成代码来访问合约,生成的代码是静态的Typescript对象
  10. Keys服务,提供代理签名服务器
  11. Web3 RPC,兼容Ethereum主网的开发工具,如 Truffle、 Metamask、Remix

Burrow应用于多个区块链生产项目

初始化Burrow节点

https://github.com/hyperledger/burrow/下载可执行文件,本文以 ubuntu 环境为例。

1
./burrow spec -f2 -p2 | ./burrow configure --curve-type secp256k1 -s- --pool --separate-genesis-doc=genesis.json

./burrow spec 建立一个GenesisSpec作为GenesisDoc和configure命令的模板,f2是指2个full-accounts,p2是指2个participant-accounts。

--curve-type secp256k1 是指定加密曲线的类型。

./burrow configure -s- 通过使用GenesisDoc或GenesisSpec,创建密钥并创建配置文档。--pool 为名为burrowNNN.toml的所有共识节点(validators)编写配置文件。--separate-genesis-doc 将genesis文档投送至 JSON或者TOML文件。

  • validator-accounts 共识的参与者,需要抵押一部分资金

  • root-accounts 根账户

  • developer-accounts 开发者,功能很多和全节点很像

  • participant-accounts 参与者

  • full-accounts 全功能

启动Burrow节点

1
2
3
4
5
6
7
8
➜  script ./burrow start --config=burrow000.toml &
./burrow start --config=burrow001.toml &
./burrow start --config=burrow002.toml &
./burrow start --config=burrow003.toml &
[5] 12458
[6] 12459
[7] 12460
[8] 12464

网页端访问RPC服务

http://127.0.0.1:26759/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Available endpoints:
//127.0.0.1:26759/account_stats
//127.0.0.1:26759/accounts
//127.0.0.1:26759/chain_id
//127.0.0.1:26759/consensus
//127.0.0.1:26759/genesis
//127.0.0.1:26759/network
//127.0.0.1:26759/network/registry
//127.0.0.1:26759/validators

Endpoints that require arguments:
//127.0.0.1:26759/account?address=_
//127.0.0.1:26759/account_human?address=_
//127.0.0.1:26759/block?height=_
//127.0.0.1:26759/blocks?minHeight=_&maxHeight=_
//127.0.0.1:26759/dump_storage?address=_
//127.0.0.1:26759/name?name=_
//127.0.0.1:26759/names?regex=_
//127.0.0.1:26759/status?block_time_within=_&block_seen_time_within=_
//127.0.0.1:26759/storage?address=_&key=_
//127.0.0.1:26759/unconfirmed_txs?maxTxs=_

Kuboard 是 Kubernetes 的一款图形化管理界面。参考如下链接:https://kuboard.cn/install/install-dashboard.html 安装kuboard

  1. kuboard 首页

  1. Deployment 视图页面

体验结论:

  1. kuboard 比 Kubernetes Dashboard(Kubernetes 的官方 Web UI)要友好许多,并且 Kubernetes Dashboard 需要在操作机中具备 Kubectl;
  2. wayne 对用户的权限管理会优秀一些。但是经过docker-compose实验,启动为dev版本,未成功打开页面
  3. rancherhttps://github.com/rancher/)Rancher为您提供“Kubernetes即服务(Kubernetes-as-a-Service)”。在国内北京、上海、深圳、沈阳均有办公地点,汉语支持较好。推荐使用。

SeaweedFS 是开源的,简单的,高伸缩性的分布式文件系统。SeaweedFS 作为支持全 POSIX 文件系统语义替代,Seaweed-FS 选择仅实现 key-file 的映射,类似 “NoSQL”,也可以说是 “NoFS”。

SeaweedFS 仅花费 40 字节的硬盘来存储每个文件的元数据。

GlusterFS, Ceph相比较

System File Meta File Content Read POSIX REST API Optimized for small files
SeaweedFS lookup volume id, cacheable O(1) disk seek Yes Yes
SeaweedFS Filer Linearly Scalable, Customizable O(1) disk seek FUSE Yes Yes
GlusterFS hashing FUSE, NFS
Ceph hashing + rules FUSE Yes
MooseFS in memory FUSE No

体验seaweedfs

参考==>https://hub.docker.com/r/chrislusf/seaweedfs

  1. 拉取 docker-compose 文件,wget https://raw.githubusercontent.com/chrislusf/seaweedfs/master/docker/seaweedfs-compose.yml
  2. 启动,docker-compose -f seaweedfs-compose.yml -p seaweedfs up

参考 => https://github.com/chrislusf/seaweedfs/wiki/Volume-Server-API

1
2
3
4
5
6
➜  seaweedfs: curl http://localhost:9333/dir/assign
{"fid":"7,01248b7b86","url":"172.18.0.3:8080","publicUrl":"172.18.0.3:8080","count":1}%
➜ seaweedfs: curl -F file=@/home/will/documents/zaq12wsxcde3--de4064dc15870163a9aab589a1ccf7900dd68ef4 http://127.0.0.1:8080/7,01248b7b86
{"name":"zaq12wsxcde3--de4064dc15870163a9aab589a1ccf7900dd68ef4","size":489,"eTag":"468de108"}%
➜ seaweedfs: curl http://localhost:9333/dir/lookup\?volumeId\=7
{"volumeId":"7","locations":[{"url":"172.18.0.3:8080","publicUrl":"172.18.0.3:8080"}]}%
  1. curl http://localhost:9333/dir/assign 获取fid
  2. curl -F file=@/home/will/documents/zaq12wsxcde3--de4064dc15870163a9aab589a1ccf7900dd68ef4 http://127.0.0.1:8080/7,01248b7b86 上传文件
  3. curl http://localhost:9333/dir/lookup\?volumeId\=7 查询
  4. 在浏览器中打开 http://172.18.0.3:8080/7,01248b7b86,查看文档
  5. master 的url:http://127.0.0.1:9333/
  6. volume的url:http://172.18.0.3:8080/ui/index.html

Chainlink是一个去中心化的预言机,但是你同样可以在私有环境中使用Chainlink,让它成为一个为私有链或联盟链服务的中心化的预言机系统。只要你的私有链环境支持完整的EVM环境,就可以利用Chainlink的开源实现,为自己的系统搭建一个具有广泛适配能力的预言机系统。

准备工作

私有链/联盟链(需支持EVM,开放WebSocket端口)

由于目前Chainlink的合约系统都是在以太坊网络上的虚拟环境中运行的,所以需要您的私有链/联盟链支持EVM环境以及Solidity合约编程语言。

用于部署合约的账户,账户需持有足够数量的Native Token(原生代币)

一般来说,向区块链提交事务,不管是创建合约还是普通转账,都需要事务发起账户提供一定的手续费,所以需要一个持有原生代币的账户,用于部署合约和节点提交事务。如果您的私有链提交事务不需要手续费,那仅需要一个账户就可以。(具体请根据您的私有链的配置操作)

一台服务器用于部署Chainlink节点

Chainlink节点相当于区块链在真实世界中的代理,它可以接收链上的数据请求,并获取到链上所需要的数据,通过事务提交给链上。所以需要一台服务器来建立Chainlink节点服务,服务器配置不需要很高,但是需要和私有链环境保持良好的网络通讯。

之前的Chainlink节点版本默认使用Sqlite作为存储数据库,但是随着功能越来越完善,性能要求也越来越高,从0.8.0版本起,Chainlink节点要求必须使用postgres作为存储数据库,所以我们需要搭建一个postgres数据库。这个数据库可以和节点位于同一台服务器上,也可以位于不同的服务器上。您也可以同时搭建两个数据库作为备份。

(可选)准备truffle suite和npm或WebIDE Remix等开发部署工具

您可以选择Chainlink提供的truffle box来编写和部署测试合约

1
truffle unbox smartcontractkit/box

也可以在已有的项目中添加Chainlink开发库

1
2
truffle init
npm install @chainlink/contracts --save

同样的,您也可以使用可视化的Web IDE Remix来进行开发,使用起来更加方便,也无需配置本地开发环境。在使用Remix时,可以搭配MetaMask来进行转账和事务操作。

https://remix.ethereum.org

https://metamask.io

实施步骤

0.搭建 EVM 私链

LinkToken.sol

所有Chainlink的功能实现和数据流转都是围绕LINK token来实现的。这里的remix中默认是https url,如果访问vmware中的linux server,建议在remix中使用 http url

img

2.部署Chainlink节点

2.1 安装docker、postgres (建议postgres也在docker中安装)

2.2 创建环境变量配置文件

1
2
3
mkdir ~/.chainlink
cd ~/.chainlink
vim .env
1
2
3
4
5
6
7
8
9
10
11
12
ROOT=/chainlink
LOG_LEVEL=debug
ETH_CHAIN_ID=1337
MIN_OUTGOING_CONFIRMATIONS=0
MIN_INCOMING_CONFIRMATIONS=0
LINK_CONTRACT_ADDRESS=0x9E05B78ea853a4B093694645561c4BFc953A6f62
CHAINLINK_TLS_PORT=0
SECURE_COOKIES=false
ALLOW_ORIGINS=*
ETH_URL=ws://localhost:8546
DATABASE_URL=postgresql://postgres:123456@localhost:5432/chainlink?sslmode=disable
DATABASE_TIMEOUT=0

其中ETH_URL是私有链的RPC接口,必须是WebSocket接口,可以是ws也可以是wss

LINK_CONTRACT_ADDRESS 是刚刚部署的Link token 地址。

2.3 通过docker启动

1
2
3
4
5
cd ~/.chainlink
# 启动postgres
docker run --name postgres_chainlink -e POSTGRES_PASSWORD=123456 -v /home/will/documents/chainlink:/var/lib/postgresql/data -p 5432:5432 -d postgres:11.5-alpine
# 启动chainlink节点
docker run --net host -p 6688:6688 -v ~/.chainlink:/chainlink -it --env-file=.env smartcontract/chainlink:0.7.8 local n

其中--net host 是为了让通过docker启动的Chainlink节点可以访问到宿主记得网络,否则上面配置文件中的localhost都是不可访问的。也可以通过其他更加安全的docker网络配置完成同样功能。

0.7.8是Chainlink的release版本号,不写的话默认是latest。

2.4 记录节点管理密码

首次启动成功后,首先会要求输入一个密码,这个密码是Chainlink节点账户的私钥密码,可以用来控制Chainlink节点账户,必须牢记,否则节点账户所持有的资金无法取出。

然后会要求输入一对用户名和密码,这是Chainlink管理界面的的用户名和密码,在通过 http: //chainlink_ip:6688 访问管理端界面时会要求输入这对用户名和密码。

img

2.5 创建Job

https://docs.chain.link/docs/fulfilling-requests#section-add-jobs-to-the-node

创建不同数据类型的 Job

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"initiators": [
{
"type": "runlog"
}
],
"tasks": [
{
"type": "httpget"
},
{
"type": "jsonparse"
},
{
"type": "ethbytes32"
},
{
"type": "ethtx"
}
]
}

2.6 向Chainlink节点(ACCOUNT_ADDRESS)转入一定数量的Native token用于提交事务

比如:如果是以太坊公网,需要转入ETH,以作为交易的gas费用。

节点地址可以在管理页面的configure页面下找到,账户资金仅用于提交transaction。

3.部署oracle contract

1
2
3
pragma solidity 0.4.24;

import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.4/Oracle.sol";

调用合约中的setFulfillPermission方法,传递参数为(ACCOUNT_ADDRESS,true),ACCOUNT_ADDRESS是ChainLink Operator。

4.编写部署用户合约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
pragma solidity 0.4.24;

import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.4/ChainlinkClient.sol";


contract GetTemperature is ChainlinkClient {
LinkTokenInterface internal LinkToken;


//string constant url = "https://www.random.org/integers/?num=1&min=1&max=6&col=1&base=10&format=plain&rnd=new";
string constant url = "https://api.seniverse.com/v3/weather/now.json?key=S9g8Ize9pNyUZ_BOP&location=shanghai&language=zh-Hans&unit=c";
address constant oracleAddress = 0xa6126AD8B8307C6e1b668F486BEA155e814FA22d;
bytes32 constant JobId = "d91130d49daf46aaa591bcbce6d59b72";
address constant linkAddress = 0x9E05B78ea853a4B093694645561c4BFc953A6f62;

constructor() public {
setChainlinkToken(linkAddress);
setChainlinkOracle(oracleAddress);
LinkToken = LinkTokenInterface(linkAddress);
}

string public temperature;

function getData() public {

// 发起Chainlink请求
requestTemperature(JobId);

}


function requestTemperature(bytes32 _jobId) public returns (bytes32 requestId) {

Chainlink.Request memory req = buildChainlinkRequest(_jobId, this, this.fulfillTemperature.selector);

req.add("get", url);
req.add("path", "results.0.now.temperature");

requestId = sendChainlinkRequest(req, 1 * LINK);

return requestId;
}


function fulfillTemperature(bytes32 _requestId, bytes32 _temp)
public recordChainlinkFulfillment(_requestId)
{
temperature = bytes32ToString(_temp);
//data = _temp;
}


function bytes32ToString(bytes32 x) private pure returns (string) {
bytes memory bytesString = new bytes(32);
uint charCount = 0;
for (uint j = 0; j < 32; j++) {
byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
if (char != 0) {
bytesString[charCount] = char;
charCount++;
}
}
bytes memory bytesStringTrimmed = new bytes(charCount);
for (j = 0; j < charCount; j++) {
bytesStringTrimmed[j] = bytesString[j];
}
return string(bytesStringTrimmed);
}

}

其中 linkAddress、OracleAddress、JobId 需要根据上面的配置结果填写,或作为参数在调用时传入。

向部署好的用户合约地址转入Link token,用户在发起请求是支付给节点的费用。上述部署的Link Token为18位精度,建议使用 transfer 方法转移 Link token 2000,000000000000000000

发起请求获取数据,使用getData方法获取天气数据。

image