Skip to content

Taint propagation assumes input-order == chronological order #8

Description

@cognis-digital

Context

propagate_taint() processes transactions in the order they appear in the input list, with the documented assumption that this is "roughly chronological, as in an exported graph." When a tx spends an output that appears later in the list than the spend, the taint carried by that input has not been accumulated yet, so downstream taint is under-counted.

Why it matters

Exports are not guaranteed to be topologically sorted. A graph delivered newest-first, or interleaved across addresses, can produce a lower dirty_value / taint fraction than the true value — a silent accuracy bug rather than a crash.

Repro sketch

from cryptotrace.core import propagate_taint, Transaction
SDN = "0x722122df12d4e14e13ac3b6895a86e84145b6967"
# t1 (B->C) listed BEFORE t0 (SDN->B): C should be tainted, but B has no taint yet
txs = [
    Transaction("t1", ["B"], ["C"], "ETH", 10.0),
    Transaction("t0", [SDN], ["B"], "ETH", 10.0),
]
print(propagate_taint(txs, {SDN}))  # C's taint is understated vs a sorted graph

Possible fix (non-breaking)

Topologically sort by timestamp (falling back to a dependency sort on the input→output graph) before propagating, when timestamps are present. Keep the current single-pass behaviour as a fallback when ordering is unavailable, and document the guarantee.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions