Skip to content

Duplicate ContractChanges on transaction retry in flushBatchBufferWithRetry #534

@aristidesstaffieri

Description

@aristidesstaffieri

What version are you using?

latest

Problem

File: internal/services/ingest_backfill.go lines 418-486

Buggy code:

for attempt := 0; attempt < maxIngestProcessedDataRetries; attempt++ {
    err := db.RunInTransaction(ctx, m.models.DB, func(dbTx pgx.Tx) error {
        // This in-memory append is NOT rolled back when the transaction fails
        batchChanges.ContractChanges = append(batchChanges.ContractChanges, buffer.GetContractChanges()...)
        // ... DB operations that may fail ...
    })
    // On failure, retries the loop — appending ContractChanges AGAIN
}

Description: The batchChanges.ContractChanges slice append happens inside the transaction closure but is an in-memory operation not rolled back on DB transaction failure. On retry, the same contract changes are appended again, creating duplicates that propagate to ProcessTokenChanges. The map-based merges (mergeTrustlineChanges, mergeAccountChanges, etc.) are idempotent, but the slice append is not.

Suggested fix: Move the batchChanges collection after the successful transaction commit, or reset batchChanges.ContractChanges at the start of each retry.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions