体验Chainlink

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