为啥我的以太坊“.on”事件监听器停止触发?

Posted

技术标签:

【中文标题】为啥我的以太坊“.on”事件监听器停止触发?【英文标题】:Why Does My Ethereum ".on" Event Listener Stop Firing?为什么我的以太坊“.on”事件监听器停止触发? 【发布时间】:2022-01-16 09:54:40 【问题描述】:

我有一个 node.js 服务器,我在其中监听从部署在 Mumbai Polygon 测试网上的 Solidity 智能合约发出的事件。

首先,我使用“web3-providers-ws”节点包创建提供程序,使用 keepalive 和重新连接选项:

let providerNetworkUrl;
let ccggContractAddress;

if (process.env.TESTNET === 'true') 

  console.log('using mumbai URLs')
  // on mumbai
  ccggContractAddress = process.env.CCGG_ADDRESS_MUMBAI_TESTNET;
  providerNetworkUrl = 'wss://polygon-mumbai.g.alchemy.com/v2/';
 else 
  // on polygon mainnet
  ccggContractAddress = process.env.CCGG_ADDRESS_POLYGON_MAINNET;
  providerNetworkUrl = 'wss://polygon-mumbai.g.alchemy.com/v2/';


const connectionUrl = providerNetworkUrl + process.env.alchemyApiKey;
console.log('connectionUrl: ', connectionUrl)

// Enable auto reconnection
const options = 

  clientConfig: 
    // Useful to keep a connection alive
    keepalive: true,
    keepaliveInterval: 20 * 60 * 60 * 1000 // keep alive for 20 min
  ,

  // Enable auto reconnection
  reconnect: 
    auto: true,
    delay: 1000, // ms
    maxAttempts: 10,
    onTimeout: false
  
;

let provider = new ethers.providers.WebSocketProvider(
  new Web3WsProvider(connectionUrl, options))

provider.on('end', (e) => 
  console.log('provider ended: ' + e);
)

provider.on('error', (e) => 
  console.log('provider errored: ' + e);
)

然后我使用 ethers.js 连接到智能合约。

const wallet = new ethers.Wallet(process.env.PRIVATE_WALLET_KEY, provider)
console.log('my address (wallet): ', wallet.address)

const signer = wallet.connect(provider)

const ccggContract = new ethers.Contract(
  ccggContractAddress,
  ccggAbi,
  signer
)

最后我为“GuessSubmitted”事件设置了监听器。

ccggContract.on('GuessSubmitted', async (guess, sender, betSize) => 

  console.log('GuessSubmitted')

)

奇怪的是,当我第一次启动它时,一切都很好。节点服务器听到事件,记录“GuessSubmitted”,并处理事件。

但是,几个小时后,或者一夜之间,我去玩游戏,事件在 Solidity 中调度,但节点服务器什么也没听到!!!什么??

在查看了互联网上的其他一些帖子后,我什至设置了这个 ping 函数来保持 websocket 连接处于活动状态,并且我每 15 分钟调用一次:

async function ping() 

  const now = new Date();

  try 
    console.log('Sending a ping! ' + now.toUTCString());
    const blockNum = await provider.send('eth_blockNumber');
    console.log('Got blocknum: ', blockNum);
  
  catch (err) 
    console.log('PING ERROR')
    console.log(err)
  



// ping every 15 min
setInterval(ping, 1000 * 60 * 15);

console.log('provider created.')

奇怪的是,连接似乎并没有真正断开。我从未在日志中看到任何“供应商错误”或“供应商终止”。

日志看起来像这样,每 15 分钟 ping 一次,但再也听不到任何“GuessSubmitted”事件!! ????

我认为问题可能出在我的 eth 连接提供程序上,但我现在已经尝试使用 Alchemy、Infura 和 GetBlock!这个“停止听到事件”问题发生在所有三个问题上,所以我想知道可能是什么问题,如果它是以太坊平台中的一些潜在错误,或者我在代码中犯了一些错误......

谢谢!

【问题讨论】:

又一次发生在我身上!我认为这是以太坊本身的一个**非常**的关键问题!!!遗憾的是它仍然存在这么多问题并且没有解决方案...... ???? 您说“...ping 每 15 分钟一次正常...”,但在您的示例输出中,您只显示“Sending a ping!...”日志消息。没有“Got blocknum:...”日志消息。所以检查很明显,你实际上得到了对你的 ping 请求的响应,对吗? @kaliatech 是的,它每次都显示“pong”日志。 【参考方案1】:

如果您查看 web3.js 项目问题,有很多关于断开/关闭/重新连接无法按预期工作的报告:

https://github.com/ChainSafe/web3.js/issues/3927 https://github.com/ethers-io/ethers.js/issues/1053 (不同的项目,但相关的和最近的 cmets 是相关的)

没有唯一的解决方案,afaict。正在进行重写以解决一些问题:

https://github.com/ChainSafe/web3.js/issues/4313

【讨论】:

我不认为这个问题与“断开/关闭/重新连接”有关,因为我看到了“pong”日志......这是调度solidity事件的侦听器的问题。

以上是关于为啥我的以太坊“.on”事件监听器停止触发?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的事件监听器没有在 laravel 5 中触发?

父组件监听子组件的生命周期

vue-learning:27 - component - 组件三大API之二:event

详解 Solidity 事件Event - 完全搞懂事件的使用

完全搞懂事件

用Go来做以太坊开发⑤事件日志