abbshr.github.io icon indicating copy to clipboard operation
abbshr.github.io copied to clipboard

Biter loggers 4:bitcoind JSON-RPC

Open abbshr opened this issue 10 years ago • 0 comments

Note:第一篇bitcoin日志中介绍了JSON-RPC, 同时记录了启动bitcoind的基本方法。

使用bitcoin-explorer获取block chain中的数据,加以分析处理。这一过程的最开始就利用了JSON-RPC。拿insight为例,其后台insight-api中的核心bitcore就是用来和bitcoind进程通信的,而通信的方式就是JSON-RPC:insight进程向bitcoind进程发送RPC指令,并在回调中得到想要的数据,然后呈现给上层应用做数据可视化。

JSON-RPC

JSON-RPC协议的本质仍是HTTP协议,也就是说JSON-RPC在HTTP基础上进行通信的。 在2013年更新了2.0版本,bitcoind使用的就是JSON-RPC 2.0

  • 规定客户端发送JSON的格式:
jsonrpc: 用来指定JSON-RPC的版本,必须为2.0
method: 需要调用的方法名
params: 参数数组,
id: 由客户端建立的rpc标识符
  • 服务器响应格式:
jsonrpc: 同上
result: 服务器返回的结果,如果出现错误,就没有这个字段
error: 一个JSON对象,如果调用成功则没有这个字段
id: 与请求的id相同(如果请求失败,id为null)
Batch

客户端在同一时刻发送多个请求对象,这些请求对象包装在一个数组中。这时服务器返回的也是个数组,包含对应请求对象的响应。

client => [
        {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
        {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
        {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
        {"foo": "boo"},
        {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
        {"jsonrpc": "2.0", "method": "get_data", "id": "9"} 
] 

server => [
        {"jsonrpc": "2.0", "result": 7, "id": "1"},
        {"jsonrpc": "2.0", "result": 19, "id": "2"},
        {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
        {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
        {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
]

bitcoind

它是中本聪编写的BTC客户端,也是第一个BTC客户端。实现了BTC的相关协议,并提供了RPC通信接口,允许本机进程或远程主机与其通信。

为了方便起见,把bitcoind添加到alias:

echo "alias btcrpc=$HOME/bitcoind -conf=$HOME/bitcoin.conf" >> .bashrc

bitcoind提供了一大堆RPC API,列表详见: https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list

通过help命令也可以获取:

btcrpc help
addmultisigaddress nrequired ["key",...] ( "account" )
addnode "node" "add|remove|onetry"
backupwallet "destination"
createmultisig nrequired ["key",...]
createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...}
decoderawtransaction "hexstring"
decodescript "hex"
dumpprivkey "bitcoinaddress"
dumpwallet "filename"
encryptwallet "passphrase"
getaccount "bitcoinaddress"
getaccountaddress "account"
getaddednodeinfo dns ( "node" )
getaddressesbyaccount "account"
getbalance ( "account" minconf )
getbestblockhash
getblock "hash" ( verbose )
getblockcount
getblockhash index
getblocktemplate ( "jsonrequestobject" )
getconnectioncount
getdifficulty
getgenerate
gethashespersec
getinfo
getmininginfo
getnettotals
getnetworkhashps ( blocks height )
getnewaddress ( "account" )
getpeerinfo
getrawchangeaddress
getrawmempool ( verbose )
getrawtransaction "txid" ( verbose )
getreceivedbyaccount "account" ( minconf )
getreceivedbyaddress "bitcoinaddress" ( minconf )
gettransaction "txid"
gettxout "txid" n ( includemempool )
gettxoutsetinfo
getunconfirmedbalance
getwork ( "data" )
help ( "command" )
importprivkey "bitcoinprivkey" ( "label" rescan )
importwallet "filename"
keypoolrefill ( newsize )
listaccounts ( minconf )
listaddressgroupings
listlockunspent
listreceivedbyaccount ( minconf includeempty )
listreceivedbyaddress ( minconf includeempty )
listsinceblock ( "blockhash" target-confirmations )
listtransactions ( "account" count from )
listunspent ( minconf maxconf  ["address",...] )
lockunspent unlock [{"txid":"txid","vout":n},...]
move "fromaccount" "toaccount" amount ( minconf "comment" )
ping
sendfrom "fromaccount" "tobitcoinaddress" amount ( minconf "comment" "comment-to" )
sendmany "fromaccount" {"address":amount,...} ( minconf "comment" )
sendrawtransaction "hexstring" ( allowhighfees )
sendtoaddress "bitcoinaddress" amount ( "comment" "comment-to" )
setaccount "bitcoinaddress" "account"
setgenerate generate ( genproclimit )
settxfee amount
signmessage "bitcoinaddress" "message"
signrawtransaction "hexstring" ( [{"txid":"id","vout":n,"scriptPubKey":"hex","redeemScript":"hex"},...] ["privatekey1",...] sighashtype )
stop
submitblock "hexdata" ( "jsonparametersobject" )
validateaddress "bitcoinaddress"
verifychain ( checklevel numblocks )
verifymessage "bitcoinaddress" "signature" "message"

ex:

btcrpc getpeerinfo
[
    {
        "addr" : "127.0.0.1:35629",
        "services" : "00000001",
        "lastsend" : 1400043134,
        "lastrecv" : 1400043134,
        "bytessent" : 3357058,
        "bytesrecv" : 147242,
        "conntime" : 1400039657,
        "pingtime" : 0.00000000,
        "version" : 70000,
        "subver" : "/BitcoinX:0.1/",
        "inbound" : true,
        "startingheight" : 0,
        "banscore" : 0
    },
    {
        "addr" : "50.184.166.246:8333",
        "services" : "00000001",
        "lastsend" : 1400043145,
        "lastrecv" : 1400043133,
        "bytessent" : 122888,
        "bytesrecv" : 800499,
        "conntime" : 1400039658,
        "pingtime" : 0.00000000,
        "version" : 70001,
        "subver" : "/Satoshi:0.8.6/",
        "inbound" : false,
        "startingheight" : 300640,
        "banscore" : 0,
        "syncnode" : true
    },
    {
        "addr" : "67.212.92.167:8333",
        "services" : "00000001",
        "lastsend" : 1400043145,
        "lastrecv" : 1400043125,
        "bytessent" : 124584,
        "bytesrecv" : 749619,
        "conntime" : 1400039658,
        "pingtime" : 0.00000000,
        "version" : 70002,
        "subver" : "/Satoshi:0.9.1/",
        "inbound" : false,
        "startingheight" : 300640,
        "banscore" : 0
    },
    {
        "addr" : "174.78.248.214:8333",
        "services" : "00000001",
        "lastsend" : 1400043134,
        "lastrecv" : 1400043144,
        "bytessent" : 119650,
        "bytesrecv" : 388564,
        "conntime" : 1400039659,
        "pingtime" : 0.00000000,
        "version" : 70002,
        "subver" : "/Satoshi:0.9.1/",
        "inbound" : false,
        "startingheight" : 300640,
        "banscore" : 0
    },
    {
        "addr" : "89.98.93.137:8333",
        "services" : "00000001",
        "lastsend" : 1400043144,
        "lastrecv" : 1400043119,
        "bytessent" : 130925,
        "bytesrecv" : 1011629,
        "conntime" : 1400039666,
        "pingtime" : 0.00000000,
        "version" : 70002,
        "subver" : "/Satoshi:0.9.1/",
        "inbound" : false,
        "startingheight" : 300640,
        "banscore" : 0
    },
    {
        "addr" : "199.115.176.18:8333",
        "services" : "00000001",
        "lastsend" : 1400043135,
        "lastrecv" : 1400043127,
        "bytessent" : 345728,
        "bytesrecv" : 25299,
        "conntime" : 1400039675,
        "pingtime" : 0.00000000,
        "version" : 50000,
        "subver" : "",
        "inbound" : false,
        "startingheight" : 277595,
        "banscore" : 0
    },
    {
        "addr" : "108.53.129.182:8333",
        "services" : "00000001",
        "lastsend" : 1400043134,
        "lastrecv" : 1400043144,
        "bytessent" : 115329,
        "bytesrecv" : 359246,
        "conntime" : 1400039691,
        "pingtime" : 0.00000000,
        "version" : 70002,
        "subver" : "/Satoshi:0.9.1/",
        "inbound" : false,
        "startingheight" : 300640,
        "banscore" : 0
    },
    {
        "addr" : "107.170.211.129:8333",
        "services" : "00000001",
        "lastsend" : 1400043144,
        "lastrecv" : 1400043144,
        "bytessent" : 133227,
        "bytesrecv" : 992178,
        "conntime" : 1400039697,
        "pingtime" : 0.00000000,
        "version" : 70001,
        "subver" : "/Satoshi:0.8.5/",
        "inbound" : false,
        "startingheight" : 300640,
        "banscore" : 0
    },
    {
        "addr" : "24.159.17.178:8333",
        "services" : "00000001",
        "lastsend" : 1400043145,
        "lastrecv" : 1400043005,
        "bytessent" : 36944879,
        "bytesrecv" : 130539,
        "conntime" : 1400040379,
        "pingtime" : 0.00000000,
        "version" : 70002,
        "subver" : "/Satoshi:0.9.1/",
        "inbound" : false,
        "startingheight" : 181817,
        "banscore" : 0
    }
]

注意JSON-RPC不仅仅通信使用JSON格式,得到的结果当然也是JSON格式的啦。

其他方法

除了命令行的方式外,也有很多编程语言的wrapper以及curl工具:

curl

这是最Raw的方法,可以看到RPC交互的数据格式:

  curl --user user --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getinfo", "params": [] }' 
    -H 'content-type: text/plain;' http://127.0.0.1:8332/

返回:

  {"result":{"balance":0.000000000000000,"blocks":59952,"connections":48,"proxy":"","generate":false,
     "genproclimit":-1,"difficulty":16.61907875185736,"error":null,"id":"curltest"}
JavaScript

自然有人写模块啦,node下有很多wrap,这个例子(bitcoin模块)是来自官网的:

var bitcoin = require('bitcoin');
var client = new bitcoin.Client({
  host: 'localhost',
  port: 8332,
  user: 'user',
  pass: 'pass'
});

client.getDifficulty(function(err, difficulty) {
  if (err) {
    return console.error(err);
  }

  console.log('Difficulty: ' + difficulty);
});

abbshr avatar May 14 '14 04:05 abbshr