There is a way to make these calls more efficient and it's through doing some memoisation.
There's no way around having to make the getRawTransaction call on each unique transaction at least once - but that doesn't mean we need to do it again!
Here is how I've done it for the blockscrape project I'm working on:
const api = require('./api/api.js')
let transactions = {}
const storeTransaction = (tx, vout) => { transactions[tx] = vout }
const transactionExists = (tx) => transactions[tx] ? true : false
const retrieveTransacton = (tx) => transactions[tx]
// loop through the outputs of a tx, greedily returning the value of an output tx where n matches vOutIdx
const getMatchingTransactionValue = async (txHash, voutIndex) => {
let tx = undefined
let voutArray = undefined
if (transactionExists(txHash)) {
voutArray = retrieveTransacton(txHash)
} else {
tx = await api.getRawTransaction(txHash)
voutArray = JSON.parse(tx).vout
storeTransaction(txHash, voutArray)
}
for (let i = 0; i < voutArray.length; i++) {
if (voutArray[i].n === voutIndex) {
return voutArray[i].value
}
}
}
The api file is just a wrapper for spawning a child process and executing api specific arguments (i.e. litecoin-cli getrawtransaction txhash 1
) - which are themselves wrapped into a promise (hence using the await
keyword).
The key to taking advantage of the memoisation is that you'll need to traverse whatever blocks you need backwards -- otherwise you'll be storing transactions in memory and never find a match.
This is because all transactions on the blockchain reference both inputs and outputs and we need to work with the outputs (later transactions) in order to calculate the fee - which means if we work backwards, we will likely store many transactions which are referenced by past blocks (but we won't ever find transactions which are referenced in the vout array of future blocks, since our program has no knowledge of them yet as they are in the "future").
Of course, this is one of the advantages of working with historical data - when we know, in reality, those transactions do exist, we just need to adapt our program to reflect this fact :)