使用Truflle开发基于oraclize的应用

Oraclize 是什么

Oraclize是将外部的变化引入Blockchain的一套工具。Oraclize已经部署到了很多Blockchain当中,
最常见的,在Ethererum上,Oraclize是一个智能合约。
直接安例子比较直观。

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
pragma solidity ^0.4.11;
import "github.com/oraclize/ethereum-api/oraclizeAPI.sol";

contract ExampleContract is usingOraclize {

string public EURGBP;
event LogPriceUpdated(string price);
event LogNewOraclizeQuery(string description);

function ExampleContract() payable {
updatePrice();
}

function __callback(bytes32 myid, string result) {
if (msg.sender != oraclize_cbAddress()) throw;
EURGBP = result;
LogPriceUpdated(result);
}

function updatePrice() payable {
if (oraclize_getPrice("URL") > this.balance) {
LogNewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee");
} else {
LogNewOraclizeQuery("Oraclize query was sent, standing by for the answer..");
oraclize_query("URL", "json(https://api.fixer.io/latest?symbols=USD,GBP).rates.GBP");
}
}
}

上面的智能合约调用了oraclize_query这个oraclize提供的方法。oraclize会监听整个Ethereum Blockchain,在区块链外调用这个query,获取到结果之后,调用目标合约的__callback方法并把query的结果作为参数传入。

有了oraclize,我们想要在blockchain内部调用外部api的时候,只需要写好相应的callback函数就行了。

用Truffle将上例的智能合约部署到Rinkeby TestNet

其实下面的内容和oraclize关系不大。不过既然尝试了解oraclize,不如将其部署之后熟悉一下中间的步骤。

首先是需要的东西。

  • Mist 钱包以及testnet的账号。注意同步最新的内容。

  • Geth

  • Rinkeby Testnet的Eth。网上所以下faucet一下就出来了。

用Geth 跑起local 节点

Mist自带的Geth已经同步了最新的链上的内容,我们需要关掉mist,然后在local用Geth跑Rinkeby的节点。

1
geth --rinkeby --rpc --rpcapi db,eth,net,web3,personal --unlock="0x889a183da0d5450CCbC4604a8200eEb47020f719" --rpccorsdomain https://localhost:3000

注意要输入解锁账号的phrase。

建立truffle项目进行配置

1
2
3
$ mkdir truffle-test
$ cd truffle-test
$ truffle init

需要修改truffle.js的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
networks: {
development: {
host: "localhost",
port: 8545,
network_id: "*", // Match any network id
},
rinkeby: {
host: "localhost", // Connect to geth on the specified
port: 8545,
from: "0x889a183da0d5450CCbC4604a8200eEb47020f719", // default address to use for any transaction Truffle makes during migrations
network_id: 4,
gas: 4612388 // Gas limit used for deploys
}
}
};

然后书写我们的合约。

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
# contracts/Example.sol

pragma solidity ^0.4.11;
import "./oraclizeAPI.sol";

contract ExampleContract is usingOraclize {

string public EURGBP;
event LogPriceUpdated(string price);
event LogNewOraclizeQuery(string description);

function ExampleContract() payable {
updatePrice();
}

function __callback(bytes32 myid, string result) {
if (msg.sender != oraclize_cbAddress()) throw;
EURGBP = result;
LogPriceUpdated(result);
}

function updatePrice() payable {
if (oraclize_getPrice("URL") > this.balance) {
LogNewOraclizeQuery("Oraclize query was NOT sent, please add some ETH to cover for the query fee");
} else {
LogNewOraclizeQuery("Oraclize query was sent, standing by for the answer..");
oraclize_query("URL", "json(https://api.fixer.io/latest?symbols=USD,GBP).rates.GBP");
}
}
}

我们需要在local应用oraclize。

1
2
3
$ cd contracts
$ wget https://raw.githubusercontent.com/oraclize/ethereum-api/master/oraclizeAPI_0.5.sol
$ mv oraclizeAPI_0.5.sol oraclizeAPI.sol

接下来在migrations下面添加2_deploy_contracts.js

1
2
3
4
5
var Example = artifacts.require("ExampleContract");

module.exports = function(deployer) {
deployer.deploy(Example);
};

这样智能合约的内容就完成了。
rk rinkeby

a 译truffle compile, 部署 truffle migrate --network rinkeby

大功告成。

用Truffle console 调试

1
2
3
4
5
6
$ truffle console --network rinkeby
truffle(rinkeby)> ExampleContract.deployed().then(function(instance){return instance.EURGBP.call();}).then(function(value){return value});
'0.87523'
truffle(rinkeby)> ExampleContract.deployed().then(function(instance){return instance.updatePrice({value: web3.toWei(0.01, "ether")});}).then(function(value){return value.logs[0].
args});
{ description: 'Oraclize query was sent, standing by for the answer..' }

最后如果要监听回掉函数里面的Event,可以用下面的方法。

1
ExampleContract.deployed().then(meta => { const allEvents = meta.allEvents({ fromBlock: 0, toBlock: 'latest' });allEvents.watch((err, res) => { console.log(err, res);});});

以上流水账仅供备忘。