最近在一个新项目上工作时,我无意中发现了一个问题:我必须将所有的交易或多或少地实时发送到一个给定的帐户。在查看了Web3.js API文档和堆栈溢出之后,没有明确的方法可以执行此操作,因此我尝试自己创建一些程序。,这就是该程序产生的原因。
两 个 脚 本
经过多次尝试和错误之后,我得出两个脚本,它们都适合不同的状态,第一个非常慢,但更具扩展性,而另一个非常轻量级,但不太可定制。让我们一起探索它们。
检查某个地址的事务可能看起来很简单,但实际上比我最初想象的要困难得多。有人希望我们可以通过监听某种网络事件来监视以太坊地址,以获取传入事务,但这种功能目前还不存在。
在开始之前,您需要满足以下几项要求:
· 正在运行的以太坊节点,如Geth或Infura
· Node.js和NPM
· 用npm init初始化的新目录
我们只需要一个依赖项-web3.js(请查看文档)。与以太坊网络交互的JavaScript API。 所以一定要安装npm。
首先创建一个为我们初始化web3客户端的模块:
请注意,本文中的每个代码段都是一个单独的js文件,我们将其与index.js结合在一起
该模块接收Web3包并返回一个初始化的客户端。 我在rinkeby测试网上使用了一个Infura Ethereum节点,并且如果您决定也这样做(我建议这样做),请确保使用正确的密钥替换YOUR_INFURA_API_KEY。
接下来,我们将创建实际的交易检查器:
我们的第二个模块使用该web3客户端来查询实际网络。我们有一个私有account变量,您应将其替换为您感兴趣的地址,然后返回checkLastBlock函数。首先我们检索最新的区块,并将数字记录到控制台。这样的代码块看起来就是这样(我排除了一些对我们没有用的字段):
您可以看到诸如number、nonce和hash之类的字段,但我们现在真正感兴趣的是transactions字段。这是一个数组,包含该块中包含的所有事务哈希。
在transactionChecker.js的第9行,我们检查block和block.transactions数组是否不为空,在第10行,我们遍历该数组。对于数组中的每个交易哈希,我们请求实际交易。事务如下所示:
如果我们现在发现to字段(事务接收端的地址)等于我们的地址(不要忘记toLowerCase()函数),那么我们已经找到了要查找的内容,并且可以将一些数据记录到控制台。(如果事务不包含“收件人”字段,则为合约创建)
底部的间隔功能每7秒检查一次当前区块。我选择此数字是因为以太坊的平均出块时间为15秒,我们不想错过任何区块。该程序的问题在于它不依赖统计异常值。例如如果一个区块在7秒内被挖掘,则可能会完全丢失该区块。而且如果我们尝试通过减少轮询间隔来缓解这种情况,则会发现我们需要一个非常快速的Internet连接来处理所有异步网络I/O。
有利的一面是,我们可以扩展此脚本,例如检查一系列区块之间的所有到该帐户的交易,如下所示:
也不要忘记返回这个函数。
如果您对我的模块编写方式完全感到困惑:我导出所谓的工厂函数,这是JavaScript的绝佳设计模式。
第二个程序利用以太坊的pub/sub。pub/sub是一个系统,发布者通过该系统不断向网络广播与特定主题相关的事件,客户端(订阅者)可以订阅这些事件。这比像我们在第一个程序中那样不停地对网络进行投票要好得多,也快得多。但是您必须考虑以下几个方面:
– 通知是实时发送的,用于当前事件,而不是过去事件。可以调整前一个程序以搜索一系列块之间的事务,但这对该程序不起作用。
– 订阅需要全双工连接。幸运的是,Infura和Geth都以websocket的形式提供了这种连接。
由于我们是实时监控帐户,因此这些要点不会打扰我们,让我们继续。我现在在一个新的npm目录中工作,如果您正在编码,请记住这一点。
首先我们必须创建我们的客户。对于此程序,我们需要一个普通的http提供程序以及一个websocket提供程序。在我们的代码中,我们将两者都返回到一个对象中-web3http将是http客户端,web3是websocket客户端:
现在对于第二个版本的事务检查器:
让我们把这个分解。有几个主题可以订阅,如newBlockHeaders或logs。日志是理想的,但是这个订阅主题还不起作用。所以我们将使用pendingTransactions订阅。这发生在第5行。我们的订阅是事件发射器,当有人发送新交易(因此尚未确认)的那一刻,它就向我们发送该交易的交易哈希。这发生在函数watchTransactions中,我们在第11行公开了该函数。
由于这些事务还没有被确认,我们将使用setTimeout函数来阻止每一个事件的进一步代码执行,直到一分钟后,希望到那时,该事务将被挖掘出来。因为在那之后,我们实际上只做了与第一个程序相同的事情:检索事务,并检查我们的地址是否是接收端的地址。
最后是我们的索引文件:
该程序更加优雅,并且不会占用大量资源。但是请注意,这两个程序都存在一些可靠性问题。我们讨论的第一个区块:如果区块时间比平均区块时间低很多,则可能会错过该区块。对于第二笔,如果有人支付了很少的费用,那么肯定不会在一分钟后被挖掘。在我的项目中,我将setTimeout增加到5分钟,因为出于我的考虑,这仍然在范围之内。但是如果要实际使用此功能,请小心。理想情况下,我们将订阅日志,但这仍然是真正的错误,因此是一个非常糟糕的主意。