From 17f919238bebb28cc745d17f66bed2a34420aaf7 Mon Sep 17 00:00:00 2001 From: Robert Wei Date: Sun, 21 Apr 2024 17:54:32 -0400 Subject: [PATCH] expand spent outputs to utxos --- src/indexer/types.ts | 7 ++----- src/indexer/updater.ts | 19 ++++++++++++++----- test/updater.test.ts | 30 ++++++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/indexer/types.ts b/src/indexer/types.ts index 01c12ab..42a745e 100644 --- a/src/indexer/types.ts +++ b/src/indexer/types.ts @@ -104,10 +104,7 @@ export namespace RuneLocation { } } -export type RuneOutput = { - txid: string; - vout: number; -}; +export type SpentRuneUtxoBalance = RuneUtxoBalance & { mempoolTxid: string }; export type RuneUtxoBalance = { txid: string; @@ -156,6 +153,6 @@ export type RuneBlockIndex = { etchings: RuneEtching[]; mintCounts: RuneMintCount[]; utxoBalances: RuneUtxoBalance[]; - spentOutputs: RuneOutput[]; + spentOutputs: SpentRuneUtxoBalance[]; burnedBalances: RuneBalance[]; }; diff --git a/src/indexer/updater.ts b/src/indexer/updater.ts index 78ff3d7..f07ff4c 100644 --- a/src/indexer/updater.ts +++ b/src/indexer/updater.ts @@ -12,18 +12,18 @@ import { BitcoinRpcClient } from '../rpcclient'; import { Rune } from '../rune'; import { Runestone } from '../runestone'; import { script } from '../script'; +import { SpacedRune } from '../spacedrune'; import { BlockInfo, - RuneBlockIndex, RuneBalance, + RuneBlockIndex, RuneEtching, RuneLocation, RuneMintCount, - RuneOutput, RuneUtxoBalance, RunestoneStorage, + SpentRuneUtxoBalance, } from './types'; -import { SpacedRune } from '../spacedrune'; function isScriptPubKeyHexOpReturn(scriptPubKeyHex: string) { return scriptPubKeyHex && Buffer.from(scriptPubKeyHex, 'hex')[0] === OP_RETURN; @@ -39,7 +39,7 @@ export class RuneUpdater implements RuneBlockIndex { block: BlockInfo; etchings: RuneEtching[] = []; utxoBalances: RuneUtxoBalance[] = []; - spentOutputs: RuneOutput[] = []; + spentOutputs: SpentRuneUtxoBalance[] = []; private _minimum: Rune; private _mintCountsByRuneLocation: Map = new Map(); @@ -446,13 +446,22 @@ export class RuneUpdater implements RuneBlockIndex { const utxoBalance = utxoBalancesByOutputLocation.get(`${input.txid}:${input.vout}`) ?? (await this._storage.getUtxoBalance(input.txid, input.vout)); - this.spentOutputs.push({ txid: input.txid, vout: input.vout }); for (const additionalBalance of utxoBalance) { const runeId = additionalBalance.runeId; const runeLocation = RuneLocation.toString(runeId); const balance = unallocated.get(runeLocation) ?? { runeId, amount: 0n }; unallocated.set(runeLocation, balance); balance.amount = u128.checkedAddThrow(u128(balance.amount), u128(additionalBalance.amount)); + this.spentOutputs.push({ + txid: input.txid, + vout: input.vout, + address: additionalBalance.address, + scriptPubKey: additionalBalance.scriptPubKey, + runeId: additionalBalance.runeId, + runeTicker: additionalBalance.runeTicker, + amount: additionalBalance.amount, + mempoolTxid: tx.txid, + }); } } diff --git a/test/updater.test.ts b/test/updater.test.ts index 6dc9718..0aa7c7c 100644 --- a/test/updater.test.ts +++ b/test/updater.test.ts @@ -882,6 +882,7 @@ describe('edict', () => { await runeUpdater.indexRunes(tx2, 89); expect(runeUpdater.etchings.length).toBe(0); expect(runeUpdater.utxoBalances.length).toBe(2); + expect(runeUpdater.spentOutputs.length).toBe(2); expect(runeUpdater.utxoBalances[0]).toMatchObject({ txid: 'txid', vout: 1, @@ -902,10 +903,31 @@ describe('edict', () => { }, amount: 400n, }); - expect(runeUpdater.spentOutputs).toEqual([ - { txid: 'parenttxid', vout: 0 }, - { txid: 'txid', vout: 1 }, - ]); + expect(runeUpdater.spentOutputs[0]).toMatchObject({ + txid: 'parenttxid', + vout: 0, + address: '3P4WqXDbSLRhzo2H6MT6YFbvBKBDPLbVtQ', + scriptPubKey: Buffer.from('a914ea6b832a05c6ca578baa3836f3f25553d41068a587', 'hex'), + runeId: { + block: 888, + tx: 8, + }, + runeTicker: 'TESTRUNE', + amount: 400n, + mempoolTxid: 'txid', + }); + expect(runeUpdater.spentOutputs[1]).toMatchObject({ + txid: 'txid', + vout: 1, + address: '3P4WqXDbSLRhzo2H6MT6YFbvBKBDPLbVtQ', + runeId: { + block: 888, + tx: 8, + }, + runeTicker: 'TESTRUNE', + amount: 400n, + mempoolTxid: 'childtxid', + }); }); test('edict with invalid output is cenotaph', async () => {