以太坊系列之十七: 使用web3进行合约部署调用以及监听
2017-09-04 17:55
701 查看
以太坊系列之十七: 使用web3进行智能合约的部署调用以及监听事件(Event)
上一篇介绍了使用golang进行智能合约的部署以及调用,但是使用go语言最大的一个问题是没法持续监听事件的发生.比如我的后台程序需要监控谁给我转账了,如果使用go语言,目前就只能是轮询数据,而使用web3就简单许多,geth会把我关心的事件
主动通知给我.
以太坊系列之十七: 使用web3进行智能合约的部署调用以及监听事件(Event)
token合约
编译token
部署合约
查询合约
调用合约函数
监听事件
token合约
token合约是官方提供的一个样例,这里给出我修改过的版本,方便演示.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,由于太长,太占地方就不放上来了.这些会在部署以及调用的时候用到.
下面来通过web3进行合约的部署,读取数据,发起事务以及监听事件的发生.
部署合约
部署合约需要创建事务,话费gas,因此相关账户必须事先解锁,web3目前没有api可以解锁账户,需要自己在控制台事先解锁才行.首先创建合约,需要制定abi.
然后就可以部署合约了,这时候需要合约的code,
部署合约的结果可以通过异步函数来获取,例子已经给出.
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,因此比较简单.
var tokenContract = new web3.eth.Contract(MyTokenABI, '0x6a0dF9E94a41fCd89d8236a8C03f9D678df5Acf9'); tokenContract.methods.name().call(null,function(error,result){ console.log("contract name "+result); })
调用合约函数
合约的函数除了指明返回值是constant的以外,都需要发起事务,这时候就需要指定调用者,因为要花费该账户的gas.这里调用一下transfer函数.
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文档
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);
需要说明的是,这个监听不仅传送历史事件,未来所有事件也会传送.
下面的结果是首先运行程序,会先打印出来刚刚进行的转账.
然后我在通过其他途径进行转账操作,这时候终端会把新的转账也打印出来.
历史转账: { 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' ] } }
相关文章推荐
- 【区块链】以太坊 web3j for java 使用 - 部署和调用合约 <3>
- C#如何进行以太坊合约调用交易,时间处理,使用过滤器和主题。
- 如何在私有区块链上编写、部署以及与以太坊进行交互的智能合约
- C++ VS 2008中ATL的创建,使用。并在C++项目以及C#项目中进行调用测试
- JavaEE开发之Spring中的事件发送与监听以及使用Profile进行环境切换
- PHP 使用 curl_* 系列函数和 curl_multi_* 系列函数进行多接口调用时的性能对比
- Android开发系列(十四):ListView用法、对ListView监听的三种方法以及ListView中Adapter的使用方法
- 使用Eclipse(以及intellij IDEA)配合JDWP对服务器上部署的代码进行调试
- python应用系列教程——python使用scapy监听网络数据包、按TCP/IP协议进行解析
- Zookeeper系列三:Zookeeper客户端的使用(Zookeeper原生API如何进行调用、ZKClient、Curator)
- 【附代码】如何在私有链上编写、部署与以太坊进行交互的智能合约
- 以太坊系列之十一: 零起步使用remix开发智能合约
- 以太坊笔记 使用 Browser-solidity 在 Go-Ethereum1.7.2 上进行简单的智能合约部署
- 使用web3部署一个比较复杂的智能合约
- Linux 网络渗透 如何使用Aircrack-ng 系列工具进行WPA/WPA2的监听和破解
- ArrayList 与HashSet的比较,及应用反射读取properties配置文件中的数据进行实例化再调用,以及类加载器的使用;还有HashCode的分析,及导致内存泄露,内存溢出的原因之一
- ADRMS部署系列之(五)—配置并使用ADRMS权限模板进行加密
- 使用HttpClient进行http post/get方法的调用,以及使用dom4j解析xml
- 手把手教你搭建智能合约测试环境、开发、编译、部署以及如何通过JS调用合约方法
- ADRMS部署系列之(五)—配置并使用ADRMS权限模板进行加密