create account

【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約 by ankar

View this thread on: hive.blogpeakd.comecency.com
· @ankar · (edited)
$0.03
【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約
![Infura Logo From Consensys](https://i.imgur.com/doEO8gu.jpg)

> Infura 提供公開的 Ethereum 主網和測試網路節點。到 [Infura 官網申請](https://infura.io/signup),只要輸入一點基本資料和 Email,就可以收到 API-key。

![Infura API Key](https://i.imgur.com/yz9kOFo.png)

---

## 使用 RPC 查詢合約內儲存的狀態

最常需要查詢的狀態就是 Token 的餘額啦。我就用 EOS 代幣合約最為範例試看看。

### 取得合約資訊

可以透過 Etherscan,大部分知名的合約可以直接搜尋到。

![](https://i.imgur.com/vVx5L4A.png)

要呼叫合約,至少需要:

- **合約地址**,例如 0x86Fa049857E0209aa7D9e616F7eb3b3B78ECfdb0
- **要呼叫的 function signature**,例如以 ERC 20 代幣合約來說,查詢餘額要呼叫的 function 是 `balanceOf(address)`,其對應的 function signature 是 `70a08231`。

如何取得 function signature 呢?以 `balanceOf(address)` 為例:
1. 把 `balanceOf(address)` 經過 sha3

        0x70a08231b98ef4ca268c9cc3f6b4590e4bfec28280db06bb5d45e689f2a360be

2. 取除了 `0x` 外,前面的 8 位
    
        70a08231

以上流程可以用任何工具完成,以 web3.js 為例:

    var functionSig = we3.sha3("balanceOf(address)").substr(2,8)

另外也可以把 contract code 貼到 remix。在合約的 Details 中可以看到完整的合約介面和對應的 function signature。

![](https://i.imgur.com/YRtWIGr.png)

### 使用 RPC

可以透過一個簡單的 POST 用 Infura 提供的節點呼叫一個 RPC。有哪些 RPC method 可以看 [Ethereum RPC doc](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction)。

如果要呼叫的 function 只是查詢,而沒有要更新合約的狀態,那就用 `eth_call` 這個 RPC。POST Data 如下:

    {
        "jsonrpc":"2.0",
        "method":"eth_call",
        "params":[
            {
                "to":"0x86Fa049857E0209aa7D9e616F7eb3b3B78ECfdb0",
                "data":"0x70a0823100000000000000000000000033b8287511ac7F003902e83D642Be4603afCd876"
            },
            "latest"
        ],
        "id":123
    }

其中 `params` 的值包含:

- `"to"`:合約地址
- `"data"`:丟給合約的參數。由三個部分組成:`0x`、`70a08231`和一個 32 bytes 的參數 `00000000000000000000000033b8287511ac7F003902e83D642Be46`(也就是我要查詢的帳戶)
- `"latest"`,代表使用最新的區塊鏈資料

#### 範例

    // Request
    curl https://mainnet.infura.io/<your-api-key> -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x86Fa049857E0209aa7D9e616F7eb3b3B78ECfdb0", "data":"0x70a0823100000000000000000000000033b8287511ac7F003902e83D642Be4603afCd876"}, "latest"],"id":123 }'

    // Result
    {
        "jsonrpc": "2.0",
        "id": 123,
        "result": "0x000000000000000000000000000000000000000000000000b1d16ec625a59d3e"
    }

`0x000000000000000000000000000000000000000000000000b1d16ec625a59d3e` 是十六進位,換算成十進位是 `12813144212159962430`。也就是小弟只有少少的 **12.x** 個 EOS token。

---

## web3.js(JavaScript API)

如果要更新合約的狀態,就需要送 transaction,要送 transaction 就需要錢包或是說 private key 來 sign transaction 和提供 Ether 做手續費。因為送 transaction 要手續費,為了省點錢,我就部一個合約在 **Ropsten 測試鏈**上做這次的試驗。以上步驟比較麻煩,**我就用 web3.js 寫兩個簡單的程式,一個查詢合約狀態、一個更新合約狀態**。web3.js 的功能和 RPC 差不多,但是個 JavaScript 套件。有哪些 API 可以用請看 [JavaScript API doc](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3versionapi)。

### 安裝

    npm install web3, ethereumjs-tx
    
### 官方建議的初始化方式

    var Web3 = require('web3');

    if (typeof web3 !== 'undefined') {
        web3 = new Web3(web3.currentProvider);
    } else {
        // set the provider you want from Web3.providers
        web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/<your-api-key>"));
    }

### 部署測試合約

這次部署一個很簡單的合約。合約只儲存一個狀態 `data`,並可透過 `set()` 更新狀態。

合約程式碼:

    pragma solidity ^0.4.19;

    contract SimpleStorage {
        uint public data;
        
        function set(uint x) public {
            data = x;
        }
    }

合約地址:`0x5fb30123b9efedcd15094266948fb7c862279ee1`

合約的 function signatures:

    {
        "73d4a13a": "data()",
        "60fe47b1": "set(uint256)"
    }

---

### 查詢合約狀態

使用 `web3.eth.call`。

    // Request
    var result = web3.eth.call({
        to: "0x5fb30123b9efedcd15094266948fb7c862279ee1", 
        data: "0x" + "73d4a13a"
    });

    // Print Result
    console.log(parseInt(result, 16));

Print 出來結果會是 `0`,因為還沒更新過狀態。

---

### 更新合約狀態

使用 `web3.eth.sendRawTransaction`。

> RPC 和 web3.js 提供的 `SendTransaction` 都是連到一節點,使用節點中的帳戶發送 transaction。而如果要用自己的帳戶就要用 `sendRawTransaction`,也就是說要自己建立 transaction、自己 sign 過,再透過 `sendRawTransaction` 發送。

#### Define raw transaction

    var rawTx = {
        nonce: '0x14',
        gasPrice: '0x3B9ACA00', 
        gasLimit: '0xC20A',
        to: '0x5fb30123b9efedcd15094266948fb7c862279ee1', 
        value: '0x00', 
        data: '0x' + '60fe47b1' + '000000000000000000000000000000000000000000000000000000000000000a'
    }

`rawTx` 中包含:

- `nonce`:紀錄目前帳戶送出的交易數,用來避免 replay attack,每次送要加 1。可以用 RPC `eth_getTransactionCount` 查詢目前帳戶的 nonce。也可以用 Etherscan 查,但 Etherscan 顯示的 `No Of Transactions` 會包含送出去但沒有成功的交易,所以會不準
- `gasPrice`:一般用 1 Gwei(= 1000000000 = 0x3B9ACA00)
- `gasLimit`:gaslimit 估算可參考 [使用ethereum browser計算gas cost](https://medium.com/taipei-ethereum-meetup/%E4%BD%BF%E7%94%A8ethereum-browser%E8%A8%88%E7%AE%97gas-cost-9122950a04f7)
- `to`:合約地址
- `value`:要送的 Ether 數量,因為只是要呼叫合約所以設 0
- `data`:丟給合約的參數。由三個部分組成:`0x`、`60fe47b1`和一個 32 bytes 的參數 `000000000000000000000000000000000000000000000000000000000000000a`(我要更新的值,這邊設 10)

#### Create and Sign raw transaction

要引入另一個套件 `ethereumjs-tx`。記得先用 npm 安裝。
    
    var Tx = require('ethereumjs-tx');

建立 raw transaction。

    var tx = new Tx(rawTx);

用自己的 private key sign。

    const privateKey = new Buffer('<your-private-key>', 'hex')
    tx.sign(privateKey);

#### Send raw transaction

    var serializedTx = tx.serialize();
    web3.eth.sendRawTransaction('0x' + serializedTx.toString('hex'), function(err, hash) {
        if (!err) {
            console.log(hash);
        } else {
            console.log(err)
        }
    });

#### Result

成功就會回傳一個 transaction hash,像是:

    0x2a9d89b0f329853b5c0f83c83cea4cfa2e38ddd1041d9abd0afcc9af5ed1bf1b

交易成功送出且被收進 block 後,再次查詢合約狀態,Print 出來結果就會是 **10**。

可以透過 Etherscan 確認交易有沒有被收進 block 以及合約執行的結果(可能因為參數錯誤導致執行失敗)。

![https://ropsten.etherscan.io/tx/0x2a9d89b0f329853b5c0f83c83cea4cfa2e38ddd1041d9abd0afcc9af5ed1bf1b](https://i.imgur.com/RdDK54y.png)

## References

- [在區塊鏈上建立可更新的智慧合約(一)](https://medium.com/@twedusuck/%E5%9C%A8%E5%8D%80%E5%A1%8A%E9%8F%88%E4%B8%8A%E5%BB%BA%E7%AB%8B%E5%8F%AF%E6%9B%B4%E6%96%B0%E7%9A%84%E6%99%BA%E6%85%A7%E5%90%88%E7%B4%84-cbe015bdb339)
- [Ethereum JSON RPC Document](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactioncount)
- [We3.js API Document](https://github.com/ethereum/wiki/wiki/JavaScript-API)
👍  , , , ,
properties (23)
authorankar
permlinkethereum-infura-web3-js
categorycn
json_metadata{"tags":["cn","blockchain","ethereum","infura","web3"],"image":["https://i.imgur.com/doEO8gu.jpg","https://i.imgur.com/yz9kOFo.png","https://i.imgur.com/vVx5L4A.png","https://i.imgur.com/YRtWIGr.png","https://i.imgur.com/RdDK54y.png"],"links":["https://infura.io/signup","https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction","https://github.com/ethereum/wiki/wiki/JavaScript-API#web3versionapi","https://medium.com/taipei-ethereum-meetup/%E4%BD%BF%E7%94%A8ethereum-browser%E8%A8%88%E7%AE%97gas-cost-9122950a04f7","https://medium.com/@twedusuck/%E5%9C%A8%E5%8D%80%E5%A1%8A%E9%8F%88%E4%B8%8A%E5%BB%BA%E7%AB%8B%E5%8F%AF%E6%9B%B4%E6%96%B0%E7%9A%84%E6%99%BA%E6%85%A7%E5%90%88%E7%B4%84-cbe015bdb339","https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactioncount","https://github.com/ethereum/wiki/wiki/JavaScript-API"],"app":"steemit/0.1","format":"markdown"}
created2018-01-26 10:45:54
last_update2018-01-29 03:57:42
depth0
children6
last_payout2018-02-02 10:45:54
cashout_time1969-12-31 23:59:59
total_payout_value0.033 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length6,230
author_reputation130,030,985,850
root_title"【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id32,440,179
net_rshares4,002,631,740
author_curate_reward""
vote details (5)
@cn-naughty.boy ·
@ankar, 帅呆了!
properties (22)
authorcn-naughty.boy
permlink20180126t104551219z-post
categorycn
json_metadata{"tags":["cn"]}
created2018-01-26 10:46:18
last_update2018-01-26 10:46:18
depth1
children0
last_payout2018-02-02 10:46:18
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length12
author_reputation803,970,857,060
root_title"【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id32,440,255
net_rshares0
@coin.info ·
**Coins mentioned in post:**

Coin | | Price (USD) | 📉 24h | 📈 7d
- | - | - | - | -
**AE** | Aeternity | 2.179$ | _4.49%_ | _41.71%_
**EOS** | EOS | 13.420$ | _-4.43%_ | _21.64%_
**ETH** | Ethereum | 1014.840$ | _-4.38%_ | _-4.61%_
**ZRX** | 0x | 1.567$ | _-3.62%_ | _-11.2%_
properties (22)
authorcoin.info
permlinkre-ankar-ethereum-infura-web3-js-20180126t121542019z
categorycn
json_metadata{"app":"coininfo/1.0.0","format":"markdown"}
created2018-01-26 12:15:42
last_update2018-01-26 12:15:42
depth1
children0
last_payout2018-02-02 12:15:42
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length275
author_reputation133,144,230,969
root_title"【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id32,458,405
net_rshares0
@pupujiang ·
6666.......主要是為了更新合約嗎?
properties (22)
authorpupujiang
permlinkre-ankar-ethereum-infura-web3-js-20180413t094922090z
categorycn
json_metadata{"tags":["cn"],"app":"steemit/0.1"}
created2018-04-13 09:49:21
last_update2018-04-13 09:49:21
depth1
children0
last_payout2018-04-20 09:49:21
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length22
author_reputation357,902,631
root_title"【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id49,827,254
net_rshares0
@steemitboard ·
Congratulations @ankar! You have received a personal award!

[![](https://steemitimages.com/70x70/http://steemitboard.com/@ankar/birthday1.png)](http://steemitboard.com/@ankar)  1 Year on Steemit
Click on the badge to view your own Board of Honor on SteemitBoard.

> By upvoting this notification, you can help all Steemit users. Learn how [here](https://steemit.com/steemitboard/@steemitboard/http-i-cubeupload-com-7ciqeo-png)!
properties (22)
authorsteemitboard
permlinksteemitboard-notify-ankar-20180210t071120000z
categorycn
json_metadata{"image":["https://steemitboard.com/img/notifications.png"]}
created2018-02-10 07:11:21
last_update2018-02-10 07:11:21
depth1
children0
last_payout2018-02-17 07:11:21
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length428
author_reputation38,975,615,169,260
root_title"【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id36,350,885
net_rshares0
@steemitboard ·
Congratulations @ankar! You received a personal award!

<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@ankar/birthday2.png</td><td>Happy Birthday! - You are on the Steem blockchain for 2 years!</td></tr></table>

<sub>_[Click here to view your Board](https://steemitboard.com/@ankar)_</sub>


> Support [SteemitBoard's project](https://steemit.com/@steemitboard)! **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**!
properties (22)
authorsteemitboard
permlinksteemitboard-notify-ankar-20190210t074817000z
categorycn
json_metadata{"image":["https://steemitboard.com/img/notify.png"]}
created2019-02-10 07:48:18
last_update2019-02-10 07:48:18
depth1
children0
last_payout2019-02-17 07:48:18
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length529
author_reputation38,975,615,169,260
root_title"【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id79,652,706
net_rshares0
@steemitboard ·
Congratulations @ankar! You received a personal award!

<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@ankar/birthday3.png</td><td>Happy Birthday! - You are on the Steem blockchain for 3 years!</td></tr></table>

<sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@ankar) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=ankar)_</sub>


###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes!
properties (22)
authorsteemitboard
permlinksteemitboard-notify-ankar-20200210t071351000z
categorycn
json_metadata{"image":["https://steemitboard.com/img/notify.png"]}
created2020-02-10 07:13:51
last_update2020-02-10 07:13:51
depth1
children0
last_payout2020-02-17 07:13:51
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length608
author_reputation38,975,615,169,260
root_title"【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id95,280,164
net_rshares0