以太坊系列之十七: 使用web3进行合约部署调用以及监听

简介: 以太坊系列之十七: 使用web3进行智能合约的部署调用以及监听事件(Event)上一篇介绍了使用golang进行智能合约的部署以及调用,但是使用go语言最大的一个问题是没法持续监听事件的发生.比如我的后台程序需要监控谁给我转账了,如果使用go语言,目前就只能是轮询数据,而使用web3就简单许多,geth会把我关心的事件主动通知给我.

以太坊系列之十七: 使用web3进行智能合约的部署调用以及监听事件(Event)

上一篇介绍了使用golang进行智能合约的部署以及调用,但是使用go语言最大的一个问题是没法持续监听事件的发生.
比如我的后台程序需要监控谁给我转账了,如果使用go语言,目前就只能是轮询数据,而使用web3就简单许多,geth会把我关心的事件
主动通知给我.

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' ] } }
目录
相关文章
|
2月前
|
中间件 Java 应用服务中间件
Windows部署web应用服务器Jboss中间件
如何在Windows系统上部署JBoss 7.1作为Web应用服务器,包括配置环境变量、自动部署WAR包、访问JBoss控制台、设置管理员账户以及修改端口和绑定地址等操作。
99 1
|
2月前
|
负载均衡 应用服务中间件 持续交付
微服务架构下的Web服务器部署
【8月更文第28天】随着互联网应用的不断发展,传统的单体应用架构逐渐显露出其局限性,特别是在可扩展性和维护性方面。为了解决这些问题,微服务架构应运而生。微服务架构通过将应用程序分解成一系列小型、独立的服务来提高系统的灵活性和可维护性。本文将探讨如何在微服务架构中有效部署和管理Web服务器实例,并提供一些实际的代码示例。
91 0
|
1月前
|
前端开发 JavaScript
构建你的第一个Web应用:从零到部署
【8月更文挑战第33天】 在这篇文章中,我们将一起踏上构建一个基本Web应用的旅程。不同于传统的“安装这个、运行那个”教程,我们的目标是通过理解每一步的意义和目的来深化你的技术理解。我们将探索HTML、CSS、JavaScript的基础,并学习如何将它们结合起来创建一个简单的个人网站。接着,我们会介绍如何使用GitHub Pages进行免费部署,让你的应用上线。准备好了吗?让我们开始吧!
|
1月前
|
负载均衡 网络协议 应用服务中间件
web群集--rocky9.2源码部署nginx1.24的详细过程
Nginx 是一款由 Igor Sysoev 开发的开源高性能 HTTP 服务器和反向代理服务器,自 2004 年发布以来,以其高效、稳定和灵活的特点迅速成为许多网站和应用的首选。本文详细介绍了 Nginx 的核心概念、工作原理及常见使用场景,涵盖高并发处理、反向代理、负载均衡、低内存占用等特点,并提供了安装配置教程,适合开发者参考学习。
|
2月前
|
JavaScript 搜索推荐 前端开发
从零搭建到部署:Angular与Angular Universal手把手教你实现服务器端渲染(SSR),全面解析及实战指南助你提升Web应用性能与SEO优化效果
【8月更文挑战第31天】服务器端渲染(SSR)是现代Web开发的关键技术,能显著提升SEO效果及首屏加载速度,改善用户体验。Angular Universal作为官方SSR解决方案,允许在服务器端生成静态HTML文件。本文通过具体示例详细介绍如何使用Angular Universal实现SSR,并分享最佳实践。首先需安装Node.js和npm。
45 1
|
2月前
|
网络协议 Serverless API
现代化 Web 应用构建问题之验证各个服务是否已成功部署如何解决
现代化 Web 应用构建问题之验证各个服务是否已成功部署如何解决
23 1
|
2月前
|
Java UED 自然语言处理
Struts 2 国际化竟有如此神奇魔力?快来揭开多语言支持的 Web 应用神秘面纱
【8月更文挑战第31天】在全球化背景下,Web应用需适应多种语言环境。Struts 2凭借其强大的国际化(i18n)支持,简化了多语言应用开发。通过不同语言的资源文件,它能自动匹配用户语言偏好,优化用户体验并扩展用户群。下面是一个示例:创建`messages.properties`(英语)与`messages_zh_CN.properties`(中文),并在Struts 2的Action类及JSP页面中调用`getText()`方法及Struts标签展示相应语言内容。此外,在struts.xml中指定资源文件,以确保框架正确加载对应语言包。通过这些步骤,开发者可以轻松实现应用的多语言支持。
60 0
|
2月前
|
Java 数据库 API
JSF与JPA的史诗级联盟:如何编织数据持久化的华丽织锦,重塑Web应用的荣耀
【8月更文挑战第31天】JavaServer Faces (JSF) 和 Java Persistence API (JPA) 分别是构建Java Web应用的用户界面组件框架和持久化标准。结合使用JSF与JPA,能够打造强大的数据驱动Web应用。首先,通过定义实体类(如`User`)和配置`persistence.xml`来设置JPA环境。然后,在JSF中利用Managed Bean(如`UserBean`)管理业务逻辑,通过`EntityManager`执行数据持久化操作。
46 0
|
2月前
|
Java 开发者 关系型数据库
JSF与AWS的神秘之旅:如何在云端部署JSF应用,让你的Web应用如虎添翼?
【8月更文挑战第31天】在云计算蓬勃发展的今天,AWS已成为企业级应用的首选平台。本文探讨了在AWS上部署JSF(JavaServer Faces)应用的方法,这是一种广泛使用的Java Web框架。通过了解并利用AWS的基础设施与服务,如EC2、RDS 和 S3,开发者能够高效地部署和管理JSF应用。文章还提供了具体的部署步骤示例,并讨论了使用AWS可能遇到的挑战及应对策略,帮助开发者更好地利用AWS的强大功能,提升Web应用开发效率。
60 0
|
2月前
|
监控 应用服务中间件 网络安全
FastAPI部署大揭秘!如何从代码到云端,让你的Web应用华丽变身生产环境之星?
【8月更文挑战第31天】FastAPI是一款基于Python 3.6+异步特性的高性能Web框架,深受开发者喜爱。本文详细介绍了将FastAPI应用部署到生产环境的过程,包括准备应用、使用Uvicorn测试、配置Gunicorn和Nginx、设置反向代理及监控日志等关键步骤。通过这些步骤,确保应用安全高效地运行在生产环境中,实现高性能与高可扩展性。
252 0