Skip to content

Commit

Permalink
feat(blockapis): add fetchPrevTxBuffers
Browse files Browse the repository at this point in the history
This is a helper function that fetches the previous transaction buffers.

We are reusing Buffer references
  • Loading branch information
OttoAllmendinger committed Oct 25, 2023
1 parent f65ff46 commit da8021a
Showing 1 changed file with 47 additions and 24 deletions.
71 changes: 47 additions & 24 deletions modules/blockapis/src/UtxoApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,60 @@ export interface UtxoApi extends TransactionApi {
getUnspentsForAddresses(address: string[]): Promise<utxolib.bitgo.Unspent[]>;
}

function toOutPoints(arr: utxolib.TxInput[] | utxolib.bitgo.TxOutPoint[]): utxolib.bitgo.TxOutPoint[] {
return arr.map((i) => {
if ('txid' in i) {
return i;
}
return utxolib.bitgo.getOutputIdForInput(i);
});
}

/**
* Helper to efficiently fetch output data.
* Typical we can query output data for all outputs of a transaction, so we first fetch all
* the output list via `f` and then pick the output data from the result.
* Helper to efficiently fetch output data. Deduplicates transaction ids and only does one lookup per txid.
* @param outpoints
* @param f - maps txid to a list of outputs with type TOut
* @return list of TOut corresponding to outputs
* @param f - lookup function for txid
* @return list of T corresponding to outpoints
*/
async function mapInputs<TOut>(
outpoints: utxolib.bitgo.TxOutPoint[],
f: (txid: string) => Promise<TOut[]>
): Promise<TOut[]> {
async function mapInputs<T>(outpoints: utxolib.bitgo.TxOutPoint[], f: (txid: string) => Promise<T>): Promise<T[]> {
const txids = [...new Set(outpoints.map((i) => i.txid))];
const txMap = new Map(await mapSeries(txids, async (txid) => [txid, await f(txid)]));
return outpoints.map((i) => {
const arr = txMap.get(i.txid);
if (arr) {
if (i.vout in arr) {
return arr[i.vout];
}
throw new Error(`could not find output ${i.vout}`);
const v = txMap.get(i.txid);
if (!v) {
throw new Error(`could not find tx ${i.txid}`);
}
throw new Error(`could not find tx ${i.txid}`);
return v;
});
}

/**
* @param outpoints
* @param f - maps txid to a list of TOut.
* @return list of TOut corresponding to outpoints
*/
async function mapInputsVOut<TOut>(
outpoints: utxolib.bitgo.TxOutPoint[],
f: (txid: string) => Promise<TOut[]>
): Promise<TOut[]> {
const allOutputs = await mapInputs(outpoints, f);
return outpoints.map((p, i) => {
const arr = allOutputs[i];
if (p.vout in arr) {
return allOutputs[i][p.vout];
}
throw new Error(`could not find output ${p.vout}`);
});
}

export async function fetchPrevTxBuffers(
ins: utxolib.TxInput[] | utxolib.bitgo.TxOutPoint[],
api: UtxoApi,
_network: utxolib.Network
): Promise<Buffer[]> {
return mapInputs(toOutPoints(ins), async (txid) => Buffer.from(await api.getTransactionHex(txid), 'hex'));
}

/**
* Fetch transaction inputs from transaction input list
* @param ins
Expand All @@ -79,13 +107,8 @@ export async function fetchInputs(
api: UtxoApi,
network: utxolib.Network
): Promise<utxolib.TxOutput[]> {
return mapInputs(
ins.map((i: utxolib.TxInput | utxolib.bitgo.TxOutPoint) => {
if ('txid' in i) {
return i;
}
return utxolib.bitgo.getOutputIdForInput(i);
}),
return mapInputsVOut(
toOutPoints(ins),
async (txid) => utxolib.bitgo.createTransactionFromHex(await api.getTransactionHex(txid), network).outs
);
}
Expand All @@ -97,5 +120,5 @@ export async function fetchTransactionSpends(
outpoints: utxolib.bitgo.TxOutPoint[],
api: UtxoApi
): Promise<OutputSpend[]> {
return mapInputs(outpoints, async (txid) => await api.getTransactionSpends(txid));
return mapInputsVOut(outpoints, async (txid) => await api.getTransactionSpends(txid));
}

0 comments on commit da8021a

Please sign in to comment.