Search code examples
expressblockchainweb3js

Web3js: How to show pending transactions on custom blockchain


I have been working on custom local blockchain testnet and want to show pending transactions on custom block explorer. So whenever GET request from frontend arrives, the api-server(Express) should response with pending transactions. I first tried with web3.eth's getPendingTransactions method but it always returned with an empty array.

Next, I tried with web3.eth.subscribe's 'pendingTransactions' option like the docs.

Below is the code what I tried.

transactionController.js

const Web3 = require("web3");
const web3 = new Web3("ws://192.168.112.82:7001");
var pndTxns = [];

exports.pendingTransactions = (req, res) => {
web3.eth
      .subscribe("pendingTransactions", function (error, result) {
        if (!error) console.log(result);
        console.log(pndTxns);
      })
      .on("data", function (transaction) {
        pndTxns.push(transaction);
}

res.status(200).json({
  success: true,
  txns: pndTxns,
});

(Here, transactionController.js a controller for pending transactions router.) But pndTxns in response always returns with empty arrary even though pndTxns in web3.eth.subscribe exist.

I think this is because web3.eth.subscribe actually build a web socket connection with the RPC node so that pndTxns can not go out of this method.

Finally, I tried with etherjs module like this blog and following is the code.

var ethers = require("ethers");
var url = "ws://192.168.112.82:7001";

var init = function () {
  var customWsProvider = new ethers.providers.WebSocketProvider(url);
  
  customWsProvider.on("pending", (tx) => {
    customWsProvider.getTransaction(tx).then(function (transaction) {
      console.log(transaction);
    });
  });

  customWsProvider._websocket.on("error", async () => {
    console.log(`Unable to connect to ${ep.subdomain} retrying in 3s...`);
    setTimeout(init, 3000);
  });
  customWsProvider._websocket.on("close", async (code) => {
    console.log(
      `Connection lost with code ${code}! Attempting reconnect in 3s...`
    );
    customWsProvider._websocket.terminate();
    setTimeout(init, 3000);
  });
};

init();

res.status(200).json({
  success: true,
  txns: pndTxns,
});

Also I could see pending transactions inside init() function but could not send those transactions with a reponse.

Here is sample output of transaction inside init function.

[
  {
    hash: '0x4c34186e0e6fee5c83406660cf8ef830c36548bb3b8cc14a0fb1eb29fe438331',
    type: 0,
    accessList: null,
    blockHash: '0x000000c9000004c2e8c3585c051b49972b1de6a64c40ce7310a2a994b00483e4',
    blockNumber: 40964,
    transactionIndex: 0,
    confirmations: 1,
    from: '0x8734CB972d36a740Cc983d5515e160C373A4a016',
    gasPrice: BigNumber { _hex: '0x3b9aca00', _isBigNumber: true },
    gasLimit: BigNumber { _hex: '0x5208', _isBigNumber: true },
    to: '0x9651819cfa16c8F3Ba927d5350Ca25417591166B',
    value: BigNumber { _hex: '0x01236efcbcbb340000', _isBigNumber: true },
    nonce: 224,
    data: '0x',
    r: '0xed3d1d5b94a413ce45a06de77851865281cc41c8cdbbcbc4b96356b4d9e49e5c',
    s: '0x2d05d609590c1d5ff7e3ff69111cc6d3caf6f517c2e0229a10de8e938ccee1ba',
    v: 535,
    creates: null,
    chainId: 250,
    wait: [Function (anonymous)]
  }
]

I don't care whatever way you use but can you tell me how can I response pending transactions?


Solution

  • The web3.eth's getPendingTransactions method returns an empty array because it's returning only transactions originating from an account on your node. Here's the source code (assuming you are on Geth).

    You can use eth.subscribe to get all the pending transactions:

    const Web3 = require('web3');
    const url = 'wss://ENDPOINT';
    const web3 = new Web3(url);
    
    var options = {
        address: null,
        topics: [
            null
        ]
    };
    
    var subscription = web3.eth.subscribe('logs', options, function(error, result){
        if (!error) console.log('got result');
        else console.log(error);
    }).on("data", function(log){
        console.log('got data', log);
    }).on("changed", function(log){
        console.log('changed');
    });
    

    This might be useful too.