rpc接口调用以太坊智能合约




传送门: 柏链项目学院



  在以太坊摸爬滚打有些日子了,也遇到了各种各样的问题。这几天主要研究了一下如何通过rpc接口编译、部署和调用合约。也遇到了一些困难和问题,下面将向大家分享。

rpc接口调用智能合约

  • 先来编写一个简单的智能合约
contract Multiply7 {
   event Print(uint);
   function multiply(uint input) returns (uint) {
      Print(input * 7);
      return input * 7;
   }
}
  • 这是输入一个无符号整数做乘法的合约,接下来想要用rpc接口编译它。编译之前先验证geth的solidity编译器是否可用
curl --data '{"jsonrpc":"2.0","method": "eth_getCompilers", "id": 3}' http://localhost:8545
  • 返回结果
HTTP/1.1 200 OK
Content-Type: application/json
Vary: Origin
Date: Fri, 20 Apr 2018 02:59:24 GMT
Content-Length: 121

{"jsonrpc":"2.0","id":3,"error":{"code":-32601,"message":"The method eth_getCompilers does not exist/is not available"}}
  • 这里竟然出现了eth_getCompilers方法不可用的错误,查阅资料后发现geth1.6以后的版本删除了这个功能,删除还包括eht.compile 等功能,至于删除原因详见https://github.com/ethereum/EIPs/issues/209

现在只好到remix ide上进行编译,编译通过后点击"Details",复制"WEB3DEPLOY"中的"data"数据,接下来部署合约

curl -i -H 'Content-Type:application/json' -d '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0x2a5026d44ab3de2094ec79dec074d4a8612a14aa", "gas": "0xfffff", "data": "0x608060405234801561001057600080fd5b5060f58061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa1146044575b600080fd5b348015604f57600080fd5b50606c600480360381019080803590602001909291905050506082565b6040518082815260200191505060405180910390f35b60007f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da600783026040518082815260200191505060405180910390a16007820290509190505600a165627a7a72305820d36dc369a6f3f653b02c492e077b9cfdb114054f44f46277eaa4826e968609010029"}], "id": 6}' http://localhost:8545
  • 部署合约用到eth_sendTransaction方法,其中from对应的是部署合约的账户地址,gas对应为gas消耗量,太少会报错。data对应的是之前复制的data

执行命令后返回了交易hasa

HTTP/1.1 200 OK
Content-Type: application/json
Vary: Origin
Date: Fri, 20 Apr 2018 14:00:58 GMT
Content-Length: 103

{"jsonrpc":"2.0","id":6,"result":"0xa31ad7bc958290c0b401ae4e046d6e93bc67db1cb038ba2953e2cffe6bdf60fa"}
  • 通过这个交易hasa可以查询部署合约的详细信息,我们可以用eth_getTransactionReceipt RPC方法验证一下
curl -i -H 'Content-Type:application/json' -d '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": ["0xa31ad7bc958290c0b401ae4e046d6e93bc67db1cb038ba2953e2cffe6bdf60fa"], "id": 7}' http://localhost:8545

在返回的信息中,contractAddress对应的内容就是合约的地址了

HTTP/1.1 200 OK
Content-Type: application/json
Vary: Origin
Date: Fri, 20 Apr 2018 14:05:03 GMT
Content-Length: 981

{"jsonrpc":"2.0","id":7,"result":{"blockHash":"0x5480323e9a5ac26ec585ca610cb15cffbfe26f2323e19fb8d8a967e11903d6a0","blockNumber":"0x5599","contractAddress":"0x21f981af36218aaf1a40621bfe1e57cf2f43455a","cumulativeGasUsed":"0x1ce23","from":"0x2a5026d44ab3de2094ec79dec074d4a8612a14aa","gasUsed":"0x1ce23","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":null,"transactionHash":"0xa31ad7bc958290c0b401ae4e046d6e93bc67db1cb038ba2953e2cffe6bdf60fa","transactionIndex":"0x0"}}
  • 拿到合约地址后,我们可以通过eth_sendTransaction调用合约
curl -i -H 'Content-Type:application/json' -d '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0x2a5026d44ab3de2094ec79dec074d4a8612a14aa","to":"0x21f981af36218aaf1a40621bfe1e57cf2f43455a","data":"0xc6888fa10000000000000000000000000000000000000000000000000000000000000007"}], "id": 6}' http://localhost:8545

from对应为调用合约的账户,to对应为要调用的合约地址。data对应为调用方法的签名和传入参数,那么我们怎么获取这个值呢,首先,它的编码方式是:sha3(“multiply(uint256)”).substring(0,10)+to_32bit_Hex_str(7)

在geth中输入:

> web3.sha3("multiply(uint256)").substring(0, 10)
"0xc6888fa1"

而参数输入为7,最后出结果为0000000000000000000000000000000000000000000000000000000000000007,加上前面的0xc6888fa1就得到了data的值。

通过eth_sendTransaction调用合约后返回:

HTTP/1.1 200 OK
Content-Type: application/json
Vary: Origin
Date: Fri, 20 Apr 2018 14:12:06 GMT
Content-Length: 103

{"jsonrpc":"2.0","id":6,"result":"0xbe0881901ee9e52c9e969a85a1367c4a8936c5ab77fa479aaee1c780fe5d1159"}

可以看到,返回了交易哈希,我们可以用这个交易哈希查询详细信息,验证是否正确,为了返回的数据格式更方便查看,我们可以在geth私有节点中输入获取交易详细信息的命令:

> eth.getTransactionReceipt("0xbe0881901ee9e52c9e969a85a1367c4a8936c5ab77fa479aaee1c780fe5d1159")

返回结果:

{
  blockHash: "0xeac4d7dd5123720ebc43fbc35778de2215738af97cf723721f0260335228eb93",
  blockNumber: 22581,
  contractAddress: null,
  cumulativeGasUsed: 22804,
  from: "0x2a5026d44ab3de2094ec79dec074d4a8612a14aa",
  gasUsed: 22804,
  logs: [{
      address: "0x21f981af36218aaf1a40621bfe1e57cf2f43455a",
      blockHash: "0xeac4d7dd5123720ebc43fbc35778de2215738af97cf723721f0260335228eb93",
      blockNumber: 22581,
      data: "0x0000000000000000000000000000000000000000000000000000000000000031",
      logIndex: 0,
      removed: false,
      topics: ["0x24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"],
      transactionHash: "0xbe0881901ee9e52c9e969a85a1367c4a8936c5ab77fa479aaee1c780fe5d1159",
      transactionIndex: 0
  }],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000004000000000000000000000000000002000000000000000000040000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000",
  status: "0x1",
  to: "0x21f981af36218aaf1a40621bfe1e57cf2f43455a",
  transactionHash: "0xbe0881901ee9e52c9e969a85a1367c4a8936c5ab77fa479aaee1c780fe5d1159",
  transactionIndex: 0
}

重点来了:我们来看一下返回数据中的logs,其中可能包含调用合约的结果。可以看到logs中也有个data,值为0x0000000000000000000000000000000000000000000000000000000000000031,把这个十六进制转换为十进制得到数字4949正好是7*7的结果,这说明我们调用合约的multiply方法成功了并得到了正确的结果。

  以太坊的JSON RPC API的用法还有很多,在这里就不一一介绍了。无论是web3.js还是web3j,都是对以太坊JSON RPC API开发接口的封装。研究JSON RPC API主要出于学习目的,开发DApp还是用web3.js方便一些。



image