Listening to New Transactions Happening on the Blockchain

A common use case of JavaScript programming with Ethereum is to listen to new blocks mined on the blockchain and looking at the content of the blocks for getting specific informations. This task is often used for example if you’d like to store all the blockhain data in a database or if you’d like to react to specific transactions or events made by some accounts.

In the previous tutorial, we saw how to setup web3JS in your project, so if you don’t have it ready yet check it first.

The first step for our program will be to listen to new blocks mined on the blockchain. For this we’ll use a JavaScript timeout function that will be called every 5 seconds for example. Keep in mind that we’ll need to store the latest block we processed as node may receive several blocks at the same time or several blocks might be mined between two calls to the getBlockNumber function.

var Web3 = require('web3');
const web3 = new Web3('https://cloudflare-eth.com');

let latestKnownBlockNumber = -1;
let blockTime = 5000;

// Our function that will triggered for every block
async function processBlock(blockNumber) {
    console.log("We process block: " + blockNumber)
    latestKnownBlockNumber = blockNumber;
}

// This function is called every blockTime, check the current block number and order the processing of the new block(s)
async function checkCurrentBlock() {
    const currentBlockNumber = await web3.eth.getBlockNumber()
    console.log("Current blockchain top: " + currentBlockNumber, " | Script is at: " + latestKnownBlockNumber)
    while (latestKnownBlockNumber == -1 || currentBlockNumber > latestKnownBlockNumber) {
        await processBlock(latestKnownBlockNumber == -1 ? currentBlockNumber : latestKnownBlockNumber + 1);
    }
    setTimeout(checkCurrentBlock, blockTime);
}

checkCurrentBlock()

The result of running the script should look similar to this:

As we can see, as the Blocks appear at irregular intervals it’s sometime making several call without having a new block to process but sometimes a few blocks appears at the same time.

Now we we’ll use the getBlock function to retrieve information about the new block.

let block = await web3.eth.getBlock(blockNumber);
console.log("new block :", block)

As you can see, the block contains a lot of informations:

We’ll now iterate over every transactions of the block and request to the node all the information it has for the transactions. For this we’ll call two different functions:

  • getTransaction: Returns all the information of the transaction that were known before the execution (from, to, value, data input…)
  • getTransactionReceipt: Returns all the information of the transaction that were generated during it’s execution (logs, output..)
for (const transactionHash of block.transactions) {
    let transaction = await web3.eth.getTransaction(transactionHash);
    let transactionReceipt = await web3.eth.getTransactionReceipt(transactionHash);
    transaction = Object.assign(transaction, transactionReceipt);
    console.log("Transaction: ", transaction);
}

Which looks like this for a single transaction:

The Transaction object will contain the following informations:

  • hash 32 Bytes – String: Hash of the transaction.
    nonce – Number: The number of transactions made by the sender prior to this one.
  • blockHash 32 Bytes – String: Hash of the block where this transaction was in. null when its pending.
  • blockNumber – Number: Block number where this transaction was in. null when its pending.
  • transactionIndex – Number: Integer of the transactions index position in the block. null when its pending.
  • from – String: Address of the sender.
  • to – String: Address of the receiver. null when its a contract creation transaction.
  • value – String: Value transferred in wei.
  • gasPrice – String: Gas price provided by the sender in wei.
  • gas – Number: Gas provided by the sender.
  • input – String: The data sent along with the transaction.
    Example
  • status – Boolean: TRUE if the transaction was successful, FALSE, if the EVM reverted the transaction.
  • contractAddress – String: The contract address created, if the transaction was a contract creation, otherwise null.
  • cumulativeGasUsed – Number: The total amount of gas used when this transaction was executed in the block.
  • gasUsed– Number: The amount of gas used by this specific transaction alone.
  • logs – Array: Array of log objects, which this transaction generated.

From this code, you should be able to write any script that reacts to a specific transaction, event… Your imagination is the limit, here is the full code of the project:

var Web3 = require('web3');
const web3 = new Web3('https://cloudflare-eth.com');

let latestKnownBlockNumber = -1;
let blockTime = 5000;

// Our function that will triggered for every block
async function processBlock(blockNumber) {
    console.log("We process block: " + blockNumber);
    let block = await web3.eth.getBlock(blockNumber);
    console.log("new block :", block)
    for (const transactionHash of block.transactions) {
        let transaction = await web3.eth.getTransaction(transactionHash);
        let transactionReceipt = await web3.eth.getTransactionReceipt(transactionHash);
        transaction = Object.assign(transaction, transactionReceipt);
        console.log("Transaction: ", transaction);
        // Do whatever you want here
    }
    latestKnownBlockNumber = blockNumber;
}

// This function is called every blockTime, check the current block number and order the processing of the new block(s)
async function checkCurrentBlock() {
    const currentBlockNumber = await web3.eth.getBlockNumber()
    console.log("Current blockchain top: " + currentBlockNumber, " | Script is at: " + latestKnownBlockNumber);
    while (latestKnownBlockNumber == -1 || currentBlockNumber > latestKnownBlockNumber) {
        await processBlock(latestKnownBlockNumber == -1 ? currentBlockNumber : latestKnownBlockNumber + 1);
    }
    setTimeout(checkCurrentBlock, blockTime);
}

checkCurrentBlock()

This tutorial does not handle errors and reorganization of the blockchain, it’s just a starting point for you to understand how to read incoming blocks, transactions and events happening on the blockchain. If you’re looking for battle tested code we recommend you taking a look at the blockchain-etl (Python) or the dappboard-etl (Javascript).

In the next tutorial we’ll see how to compile and deploy smart contracts using Javascript.

Leave a Reply

Your email address will not be published. Required fields are marked *