以太坊系列之十七: 使用web3進行合約部署調用以及監聽

以太坊系列之十七: 使用web3進行智能合約的部署調用以及監聽事件(Event)

上一篇介紹了使用golang進行智能合約的部署以及調用,可是使用go語言最大的一個問題是無法持續監聽事件的發生.
好比個人後臺程序須要監控誰給我轉帳了,若是使用go語言,目前就只能是輪詢數據,而使用web3就簡單許多,geth會把我關心的事件
主動通知給我.javascript

token合約

token合約是官方提供的一個樣例,這裏給出我修改過的版本,方便演示.html

contract MyToken {
    /* Public variables of the token */
    string public name;
    string public symbol;
    uint8 public decimals;

    /* This creates an array with all balances */
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint)) public allowance;
    mapping (address => mapping (address => uint)) public spentAllowance;

    /* This generates a public event on the blockchain that will notify clients */
    event Transfer(address indexed from, address indexed to, uint256 value);
    event ReceiveApproval(address _from, uint256 _value, address _token, bytes _extraData);

    /* Initializes contract with initial supply tokens to the creator of the contract */
    function MyToken(uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol) {
        balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens
        name = tokenName;                                   // Set the name for display purposes
        symbol = tokenSymbol;                               // Set the symbol for display purposes
        decimals = decimalUnits;                            // Amount of decimals for display purposes
    }

    /* Send coins */
    function transfer(address _to, uint256 _value) {
        if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough
        if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows
        balanceOf[msg.sender] -= _value;                     // Subtract from the sender
        balanceOf[_to] += _value;                            // Add the same to the recipient
        Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place
    }

    /* Allow another contract to spend some tokens in your behalf */

    function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        ReceiveApproval(msg.sender, _value, this, _extraData);
    }

    /* A contract attempts to get the coins */

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if (balanceOf[_from] < _value) throw;                 // Check if the sender has enough
        if (balanceOf[_to] + _value < balanceOf[_to]) throw;  // Check for overflows
        if (spentAllowance[_from][msg.sender] + _value > allowance[_from][msg.sender]) throw;   // Check allowance
        balanceOf[_from] -= _value;                          // Subtract from the sender
        balanceOf[_to] += _value;                            // Add the same to the recipient
        spentAllowance[_from][msg.sender] += _value;
        Transfer(msg.sender, _to, _value);
    }

    /* This unnamed function is called whenever someone tries to send ether to it */
    function () {
        throw;     // Prevents accidental sending of ether
    }
}

編譯token

經過solc編譯獲得的json abi以及hex編碼的code,因爲太長,太佔地方就不放上來了.java

這些會在部署以及調用的時候用到.
下面來經過web3進行合約的部署,讀取數據,發起事務以及監聽事件的發生.golang

部署合約

部署合約須要建立事務,話費gas,所以相關帳戶必須事先解鎖,web3目前沒有api能夠解鎖帳戶,須要本身在控制檯事先解鎖才行.
首先建立合約,須要制定abi.
而後就能夠部署合約了,這時候須要合約的code,
部署合約的結果能夠經過異步函數來獲取,例子已經給出.web

var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.IpcProvider("\\\\.\\pipe\\geth.ipc",net));
var eth=web3.eth;

var tokenContract = new web3.eth.Contract(MyTokenABI, null, {
    from: '0x1a9ec3b0b807464e6d3398a59d6b0a369bf422fa' // 目前web3沒有api來解鎖帳戶,只能本身事先解鎖
});

tokenContract.deploy({
    data: MyTokenBin,
    arguments: [32222, 'token on web3',0,'web3']
}).send({
    from: '0x1a9ec3b0b807464e6d3398a59d6b0a369bf422fa',
    gas: 1500000,
    gasPrice: '30000000000000'
}, function(error, transactionHash){
    console.log("deploy tx hash:"+transactionHash)
})
.on('error', function(error){ console.error(error) })
.on('transactionHash', function(transactionHash){ console.log("hash:",transactionHash)})
.on('receipt', function(receipt){
   console.log(receipt.contractAddress) // contains the new contract address
})
.on('confirmation', function(confirmationNumber, receipt){console.log("receipt,",receipt)})
.then(function(newContractInstance){
    console.log(newContractInstance.options.address) // instance with the new contract address
});

查詢合約

合約部署成功之後,有了地址就能夠根據地址來查詢合約的狀態.
查詢合約狀態並不須要發起事務,也不須要花費gas,所以比較簡單.json

var tokenContract = new web3.eth.Contract(MyTokenABI, '0x6a0dF9E94a41fCd89d8236a8C03f9D678df5Acf9');

tokenContract.methods.name().call(null,function(error,result){
        console.log("contract name "+result);
    })

調用合約函數

合約的函數除了指明返回值是constant的之外,都須要發起事務,這時候就須要指定調用者,由於要花費該帳戶的gas.
這裏調用一下transfer函數.api

tokenContract.methods.transfer("0x8c1b2e9e838e2bf510ec7ff49cc607b718ce8401",387).send({from: '0x1a9ec3b0b807464e6d3398a59d6b0a369bf422fa'})
.on('transactionHash', function(hash){
})
.on('confirmation', function(confirmationNumber, receipt){
})
.on('receipt', function(receipt){
    // receipt example
    console.log(receipt); //查詢這裏能夠獲得結果
})
.on('error', console.error); // If a out of gas error, the second parameter is the receipt.

監聽事件

剛剛調用transfer的時候還會觸發合約的事件Transfer,若是程序關注誰給誰進行了轉帳,那麼就能夠經過監聽該事件.
經過指定fromBlock,toBlock能夠限制事件發生的範圍,除了這個還有一個filter參數能夠進行更詳細的限制,
若有興趣能夠查詢文檔web3文檔app

tokenContract.events.Transfer({
    fromBlock: 0,
    toBlock:'latest'
}, function(error, event){ /*console.log("result:\n"+JSON.stringify(event)); */})
.on('data', function(event){
    console.log(event); // same results as the optional callback above
})
.on('changed', function(event){
    // remove event from local database
})
.on('error', console.error);

須要說明的是,這個監聽不只傳送歷史事件,將來全部事件也會傳送.異步

下面的結果是首先運行程序,會先打印出來剛剛進行的轉帳.
而後我在經過其餘途徑進行轉帳操做,這時候終端會把新的轉帳也打印出來.ide

歷史轉帳:
{ address: '0x6a0dF9E94a41fCd89d8236a8C03f9D678df5Acf9',
  blockNumber: 10680,
  transactionHash: '0x27d5ab9277df504a436b1068697a444d30228584094632f10ab7ba5213a4eccc',
  transactionIndex: 0,
  blockHash: '0xcde734882b0d8cb7a5bf1f7e6d1ccfac5365308de2d7391ce286b45c5546f40b',
  logIndex: 0,
  removed: false,
  id: 'log_2588a961',
  returnValues:
   Result {
     '0': '0x1a9eC3b0b807464e6D3398a59d6b0a369Bf422fA',
     '1': '0x8c1b2E9e838e2Bf510eC7Ff49CC607b718Ce8401',
     '2': '387',
     from: '0x1a9eC3b0b807464e6D3398a59d6b0a369Bf422fA',
     to: '0x8c1b2E9e838e2Bf510eC7Ff49CC607b718Ce8401',
     value: '387' },
  event: 'Transfer',
  signature: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
  raw:
   { data: '0x0000000000000000000000000000000000000000000000000000000000000183',
     topics:
      [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
        '0x0000000000000000000000001a9ec3b0b807464e6d3398a59d6b0a369bf422fa',
        '0x0000000000000000000000008c1b2e9e838e2bf510ec7ff49cc607b718ce8401' ] } }
實時監控到的轉帳
{ address: '0x6a0dF9E94a41fCd89d8236a8C03f9D678df5Acf9',
  blockNumber: 10740,
  transactionHash: '0xb42651720e8b8b64283cbd245aebaa7ad7e3dda58b9887f645ad6957bd7771b8',
  transactionIndex: 0,
  blockHash: '0xcdca97ba5a277e402a93188df03a758c916c37eea0f7498365d227ebd7cb2ee2',
  logIndex: 0,
  removed: false,
  id: 'log_edc5dc68',
  returnValues:
   Result {
     '0': '0x1a9eC3b0b807464e6D3398a59d6b0a369Bf422fA',
     '1': '0x0000000000000000000000000000000000000001',
     '2': '32',
     from: '0x1a9eC3b0b807464e6D3398a59d6b0a369Bf422fA',
     to: '0x0000000000000000000000000000000000000001',
     value: '32' },
  event: 'Transfer',
  signature: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
  raw:
   { data: '0x0000000000000000000000000000000000000000000000000000000000000020',
     topics:
      [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
        '0x0000000000000000000000001a9ec3b0b807464e6d3398a59d6b0a369bf422fa',
        '0x0000000000000000000000000000000000000000000000000000000000000001' ] } }
相關文章
相關標籤/搜索