• 如何部署、调用智能合约


    RPC

    之前的章节中我们看到了怎么写、部署合约以及与合约互动。现在该讲讲与以太坊网络和智能合约沟通的细节了。

    一个以太坊节点提供一个RPC界面。这个界面给Ðapp访问以太坊区块链的权限和节点提供的功能,比如编译智能合约代码,它用JSON-RPC 2.0规范(不支持提醒和命名的参数) 的子集作为序列化协议,在HTTP和IPC (linux/OSX上的unix域接口,在Windows上叫pipe’s)上可用。

    如果你对细节不感兴趣,正在寻找使用javascript库的简便方法,你可以略过下面的章节,从Using Web3继续。

    惯例

    RPC界面使用一些惯例,它们不是JSON-RPC 2.0规范的一部分:

    • 数字是十六进制编码。做这个决定是因为有些语言对运行极大的数字没有或有很少的限制。为了防止这些错误数字类型是十六进制编码,由开发者来分析这些数字并正确处理它们。在维基页百科查看十六进制编码章节查看案例。
    • 默认区块数字,几个RPC 方法接受区块数字。在一些情况下,给出区块数字是不可能的或者不太方便。 在那样的情况下,默认区块数字可以是以下字符串中的一个[”earliest”, “latest”, “pending”]。在维基页面查看使用默认区块参数的RPC方法列表。

    部署合约

    我们会通过不同的步骤来部署下面的合约,只用到RPC界面。

    1
    2
    3
    4
    5
    6
    7
    
    contract Multiply7 {
       event Print(uint);
       function multiply(uint input) returns (uint) {
          Print(input * 7);
          return input * 7;
       }
    }

    要做的第一件事是确保HTTP RPC界面可用。这意味着我们在开始为geth供应—rpc标志,为eth提供-j标志。在这个例子中我们用私有开发链上的geth节点。通过这种方法,我们就不需要真实网络上的以太币了。

    1
    
    > geth --rpc --dev --mine --minerthreads 1 --unlock 0 console 2>>geth.log

    这会在http://localhost:8545 上启动HTTP RPC界面。

    注意:geth支持CORS查看—rpccorsdomain标志了解更多。

    我们可以通过用curl检索coinbase地址和余额来证明界面正在运行。请注意这些例子中的数据在你本地的节点上会有所不同。如果你想要试试这些参数,视情况替换需要的参数。

    1
    2
    3
    4
    
    > curl --data '{"jsonrpc":"2.0","method":"eth_coinbase", "id":1}' localhost:8545
    {"id":1,"jsonrpc":"2.0","result":["0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"]}
    > curl --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"], "id":2}' localhost:8545
    {"id":2,"jsonrpc":"2.0","result":"0x1639e49bba16280000"}

    记不记得我们说过数字是十六进制编码?在这个情况下,余额作为十六进制字符串以Wei的形式返还。如果我们希望余额作为数字以太币为单位,我们可以从控制台用web3。

    1
    2
    
    > web3.fromWei("0x1639e49bba16280000", "ether")
    "410"

    现在我们在私有开发链上有一些以太币,我们就可以部署合约了。第一步是验证solidity编译器可用。我们可以用eth_getCompilers RPC method方法来检索可用的编译器。

    1
    2
    
    > curl --data '{"jsonrpc":"2.0","method": "eth_getCompilers", "id": 3}' localhost:8545
    {"id":3,"jsonrpc":"2.0","result":["Solidity"]}

    我们可以看到solidity编译器可用。如果不可用,按照这些说明操作。

    下一步是把Multiply7合约编译到可以发送给以太坊虚拟机的字节代码。

    1
    2
    
    > curl --data '{"jsonrpc":"2.0","method": "eth_compileSolidity", "params": ["contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
    {"id":4,"jsonrpc":"2.0","result":{"Multiply7":{"code":"0x6060604052605f8060106000396000f360606040

    现在我们有了编译代码,需要决定花多少gas去部署它。RPC界面有eth_estimateGas方法,会给我们一个预估数量。

    1
    2
    
    > curl --data '{"jsonrpc":"2.0","method": "eth_estimateGas", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "data": "0x6060604052605f8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b60586004356007810260609081526000907f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da90602090a15060070290565b5060206060f3"}], "id": 5}' localhost:8545
    {"id":5,"jsonrpc":"2.0","result":"0xb8a9"}

    最后部署合约。

    1
    2
    
    > curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "gas": "0xb8a9", "data": "0x6060604052605f8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b60586004356007810260609081526000907f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da90602090a15060070290565b5060206060f3"}], "id": 6}' localhost:8545
    {"id":6,"jsonrpc":"2.0","result":"0x3a90b5face52c4c5f30d507ccf51b0209ca628c6824d0532bcd6283df7c08

    交易由节点接受,交易散表被返还。我们可以用这个散表来跟踪交易。

    下一步是决定部署合约的地址。每个执行的交易都会创建一个接收。这个接收包含交易的各种信息,比如交易被包含在哪个区块,以太坊虚拟机用掉多少gas。如果交易创建了一个合约,它也会包含合约地址。我们可以用eth_getTransactionReceipt RPC方法检索接收。

    1
    2
    
    > curl --data '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": ["0x3a90b5face52c4c5f30d507ccf51b0209ca628c6824d0532bcd6283df7c08a7c"], "id": 7}' localhost:8545
    {"id":7,"jsonrpc":"2.0","result":{"transactionHash":"0x3a90b5face52c4c5f30d507ccf51b0209ca628c682

    我们可以看到合约在0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d上被创建。如果你得到了零而不是接收,说明还没有被纳入区块。等一下,检查看看你的矿工是否在运行,重新试一遍。

    和智能合约互动

    现在已经部署了合约,我们可以和它互动了。有两种方法,发送交易或像之前所介绍的那样使用调用。在这个例子中,我们会发送交易到合约的multiply方法。

    如果我们看eth_sendTransaction 的档案,可以发现我们需要提供几个参数。

    在我们的实例中,需要具体说明from, to 和data参数。From是我们账户的公共地址,to是合约地址。Data参数有一点困难。它包括了规定调用哪个方法和哪个参数的负载量。这就需要ABI发挥作用了。ABI规定了如何为以太坊虚拟机规定和编码数据。你可以在这儿阅读ABI的所有具体信息。

    负载量的字节是功能选择符,规定了调用哪个方法。它取Keccak散表的头4个字节,涵盖功能名称参数类型,并进行十六进制编码。multiply功能接受一个单元,也就是uint256的别名。这就让我们进行:

    1
    2
    
    > web3.sha3("multiply(uint256)").substring(0, 8)
    "c6888fa1"

    在此页查看细节。

    下一步是编码参数。我们只有一个unit256,让我们假定提供了值6。ABI有一个章节规定了怎么编码uint字节。

    int: enc(X) is the big-endian two’s complement encoding of X, padded on the higher-oder (left) side with 0xff for negative X and with zero 字节s for positive X such that the length is a multiple of 32 bytes.

    它编码到0000000000000000000000000000000000000000000000000000000000000006. 将功能选择符和编码参数结合起来,数据就会变成0xc6888fa10000000000000000000000000000000000000000000000000000000000000006.

    我们来试一下:

    1
    2
    
    > curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "to": "0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d", "data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}], "id": 8}' localhost:8545
    {"id":8,"jsonrpc":"2.0","result":"0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869

    由于我们发送了交易,于是有交易散表返回。如果我们检索接收,可以看到一些新内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    {
    blockHash: "0xbf0a347307b8c63dd8c1d3d7cbdc0b463e6e7c9bf0a35be40393588242f01d55", blockNumber: 268,
    contractAddress: null,
    cumulativeGasUsed: 22631,
    gasUsed: 22631,
    logs: [{
          address: "0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d",
          blockHash: "0xbf0a347307b8c63dd8c1d3d7cbdc0b463e6e7c9bf0a35be40393588242f01d55",
          blockNumber: 268,
          data: "0x000000000000000000000000000000000000000000000000000000000000002a",
          logIndex: 0,
          topics: ["0x24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"],
          transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74",
          transactionIndex: 0
      }],
      transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74",
      transactionIndex: 0
    }

    接收包含一个日志。日志由以太坊虚拟机在交易执行时生成,包含接收。如果我们看Multiply功能,可以看到打印事件和输入次数7一起被提出。由于打印事件的参数是uint256,我们可以根据ABI规则对它进行编码,这样我们就会得到预期的十进制42.。除数据外,主题用于决定什么事件来创建日志,是毫无意义的:

    1
    2
    
    > web3.sha3("Print(uint256)")
    "24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"

    你可以在Solidity教程中阅读更多关于事件,主题和索引的内容。

    这只是对一些最常见任务的简单介绍。在RPC维基页面查看可用RPC方法的完整列表。

    Web3.js

    正如我们在之前的案例所见,使用JSON-RPC界面相当单调乏味且容易出错,尤其是在处理ABI的时候。Web3.js是javascript库,在以太坊RPC界面顶端。它的目标是提供更友好的界面,减少出错机会。

    用web3部署Multiply7合约看起来是这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    var source = 'contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint
    var compiled = web3.eth.compile.solidity(source);
    var code = compiled.Multiply7.code;
    var abi = compiled.Multiply7.info.abiDefinition;
    web3.eth.contract(abi).new({from: "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", data: code}, func
       if (!err && contract.address)
          console.log("deployed on:", contract.address);
       }
    );
    deployed on: 0x0ab60714033847ad7f0677cc7514db48313976e2

    装载一个部署的合约,发送交易:

    1
    2
    3
    4
    5
    
    var source = 'contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
    var compiled = web3.eth.compile.solidity(source);
    var Multiply7 = web3.eth.contract(compiled.Multiply7.info.abiDefinition);
    var multi = Multiply7.at("0x0ab60714033847ad7f0677cc7514db48313976e2")
    multi.multiply.sendTransaction(6, {from: "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"})

    注册一个回调,打印事件创建日志的时候会被调用。

    1
    2
    
    multi.Print(function(err, data) { console.log(JSON.stringify(data)) })
    {"address":"0x0ab60714033847ad7f0677cc7514db48313976e2","args": {"":"21"},"blockHash":"0x259c7dc0

    在web3.js维基页面查看更多信息。

    控制台

    geth控制台提供命令行界面和javascript执行时间。它可以连接到本地或远程的geth或eth节点。它会装载用户能使用的web3.js库。这会允许用户从控制台用web3.js部署智能合约并和智能合约互动。实际上Web3.js章节的例子可以被复制进控制台。

    查看合约与交易

    有几个可用的在线区块链浏览器,能让你查询以太坊区块链。

    查看列表:区块链浏览器。

    在线区块链浏览器

    • EtherChain
    • EtherCamp
    • EtherScan (为测试网)

    其他资源

    • EtherNodes – 节点的地理分配,由客户端区分
    • EtherListen – 实时以太坊交易可视器和可听器
  • 相关阅读:
    对GDI+绘制圆弧接口的理解
    陈灯可重用代码管理器(插件版最新版本:3.2;桌面版最新版本:2.3)
    Apache OpenJPA 2.1.0 发布
    B3log Solo 0.2.5.1 发布了!
    Apache OpenJPA 2.1.0 发布
    jsoup 1.5.1 发布,超棒的HTML解析器
    程序员阿士顿的故事
    Web 是开源最大的成功
    Web 是开源最大的成功
    Python执行系统命令的方法 os.system(),os.popen(),commands renwofei423的个人空间 开源中国社区
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13313417.html
Copyright © 2020-2023  润新知