From 1f9cf7b9d61d569b52770391272a7e11ea30f22b Mon Sep 17 00:00:00 2001 From: Sameh Abouel-saad Date: Tue, 2 Jun 2026 02:39:05 +0300 Subject: [PATCH] perf(bridge): fetch transaction operations once in processTransaction When a Stellar transaction credited the bridge account more than once, processTransaction called getOperationEffect(tx.Hash) once per matching account_credited effect, refetching identical operation data from Horizon each time and slowing down processing. Fetch the operations lazily at most once per transaction and reuse the result across all matching effects. The fetch still happens only when a matching TFT credit is present (no extra call for unrelated transactions), and per-effect MintEvent emission is unchanged, so behaviour is preserved. Closes #1051 Co-Authored-By: Claude Opus 4.8 (1M context) --- bridge/tfchain_bridge/pkg/stellar/stellar.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/bridge/tfchain_bridge/pkg/stellar/stellar.go b/bridge/tfchain_bridge/pkg/stellar/stellar.go index 724ddd6df..62b2c460f 100644 --- a/bridge/tfchain_bridge/pkg/stellar/stellar.go +++ b/bridge/tfchain_bridge/pkg/stellar/stellar.go @@ -502,6 +502,13 @@ func (w *StellarWallet) processTransaction(tx hProtocol.Transaction) ([]MintEven asset := w.getAssetCodeAndIssuer() var mintEvents []MintEvent + // A transaction's operations are identical no matter how many times the bridge + // account is credited within it, so fetch them at most once and reuse the result + // across all matching account_credited effects. Previously this Horizon call was + // made once per matching effect, refetching the same data when a single + // transaction credited the bridge more than once (#1051). + var ops operations.OperationsPage + opsFetched := false for _, effect := range effects.Embedded.Records { if effect.GetAccount() != w.config.StellarBridgeAccount { continue @@ -520,9 +527,12 @@ func (w *StellarWallet) processTransaction(tx hProtocol.Transaction) ([]MintEven continue } - ops, err := w.getOperationEffect(tx.Hash) - if err != nil { - continue + if !opsFetched { + ops, err = w.getOperationEffect(tx.Hash) + if err != nil { + continue + } + opsFetched = true } senders := make(map[string]*big.Int)