fix: capture context slot consistently in getSignatureStatuses RPC#406
Merged
MicaiahReid merged 1 commit intosolana-foundation:mainfrom Nov 13, 2025
Merged
Conversation
The getSignatureStatuses RPC endpoint had a race condition that caused
inconsistent API responses when querying transaction statuses. The context
slot was captured after each signature lookup in a loop, rather than once
at the beginning of the method call.
## Problem Discovery
This bug was discovered during high-throughput transaction processing when:
- Sending many transactions at once to the network
- Calling getSignatureStatuses from a background confirmation process
- Observing that some responses returned null with a high context slot
- But post-factum finding the transaction was included in an earlier slot
This created an inconsistency where the API would report "transaction not
found" with context slot X, but the transaction actually existed in slot Y
where Y < X. This violates the semantic contract that if a transaction is
not found at slot X, it should not exist in any slot <= X.
## Root Cause
The bug was in the implementation of get_signature_statuses() at
crates/core/src/rpc/full.rs:1468-1486. The method captured the context
slot inside the signature lookup loop:
```rust
let mut last_latest_absolute_slot = 0;
for signature in signatures.into_iter() {
let res = svm_locker.get_transaction(...).await?;
last_latest_absolute_slot = svm_locker.get_latest_absolute_slot();
responses.push(res.map_some_transaction_status());
}
```
The RwLock on SurfnetSvm is held only during individual operations, not
across the entire RPC call. During the .await points in the async loop,
other tasks can acquire the write lock and advance the slot (e.g., by
confirming blocks or processing new transactions).
This created a race condition where:
1. Lookup transaction at slot 100 → not found (perhaps due to timing)
2. Async await point allows other tasks to run
3. Another task acquires write lock and advances slot to 101
4. get_latest_absolute_slot() returns 101
5. Response reports "not found" with context slot 101
6. But the transaction actually exists in slot 100
## Solution
Capture the context slot once at the beginning of the method, before any
signature lookups. This ensures all responses in a batch share the same
snapshot view of the blockchain state, even if the slot advances during
processing:
```rust
let context_slot = svm_locker.get_latest_absolute_slot();
for signature in signatures.into_iter() {
let res = svm_locker.get_transaction(...).await?;
responses.push(res.map_some_transaction_status());
}
```
This provides snapshot consistency: all lookups are evaluated as of the
same slot, preventing temporal inconsistencies in batch responses.
## Testing
Enhanced test_get_signature_statuses to verify:
- Context slot is captured at the beginning of the call
- Context slot is never 0 when the SVM has advanced
- All signatures in a batch share the same context slot
The test fails with the old implementation (context slot = 0 for empty
queries) and passes with the fix (context slot = 123).
## Impact
This fix ensures getSignatureStatuses provides consistent, predictable
responses during high-throughput transaction processing and parallel
confirmation workflows.
MicaiahReid
approved these changes
Nov 13, 2025
Collaborator
|
Thank you for the thoughtful explanation and for the fix, @serejke! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
getSignatureStatusesRPC endpoint had a race condition that caused inconsistent API responses when querying transaction statuses. The context slot was captured after each signature lookup in a loop, rather than once at the beginning of the method call.Problem Discovery
This bug was discovered during high-throughput transaction processing when:
getSignatureStatusesfrom a background confirmation processThis created an inconsistency where the API would report "transaction not found" with context slot X, but the transaction actually existed in slot Y where Y < X. This violates the semantic contract that if a transaction is not found at slot X, it should not exist in any slot <= X.
Root Cause
The bug was in the implementation of
get_signature_statuses(). The method captured the context slot inside the signature lookup loop:The RwLock on SurfnetSvm is held only during individual operations, not across the entire RPC call. During the .await points in the async loop, other tasks can acquire the write lock and advance the slot (e.g., by confirming blocks or processing new transactions).
This created a race condition where:
Solution
Capture the context slot once at the beginning of the method, before any signature lookups. This ensures all responses in a batch share the same snapshot view of the blockchain state, even if the slot advances during processing:
This provides snapshot consistency: all lookups are evaluated as of the same slot, preventing temporal inconsistencies in batch responses.
Impact
This fix ensures
getSignatureStatusesprovides consistent, predictable responses during high-throughput transaction processing and parallel confirmation workflows.