Security (EVM-02): oracle-service reads exchangeRateStored at 'latest' block; no reorg protection #8
Labels
No labels
enhancement
governance
QA
testing
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/ust1-window#8
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
@PlasticDigits finding from security review on #5.
Severity
Low-to-Medium. BSC reorgs are infrequent but do occur.
Description
oracle-service/src/bsc.rsread_exchange_rate_storedcallsc.exchangeRateStored().call().awaitwithout specifying a block tag. Alloy defaults tolatest, which is the most recent block — vulnerable to reorg.Why this matters
If BSC reorgs out the block the rate was read from, and a different rate existed on the winning chain at that height, the service may have already broadcast the pre-reorg rate to Terra. Because INV-ORACLE-MONO-001 enforces strictly non-decreasing rates on Terra, a broadcast higher-than-reality rate can never be rolled back on-chain — the Terra state would be permanently ahead of true BSC state.
BSC finality (via fast-finality proposals) has become more robust but 6-12 block reorgs have been observed historically.
Recommendation
Either:
.block(BlockNumberOrTag::Finalized)(simplest, requires newer BSC RPCs supporting finalized tag)latest - Nwhere N = configurable confirmation depth (e.g. 15 blocks = ~45s on BSC)latest, separated by N seconds, and require match before broadcastingOption 2 is the most defensive and portable.
Related
mentioned in issue #5
mentioned in commit
0f5a3e43baFix merged (main @
387e438)What changed
oracle-service/src/bsc.rs: Before callingexchangeRateStored, the service now callseth_blockNumber, then performseth_callat blocklatest - BSC_CONFIRMATION_BLOCKS(default 15 blocks), matching the review recommendation for portable reorg protection on BSC (~45s at 3s/block).BSC_CONFIRMATION_BLOCKSis read from the environment (optional); default 15 if unset.Config/main.rs: wire the confirmation depth through the existing RPC fallback path.Merge
fix/issue-8-bsc-reorg-protection, merged intomainalongside the existing EVM-03 canonicalVENUS_VTOKEN_ADDRESSvalidation (conflict resolved by keeping validation + addingbsc_confirmation_blocks).Ops note
RUST_LOG=debug(orust1_oracle_service=debug) to seelatest_block,at_block, andconfirmation_blockson each BSC read.@PlasticDigits verified fix on
0f5a3e4.bsc.rsreadsget_block_numberthen queries atat_block = latest.saturating_sub(confirmation_blocks)viaBlockId::Number(BlockNumberOrTag::Number(at_block))BSC_CONFIRMATION_BLOCKS=15(~45s on BSC) — matches the recommendation exactlysaturating_subsafe against early-chain underflowReorg window closed.