@@ -279,7 +279,16 @@ export interface ResolvedPrevout {
279279 * Inputs beyond the cap are returned without a `prevout` and the frontend
280280 * degrades gracefully (it falls back to the unenriched display).
281281 */
282- const MAX_PREVOUT_LOOKUPS = 60
282+ const MAX_PREVOUT_LOOKUPS = 12
283+ const MAX_PREVOUT_LOOKUPS_PER_ADDRESS_PAGE = 40
284+
285+ interface PrevoutLookupBudget {
286+ remaining : number
287+ }
288+
289+ interface TransactionLookupOptions {
290+ prevoutLookupBudget ?: PrevoutLookupBudget
291+ }
283292
284293// Block-specific caching with different TTLs
285294export class BlockCache extends BlockchainCache {
@@ -318,7 +327,14 @@ export class BlockCache extends BlockchainCache {
318327 * The cache is read/written directly here (rather than via {@link get}) because
319328 * the TTL must be chosen AFTER fetching, based on whether the tx is confirmed.
320329 */
321- async getTransaction ( txid : string , network : NetworkType , verbose : boolean = true ) {
330+ readonly maxPrevoutLookupsPerAddressPage = MAX_PREVOUT_LOOKUPS_PER_ADDRESS_PAGE
331+
332+ async getTransaction (
333+ txid : string ,
334+ network : NetworkType ,
335+ verbose : boolean = true ,
336+ options : TransactionLookupOptions = { } ,
337+ ) {
322338 assertValidNetwork ( network )
323339
324340 // Non-verbose callers just want the raw hex string; it never carries
@@ -384,7 +400,7 @@ export class BlockCache extends BlockchainCache {
384400 }
385401
386402 const withConfirmations = await this . withLiveConfirmations ( tx , network )
387- return await this . enrichInputPrevouts ( withConfirmations , network )
403+ return await this . enrichInputPrevouts ( withConfirmations , network , options . prevoutLookupBudget )
388404 }
389405
390406 /**
@@ -410,6 +426,7 @@ export class BlockCache extends BlockchainCache {
410426 private async enrichInputPrevouts (
411427 tx : Record < string , unknown > | null ,
412428 network : NetworkType ,
429+ budget ?: PrevoutLookupBudget ,
413430 ) : Promise < Record < string , unknown > | null > {
414431 if ( ! tx || ! Array . isArray ( tx . vin ) ) {
415432 return tx
@@ -427,14 +444,19 @@ export class BlockCache extends BlockchainCache {
427444 const parentTxid = input . txid
428445 if ( ! parentTxid || parentTxid === ZERO_HASH || seen . has ( parentTxid ) ) continue
429446 seen . add ( parentTxid )
430- if ( parentTxids . length >= MAX_PREVOUT_LOOKUPS ) break
447+ const aggregateRemaining = budget ?. remaining ?? MAX_PREVOUT_LOOKUPS
448+ if ( parentTxids . length >= MAX_PREVOUT_LOOKUPS || parentTxids . length >= aggregateRemaining ) break
431449 parentTxids . push ( parentTxid )
432450 }
433451
434452 if ( parentTxids . length === 0 ) {
435453 return tx
436454 }
437455
456+ if ( budget ) {
457+ budget . remaining = Math . max ( 0 , budget . remaining - parentTxids . length )
458+ }
459+
438460 // Fetch every needed parent transaction once, in parallel. A failed lookup
439461 // resolves to null and simply yields no prevout for the affected inputs.
440462 const parents = new Map < string , RawVout [ ] | null > ( )
0 commit comments