3

I know this question have been asked several times and many solutions are being proposed as a workaround but not sure why it is not been working on our case.

In our case we have to listen for contract events like Transfer events on our backend (node js) so that we can update our investor balances and perform other sensitive activities. We can't afford to lose events in our case.

For this, we are using WebSocket provider from infura and web3js library to connect with them. We noticed that if for a few hours we are'nt make any calls then it would close that connection and we would have to restart our app for new connections. To work around this issue we applied popular community workaround i.e listen for events like end or error on the provider and if those events occur we would make a call to instantiate a connection but after applying this patch web3 throws below error instead of connection not open error

'Connection dropped by remote peer.

Here is simplified code of our blockchain module.

const web3  = require('web3');
const ethtx = require('ethereumjs-tx');
const path = require('path');
const fs = require('fs');
const Tx = require('ethereumjs-tx');

const updatebalancedb  = require('../db/Admins/Transactions/updatebalance.js');
const dotenv = require('dotenv');
dotenv.config();



var masterwalletpublickey = process.env.daopublicaddress;
var masterwalletprivatekey = Buffer.from(process.env.daoprivatekey, 'hex');
var wsscocketprovider = process.env.infuranode;
var parentcontractaddress = process.env.maincontractaddress;

var provider = new web3.providers.WebsocketProvider(wsscocketprovider);

var web3js = new web3(provider);

provider.on('error', e => 
{
console.log('WS Error', e);
provider = new web3.providers.WebsocketProvider(wsscocketprovider);
});
provider.on('end', e => {
    console.log('WS closed');
    console.log('Attempting to reconnect...');
    provider = new web3.providers.WebsocketProvider(wsscocketprovider);

    provider.on('connect', function () {
        console.log('WSS Reconnected');
    });

    web3js.setProvider(provider);
});





 const rawcontract  = JSON.parse(fs.readFileSync(path.join(__dirname,'../BlockchainModule/build/contracts/ErContract.json')));
 const contractabi = JSON.stringify(rawcontract.abi);

const contract = new web3js.eth.Contract(rawcontract.abi,parentcontractaddress);


contract.events.Transfer()
.on('data', (event) => {
    console.log('data',event);
    var data = event;
    updatebalancedb.updateinvestorbalance(data);
})
.on('error', console.error);


const gettotaltokens = function(){


    return   contract.methods.totaltokens().call()
        .then(function(result){
            return result;

        })
        .catch(function(error){
           throw error; 
        }) 

}


const circulationtokens = function(){

    return contract.methods.circulationsupply().call()
        .then(function(result){
            return result;
        })
        .catch(function(error){
            throw error;
        })
};

module.exports={gettotaltokens,circulationtokens};

When we call functions like gettotaltokens after few hours of connectivity web3 throws such error .

Can anyone give some pointers or some guide of how to solve this messy issue?

The only solution I have in my mind is to move web3 provider code to a functional level and every time we call the function it will start a fresh new connection. That will solve the problem for time being but not very scalable and also wouldn't solve event listener issues.

Tech Environment:

  1. Node js (v10.13.0)
  2. web3.js (1.2.3)
  3. Chain : (Ropsten)
  4. Socket Provider (Infura)

3 Answers 3

8

I hope someone from Infura would comment the specifics when they terminate a connection.

However, the latest Web3.js has autoreconnect feature:

https://github.com/ethereum/web3.js/releases/tag/v1.2.7

It should alleviate your problems.

0

I am also facing this issue on a project I am working on where it is critical to not have any missed events. What I decided to do was to store the block height of the last event in-memory, and then use an event filter to fetch any events that were emitted after the connection was dropped and before the connection was re-established.

Note that I'm using Python and Web3.py with websocket_client

ws.py:

class ws():
  def __init__(contract_address):
    self.w3 = Web3(Web3.WebsocketProvider(config.WS_RPC_URL))
    self.contract_address = contract_address
    self.block_height = None

  def start(self):
    self.conn = websocket.WebSocketApp(config.WS_RPC_URL, on_open=self.on_open, on_message=self.on_message, on_close=self.on_close, on_error=self.on_error)

        while True:
            self.ws.run_forever()

  def on_open(self, conn):
    self.conn.send(json.dumps(
      {
        "id": 1,
        "method": "eth_subscribe",
      }
    ))

    current_block = self.w3.eth.get_block_number()

    event_filter = self.w3.eth.filter({
      'address': [self.contract_address],
      'topics': [self.event_signature_hash],
      'fromBlock': self.block_height,
      'toBlock': current_block
    })

    missed_events = event_filter.get_all_entries()

  def on_message(self, conn, message):
    self.block_height = ['params']['result']['blockNumber']
0

I think the best solution is to make KeepAlive (ping pong) to avoid drop from WS RPC provider,
https://github.com/ethers-io/ethers.js/issues/1053

The sample is in Etheres js

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.