以太坊提供了一套基于 JSON-RPC 的接口调用,通过这些接口调用我们可以方便的进行相关的查询、挖矿、发起交易等操作。今天带大家了解一下比较常见的一些 JSON-RPC 接口。
什么是 JSON-RPC
JSON RPC(Remote Protocol Call)是一种以 JSON 为协议的远程调用服务,具有开发调试简单、多平台通用的特性。
很明显是通过 JSON 格式的消息来调用远程的服务器,可以通过 HTTP 传输协议来调用,请求的基本格式如下:
{
"jsonrpc" : 2.0,
"method" : "sayHello",
"params" : ["Hello JSON-RPC"],
"id" : 1
}
- jsonrpc:定义 JSON-RPC 版本。
- method:调用的方法名。
- params:方法传入的参数,若无参数则为 null。
- id:调用标识符,可以为字符串,不推荐包含小数(不能准确二进制化),或为 null(可能引起混乱)。
相应结果格式:
{
"jsonrpc" : 2.0,
"result" : "HelloJSON-RPC",
"error" : null,
"id" : 1
}
- jsonrpc:定义 JSON-RPC 版本。
- result:方法返回值,调用成功时,不能为 null,调用错误时,必须为 null。
- error:调用时错误,无错误返回 null,有错误时则返回一个错误对象。
- id:调用标识符,与调用方传入的标识一致,当请求中的 id 检查发生错误时(转换错误/无效请求),则必须返回 null。
以太坊的 JSON-RPC 官方文档
以太坊 JSON-RPC 官方文档地址详见这里,需要注意的是,此链接所对应的 JSON-RPC 只是针对 ETH 角色可操作的一些方法。
以太坊的常见操作角色
在以太坊启动的章节中我们介绍了 rpcapi 的使用,其中它的参数值便是以太坊可以操作的角色。只有在启动时添加了对应的角色,才能获得相应的操作权限。
- eth:最常见最普遍的操作,也就是上面我们提供的链接里面指定的操作;
- admin:geth 节点管理;
- debug:可开启 debug 模式;
- miner:挖矿和 DAG 管理;
- personal:账户管理;
- txpool:交易池检查;
- net:节点网络情况。
net 常用接口
net_peerCount
查看当前节点所链接的其他节点数,在同步的过程中经常使用到。对应控制台的操作为:
> net.peerCount
0
ETH 常用接口
对于 ETH 常用的接口,我们已经在前面的章节中使用到过,这里介绍一下一些常用接口的基本功能,至于具体参数使用可参考官方文档。
(1)eth_syncing
查看同步情况的接口,在同步的过程中经常使用到。
>eth.syncing
false
(2)eth_coinbase
查看 coinbase 地址使用:
> eth.coinbase
"0xadce6e0e1ee491e7c1945e76d3dc5975418c4e45"
(3)eth_accounts
查看当前节点下的所有账户:
> eth.accounts
["0xadce6e0e1ee491e7c1945e76d3dc5975418c4e45"]
(4)eth_blockNumber
查看当前区块的高度,这也是我们经常使用的一个接口:
> eth.blockNumber
17
(5)eth_getBalance
查询地址余额:
> eth.getBalance("0xadce6e0e1ee491e7c1945e76d3dc5975418c4e45")
1.15792089237316195423570985008687907853269984665640564039457584007913129639927e+77
(6)eth_sign
对交易或数据进行签名操作,签名之前需要对账户进行解锁操作:
> eth.sign("0xadce6e0e1ee491e7c1945e76d3dc5975418c4e45",web3.sha3("abc"))
"0x55998b5f4ac28fc61ea245b9430ac9310d8eec50d72a34e2bb6478c15539211f6da254978a19ab054b99860658d439b58949e8d0d8f7751c67b747cb6f18f2f71c"
(7)eth_sendTransaction
发起一笔交易,需要注意的是发起交易之前需要对发起交易的账户进行解锁操作:
eth.sendTransaction({from:"0x1ece51bdb1f056f929da51c2fe0a31beeea89ab3",to:"0xdae19174969a7404e222c24b6726e4d089c12768",value:web3.toWei(10,"ether")});
在非生成环境中常用此种模式操作,但在真是生产中不建议使用此方法进行操作。
(8)eth_sendRawTransaction
广播已经签名的交易信息:
> eth.sendRawTransaction("0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675")
(9)eth_getBlockByNumber/eth_getBlockByHash
根据区块编号或区块 hash 值查询区块信息:
> eth.getBlock(1)
{
difficulty: 2,
extraData: "0xd883010703846765746887676f312e392e328664617277696e00000000000000a688730e4607f919aaaf066924841a3301915e6a3c1027f159b2144d4de3776631ddcc14da21367d32965b5f8fa1a62e4651f73bfbc78fdf037fc2df6d176d3a00",
gasLimit: 6277051,
gasUsed: 0,
hash: "0x3fe3df4301921aea1cd45b3f05cb07f312127f09a5ccf86a8aef12900a3a0a53",
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
miner: "0x0000000000000000000000000000000000000000",
mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
nonce: "0x0000000000000000",
number: 1,
parentHash: "0x419c07af30010de2e402dd92ce8e75c44a01f6c6a5f2be31f9ca9cc757e277dd",
receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 606,
stateRoot: "0x90b4c8110bb9a2b2e79ff708419f9e9fe4aba5d68e2c835bf9cc619b882d588c",
timestamp: 1522632839,
totalDifficulty: 3,
transactions: [],
transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
uncles: []
}
(10)eth_getTransactionByHash
根据交易 hash 查询交易信息:
> eth.getTransaction("0x33ea5ff9bd71de24bab82a9adc5cd9482ddd0fa3ad62e35497039b28019c6ab1")
{
blockHash: "0x8e78b71ec851395dae17fbf80709b0ce4d88a8ef86e893a2510ae8fa3d9d2990",
blockNumber: 18,
from: "0xadce6e0e1ee491e7c1945e76d3dc5975418c4e45",
gas: 90000,
gasPrice: 1,
hash: "0x33ea5ff9bd71de24bab82a9adc5cd9482ddd0fa3ad62e35497039b28019c6ab1",
input: "0x",
nonce: 0,
r: "0xfc5d47a02921a42fae148d9aeb5673371acb9f5b72adbaa6ccf3a75598fcea6",
s: "0x17379fd37ca9992f1184a8c024f52584720dba0cdbc10342ff68c24d4cde6aa7",
to: "0x5929a871f57a1c5f7e4ea304cae92dacd1c1556b",
transactionIndex: 0,
v: "0xa95",
value: 10000000000000000
}
(11)ETH 其他接口
ETH 还提供了丰富的其他操作接口,比如智能合约的发布调用,Filter 的监听使用等,不在这里一一展开,大家可以参考文档自行研究,后面针对 Java 版本,我们还会讲到 Java 版本中的 Web3j 调用,智能合约使用。
admin 常用接口
(1)addPeer 接口
给当前节点添加其他节点链接,在前面的章节中我们已经使用到了:
>admin.addPeer("enode://0d1b9eed7afe2d5878d5d8a4c2066b600a3bcac2e5730586421af224e93a58cd03cac75bf0b2a62fd8049cd3692a085758cc1e407c8b2c94bb069814a5e8d0f0@209.9.106.245:30303")
true
(2)peers 接口
查看当前节点链接的节点:
> admin.peers
[]
debug 常用接口
(1)traceTransaction
traceTransaction 调试方法将尝试以与在网络上执行相同的方式运行事务,也就是说会回放之前的交易:
> debug.traceTransaction("0x2059dd53ecac9827faad14d364f9e04b1d5fe5b506e3acc886eff7a6f88a696a")
{
gas: 85301,
returnValue: "",
structLogs: [{
depth: 1,
error: "",
gas: 162106,
gasCost: 3,
memory: null,
op: "PUSH1",
pc: 0,
stack: [],
storage: {}
},
/* snip */
{
depth: 1,
error: "",
gas: 100000,
gasCost: 0,
memory: ["0000000000000000000000000000000000000000000000000000000000000006", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000060"],
op: "STOP",
pc: 120,
stack: ["00000000000000000000000000000000000000000000000000000000d67cbec9"],
storage: {
0000000000000000000000000000000000000000000000000000000000000004: "8241fa522772837f0d05511f20caa6da1d5a3209000000000000000400000001",
0000000000000000000000000000000000000000000000000000000000000006: "0000000000000000000000000000000000000000000000000000000000000001",
f652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f: "00000000000000000000000002e816afc1b5c0f39852131959d946eb3b07b5ad"
}
}]
通过此方法,可以查看到交易花费的 Gas,是否有错误,错误信息是什么等,对于验证发出的交易是否成功有很大帮助。
miner 常用接口
(1)setGasPrice
设置默认的 GasPrice,这样当发出交易时未指定 Gas Price,则使用默认的。
> miner.setGasPrice(2)
true
(2)start/stop
这两个操作已经在前面提到过,就是启动挖矿和停止挖矿:
miner.start()
// 或
miner.start(1)
miner.stop()
(3)setEtherbase
修改 coinbase,如果挖矿的接收地址变了,可使用此方法来进行修改:
> miner.setEtherbase("0xadce6e0e1ee491e7c1945e76d3dc5975418c4e45")
true
personal 常用接口
(1)listAccounts
查看当前节点下面的所有账号信息:
> personal.listAccounts
["0xadce6e0e1ee491e7c1945e76d3dc5975418c4e45", "0x1ece51bdb1f056f929da51c2fe0a31beeea89ab3", "0xdae19174969a7404e222c24b6726e4d089c12768"]
(2)newAccount
创建一个新的账号,此方法有两种模式,一个是把密码当做参数直接传入,一种是先执行命令,然后在控制台写入密码:
> personal.newAccount("123456")
"0x1ece51bdb1f056f929da51c2fe0a31beeea89ab3"
(3)unlockAccount
解锁账户,上面已经提到,某些操作需要先将账户解锁,然后才能进行相应的操作:
> personal.unlockAccount("0xdae19174969a7404e222c24b6726e4d089c12768")
Unlock account 0xdae19174969a7404e222c24b6726e4d089c12768
Passphrase:
true
实战经验
此处需注意的是解锁账户是有时间限制的,默认解锁 5 分钟,可通过参数进行限制,建议解锁之后完成相应的操作马上把账户锁定。很多同学由于 JSON-RPC 公网开放,结果在解锁期间被黑客调用转账接口将余额全部转走,导致资产严重损失。
lockAccount
锁定账户:
> personal.lockAccount("0xdae19174969a7404e222c24b6726e4d089c12768")
true
对应上面的解锁账户。
sendTransaction
发送交易,与上面的 eth.sendTransaction 功能一样,不过此方法在 personal 下,可以直接通过密码解锁发送交易:
> personal.sendTransaction({from:"0x1ece51bdb1f056f929da51c2fe0a31beeea89ab3",to:"0xdae19174969a7404e222c24b6726e4d089c12768",value:web3.toWei(1,"ether")},"123456")
"0x3c662d12a67a1d68a3db2747abd346d0a058596217b7637ea474c2e7f801077f"
需要注意的是在真实生产环境中慎用此接口,很容易导致密码泄露或资金安全的问题。
txpool 常用接口
content
查看 txpool 中待打包交易的情况,其中 txpool 又包含 pending 和 queued 两个队列:
> txpool.content
{
pending: {
0xdAE19174969A7404e222c24B6726E4D089c12768: {
0: {
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
blockNumber: null,
from: "0xdae19174969a7404e222c24b6726e4d089c12768",
gas: "0x15f90",
gasPrice: "0x1",
hash: "0x2784a79a8c454c72700e7be3b31c1c98ceaea232ca4992a6830b0fc999ebb653",
input: "0x",
nonce: "0x0",
r: "0xdabcd46d8d0b61e468d9f10119d544437f89cd094c35a89e5cbed298faf52c4a",
s: "0x3670f23ecfb0a12e982a60438640fe042eefc50646a077de0244a8d67a84af9e",
to: "0x5929a871f57a1c5f7e4ea304cae92dacd1c1556b",
transactionIndex: "0x0",
v: "0xa95",
value: "0x2386f26fc10000"
}
}
},
queued: {
0xdAE19174969A7404e222c24B6726E4D089c12768: {
2: {
blockHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
blockNumber: null,
from: "0xdae19174969a7404e222c24b6726e4d089c12768",
gas: "0x15f90",
gasPrice: "0x4e3b29200",
hash: "0x7db7883bb23a31deb9f01b5e6fb28363b1aee1b9b6797ea8b5706be170a1187c",
input: "0x",
nonce: "0x2",
r: "0xa8953a87c326c02da9d7a712d6c7ac0cd415cbc71ea0c24423f9e01b1fec65bd",
s: "0x3faefc3a0db585a67f02996a7167890e41ff5fd8fd4be6efff3bea7a797fad29",
to: "0x5929a871f57a1c5f7e4ea304cae92dacd1c1556b",
transactionIndex: "0x0",
v: "0xa96",
value: "0x2386f26fc10000"
}
}
}
}
实战经验
txpool 内容的查看涉及 nonce 值错误或交易迟迟未打包情况的排查,通过 txpool 还可以让一些因手续费过低未被打包的交易失效,有下面两种情况:
- 如果不传入 nonce 值,那么 Geth 节点会默认计算当前地址已经发起了的交易中最大的 nonce 值为多少,然后将其 +1,然后将此交易放置在 pending 中,等待节点打包。
- 如果传入的 nonce 值过大,在进入 txpool 中检查到它之前的 nonce 并没有使用过,那么此笔交易不会发送到 pending 中,而且放置在 queued 中。只有当前面的 nonce 补齐之后,才会进入到 pending 中。
另外,可以通过设置 txpool.lifetime 参数来让发出的迟迟未成功的交易失效。
安全
最后还是要强调一下,JSON-RPC 接口的访问权限控制一定要进行严格的网络限制,不然会很容易导致资产损失。最好只开放部分 RPC 接口,并且要限制仅内网指定 IP 访问,其他服务器安全措施也要相应跟上。