I have this function that loops through the transactions of each new block, and then saves transactions that match an address stored in my database.
A block is just an array of objects.
However, if a transaction has events in different blocks, await ticker.save();
will for some reason run before the !matchingHash
conditional finishes, and then go to the next block without finishing the conditional.
The function works completely fine if all the events of a transaction are in the same block, but not if they are in different blocks.
Here is what I'm logging right now to try and troubleshoot this:
11923243
Transaction found, currentBlock: 0x365b5c75d581a74ffb6681f29156e3aca87dd4221419e91434ss4bdd03f67393ee3 11923243
getTransaction, event block, currentBlock 11923243 11923243
getBlock, event block, currentBlock 11923243 11923243
ticker saved
11923244
Transaction found, currentBlock: 0x365b5c75d581a74ffb6681f29156e3aca87dd4221419e91434ss4bdd03f67393ee3 11923244
getTransaction, event block, currentBlock 11923243 11923244
new Transaction, event block, currentBlock 11923243 11923244
New transaction added
getBlock, event block, currentBlock 11923243 11923244
new Transaction, event block, currentBlock 11923243 11923244
error: MongoError: E11000 duplicate key error collection: Cluster0.transactions index: transactionHash_1 dup key: { transactionHash: "0x365b5c75d581a74ffb6681f29156e3aca87dd4221419e91434ss4bdd03f67393ee3" }
Function:
async function getTransactions() {
try {
terminate = false;
const web3 = new Web3(
new Web3.providers.HttpProvider(
'http://example.com/rpc'
)
);
let lastBlock;
const getLastBlock = await web3.eth.getBlockNumber();
console.log('getLastBlock:', getLastBlock);
const syncing = await web3.eth.isSyncing();
console.log('Syncing status:', syncing);
// Check if the node is still syncing
if (syncing) {
lastBlock = syncing.highestBlock;
} else {
lastBlock = getLastBlock;
}
console.log(await web3.eth.getBlockNumber());
// Avoid indexing reorgs by not including the last two days
lastBlock = lastBlock - 11520;
let currentBlock;
if (
ticker.contractTransactions.lastFetchedBlock === null ||
ticker.contractTransactions.lastFetchedBlock === 0
) {
currentBlock = ticker.tickerContracts.map((item) => {
return item.block;
});
currentBlock = Math.min(...currentBlock);
} else {
currentBlock = ticker.contractTransactions.lastFetchedBlock;
}
while (currentBlock < lastBlock) {
console.log(`{currentBlock}`);
for (let i = 0; i < ticker.tickerContracts.length; i++) {
const contract = new web3.eth.Contract(
[],
ticker.tickerContracts[i].address
);
await contract.getPastEvents(
'allEvents',
{ fromBlock: currentBlock, toBlock: currentBlock },
async function (error, events) {
if (events && events.length > 0) {
function Raw(address, data, eventSignature, topics) {
this.address = address;
this.data = data;
this.eventSignature = eventSignature;
this.topics = topics;
}
);
}
ticker.contractTransactions.lastFetchedBlock = currentBlock;
await ticker.save();
console.log('ticker saved');
if (terminate === true) {
return 'All function execution has been terminated';
}
currentBlock++;
}
} catch (err) {
console.log('Error', err);
startupFetch();
console.log('Calling function to restart fetching...');
}
if (terminate === true) {
return 'All function execution has been terminated';
}
startupFetch();
console.log('Calling function to restart fetching...');
}
You are mixing callback API and promise API, this never ends well.
If you pass a function as callback, it's not supposed to be async
and won't be await
ed.
But getPastEvents
already returns a promise, so no reason to use any callback at all!
Instead of this...
await contract.getPastEvents(
'allEvents',
{ fromBlock: currentBlock, toBlock: currentBlock },
async function (error, events) {
/* Handle events here */
}
})
Do this:
const events = await contract.getPastEvents(
'allEvents',
{ fromBlock: currentBlock, toBlock: currentBlock }
})
/* Handle events here */