Skip to content

AirgapTransactionError type from blockstore#6434

Merged
steveluscher merged 2 commits intoanza-xyz:masterfrom
steveluscher:airgap-transaction-error-from-blockstore
Jun 16, 2025
Merged

AirgapTransactionError type from blockstore#6434
steveluscher merged 2 commits intoanza-xyz:masterfrom
steveluscher:airgap-transaction-error-from-blockstore

Conversation

@steveluscher
Copy link
Copy Markdown

Problem

At present, we leak the serialization format of TransactionError straight into blockstore. Any change to the serialization format of TransactionError (this being an example) could change the bytes that are stored in blockstore. A change in that serialization could cause old validator clients to fail to load transaction errors stored by newer clients, and vice versa.

Summary of Changes

In this PR, we create an ‘airgap’ – StoredTransaction between TransactionError and the type that is serialized for storage in blockstore.

This provides a locus for custom serialization logic. Now you can conceive of a change to the structure of TransactionError that can be handled by the custom serialization logic to produce bytes that are backward compatible with old validator clients, and you can create deserialization logic that handles bytes stored by older validator clients.

We also add tests to verify that the current serialization format for named, struct, tuple, and particularly InstructionError variants of TransactionError don't change without a test breaking.

This is a prerequisite for #6083

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Jun 5, 2025

Codecov Report

Attention: Patch coverage is 82.00000% with 9 lines in your changes missing coverage. Please review.

Project coverage is 82.8%. Comparing base (bfebc57) to head (308ede0).
Report is 21 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##           master    #6434     +/-   ##
=========================================
- Coverage    82.8%    82.8%   -0.1%     
=========================================
  Files         847      847             
  Lines      379486   379535     +49     
=========================================
+ Hits       314509   314547     +38     
- Misses      64977    64988     +11     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@steveluscher steveluscher force-pushed the airgap-transaction-error-from-blockstore branch from 3a6803d to fb5c61e Compare June 6, 2025 18:26
joncinque
joncinque previously approved these changes Jun 6, 2025
Copy link
Copy Markdown

@joncinque joncinque left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me! Confirming that the current generated::TransactionError is just a Vec<u8> currently, so the new type allows us to easily customize serde without any impact on sdk users.

Please get approval from at least one of the other reviewers before merging.

Comment thread storage-proto/src/convert.rs Outdated

impl From<TransactionError> for generated::TransactionError {
fn from(value: TransactionError) -> Self {
let stored_error = Into::<StoredTransactionError>::into(value).0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this might just be me, but I prefer using from instead of all the Intos

Suggested change
let stored_error = Into::<StoredTransactionError>::into(value).0;
let stored_error = StoredTransactionError::from(value).0;

Comment thread storage-proto/src/lib.rs Outdated
impl From<StoredTransactionError> for TransactionError {
fn from(value: StoredTransactionError) -> Self {
let bytes = value.0;
bincode::deserialize::<Self>(&bytes).expect("transaction error to deserialize from bytes")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is the Self needed here? I think the compiler should be able to figure it out

Suggested change
bincode::deserialize::<Self>(&bytes).expect("transaction error to deserialize from bytes")
bincode::deserialize(&bytes).expect("transaction error to deserialize from bytes")

@steveluscher
Copy link
Copy Markdown
Author

How does this look, @steviez?

@steviez
Copy link
Copy Markdown

steviez commented Jun 11, 2025

How does this look, @steviez?

I'll try to take a look in the next day or two; sorry for the delay and appreciate your patience

Copy link
Copy Markdown

@steviez steviez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a prerequisite for #6083

I see that #6083 has been closed and you have created #6546 as an index of your thoughts.

Given that you appear to be abandoning the overall goal for the time being, do you think there is still value in landing this PR right now ?

@steveluscher
Copy link
Copy Markdown
Author

I do, @steviez. It will make @jstarry's life easier (and subsequent PRs easier to review) if we land this work now.

@steveluscher steveluscher merged commit d849be8 into anza-xyz:master Jun 16, 2025
39 checks passed
@steveluscher steveluscher deleted the airgap-transaction-error-from-blockstore branch June 16, 2025 20:11
Copy link
Copy Markdown

@steviez steviez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally got around to looking at this. The general idea of the change makes sense.

I'm having to brush off some cobwebs to remember how all this stuff is hooked up so please bear with me on these questions 😅

Is this line below problematic ? Namely, we're invoking serialize() directly, but should we be using one of the From implementations ?

let err = match status {
Ok(()) => None,
Err(err) => Some(generated::TransactionError {
err: bincode::serialize(&err).expect("transaction error to serialize to bytes"),
}),
};

And is StoredTransactionError wired up to anything yet ? Should it be connected to this type ?

#[derive(Serialize, Deserialize)]
pub struct StoredTransactionStatusMeta {

@steveluscher
Copy link
Copy Markdown
Author

Namely, we're invoking serialize() directly, but should we be using one of the From implementations ?

Yeesh. It does look as though I missed that. All this code used to be in one PR. PR splitting gone wrong. I'll finish this up next week.

@steveluscher
Copy link
Copy Markdown
Author

#6704.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants