fix: check fetch write race causes invalid unexpected accounts - #738
fix: check fetch write race causes invalid unexpected accounts#738Arrowana wants to merge 1 commit into
Conversation
Greptile SummaryThe PR changes remote account hydration so network requests run without SVM locks and fetched responses are merged under a write lock, preserving local and DB-backed state.
Confidence Score: 4/5The PR is not yet safe to merge because a fetch completed after an account becomes offline can still expose the blocked remote state. The hydration guard prevents the fetched account from being inserted after it becomes offline, but the final fallback returns the same remote account when the local re-read remains empty, and both single- and multi-account lookup paths can expose that value. Files Needing Attention: crates/core/src/surfnet/svm.rs, crates/core/src/surfnet/locker.rs Important Files Changed
Sequence DiagramsequenceDiagram
participant Caller
participant Locker
participant Remote
participant SVM
Caller->>Locker: Read account
Locker->>SVM: Check local state
SVM-->>Locker: Missing
Locker->>Remote: Fetch without lock
Remote-->>Locker: Remote account
Locker->>SVM: Acquire write lock and hydrate
SVM->>SVM: Recheck local and DB-backed state
alt Local state exists
SVM-->>Locker: Return local state
else Account remains eligible for hydration
SVM->>SVM: Insert remote state
SVM-->>Locker: Return hydrated state
end
Locker-->>Caller: Contextualized result
Reviews (2): Last reviewed commit: "fix: check fetch write race" | Re-trigger Greptile |
| match self.inner.get_account_result(&requested_pubkey) { | ||
| Ok(local_result) if !local_result.is_none() => local_result, | ||
| _ => remote_read_result, | ||
| } |
There was a problem hiding this comment.
Blocked hydration returns remote state
When an account is marked offline while its remote fetch is in flight, hydrate_account_if_missing rejects insertion but this fallback still returns remote_read_result, causing the caller to observe remote state that the offline policy requires suppressing.
Knowledge Base Used: Surfnet Engine (SVM, Locker, Remote Fetch)
00afcbf to
55e9825
Compare
|
Drive by offering to say: good find! The progression here is exactly the right shape for this kind of race. It also feels like a good concurrency pattern to reuse elsewhere. Following the "where there's one, there's three" rule, I don't think this is isolated. That's follow-up work rather than this PR's scope, though. Nice fix! |
|
This is a great find, @Arrowana! I had a hard time in reviewing this - there are so many calls to I wanted to take a crack at cleaning that up a bit, so I've opened #763. It takes a policy-driven approach to inserts - there's a more centralized place to handle writes, and you have to decide ahead of time if this write is Authoritative, or if hydration should occur. |
check–fetch–write race: Surfpool checked local state, released the lock for the mainnet request, then later wrote that stale response unconditionally. A transaction could update the account during that gap.
The fix:
Background: I was testing my own system and observed very bizarre behaviour, despite a tx mutating a given account i would observe the older state afterwards, which is a revert to mainnet state.