Fix TransactionStatusMeta breakage in blockstore (#12587)
* Add helper to facilitate deserializing legacy structs * Use default_on_eof to fix blockstore vis-a-vis TransactionStatusMeta * Add should-panic test and comments
This commit is contained in:
parent
fce3c70b72
commit
865d01c38d
|
@ -0,0 +1,131 @@
|
|||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
/// This helper function enables successful deserialization of versioned structs; new structs may
|
||||
/// include additional fields if they impl Default and are added to the end of the struct. Right
|
||||
/// now, this function is targeted at `bincode` deserialization; the error match may need to be
|
||||
/// updated if another package needs to be used in the future.
|
||||
pub fn default_on_eof<'de, T, D>(d: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de> + Default,
|
||||
{
|
||||
let result = T::deserialize(d);
|
||||
match result {
|
||||
Err(err) if err.to_string() == "io error: unexpected end of file" => Ok(T::default()),
|
||||
result => result,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use bincode::deserialize;
|
||||
|
||||
#[test]
|
||||
fn test_default_on_eof() {
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
struct Foo {
|
||||
bar: u16,
|
||||
#[serde(deserialize_with = "default_on_eof")]
|
||||
baz: Option<u16>,
|
||||
#[serde(deserialize_with = "default_on_eof")]
|
||||
quz: String,
|
||||
}
|
||||
|
||||
let data = vec![1, 0];
|
||||
assert_eq!(
|
||||
Foo {
|
||||
bar: 1,
|
||||
baz: None,
|
||||
quz: "".to_string(),
|
||||
},
|
||||
deserialize(&data).unwrap()
|
||||
);
|
||||
|
||||
let data = vec![1, 0, 0];
|
||||
assert_eq!(
|
||||
Foo {
|
||||
bar: 1,
|
||||
baz: None,
|
||||
quz: "".to_string(),
|
||||
},
|
||||
deserialize(&data).unwrap()
|
||||
);
|
||||
|
||||
let data = vec![1, 0, 1];
|
||||
assert_eq!(
|
||||
Foo {
|
||||
bar: 1,
|
||||
baz: None,
|
||||
quz: "".to_string(),
|
||||
},
|
||||
deserialize(&data).unwrap()
|
||||
);
|
||||
|
||||
let data = vec![1, 0, 1, 0];
|
||||
assert_eq!(
|
||||
Foo {
|
||||
bar: 1,
|
||||
baz: None,
|
||||
quz: "".to_string(),
|
||||
},
|
||||
deserialize(&data).unwrap()
|
||||
);
|
||||
|
||||
let data = vec![1, 0, 1, 0, 0, 1];
|
||||
assert_eq!(
|
||||
Foo {
|
||||
bar: 1,
|
||||
baz: Some(0),
|
||||
quz: "".to_string(),
|
||||
},
|
||||
deserialize(&data).unwrap()
|
||||
);
|
||||
|
||||
let data = vec![1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 116];
|
||||
assert_eq!(
|
||||
Foo {
|
||||
bar: 1,
|
||||
baz: Some(0),
|
||||
quz: "t".to_string(),
|
||||
},
|
||||
deserialize(&data).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_default_on_eof_additional_untagged_fields() {
|
||||
// If later fields are not tagged `deserialize_with = "default_on_eof"`, deserialization
|
||||
// will panic on any missing fields/data
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
struct Foo {
|
||||
bar: u16,
|
||||
#[serde(deserialize_with = "default_on_eof")]
|
||||
baz: Option<u16>,
|
||||
quz: String,
|
||||
}
|
||||
|
||||
// Fully populated struct will deserialize
|
||||
let data = vec![1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 116];
|
||||
assert_eq!(
|
||||
Foo {
|
||||
bar: 1,
|
||||
baz: Some(0),
|
||||
quz: "t".to_string(),
|
||||
},
|
||||
deserialize(&data).unwrap()
|
||||
);
|
||||
|
||||
// Will panic because `quz` is missing, even though `baz` is tagged
|
||||
let data = vec![1, 0, 1, 0];
|
||||
assert_eq!(
|
||||
Foo {
|
||||
bar: 1,
|
||||
baz: None,
|
||||
quz: "".to_string(),
|
||||
},
|
||||
deserialize(&data).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ pub mod builtins;
|
|||
pub mod clock;
|
||||
pub mod commitment_config;
|
||||
pub mod decode_error;
|
||||
pub mod deserialize_utils;
|
||||
pub mod entrypoint_native;
|
||||
pub mod epoch_info;
|
||||
pub mod epoch_schedule;
|
||||
|
|
|
@ -14,6 +14,7 @@ use crate::{
|
|||
use solana_sdk::{
|
||||
clock::{Slot, UnixTimestamp},
|
||||
commitment_config::CommitmentConfig,
|
||||
deserialize_utils::default_on_eof,
|
||||
instruction::CompiledInstruction,
|
||||
message::{Message, MessageHeader},
|
||||
pubkey::Pubkey,
|
||||
|
@ -141,6 +142,7 @@ pub struct TransactionStatusMeta {
|
|||
pub fee: u64,
|
||||
pub pre_balances: Vec<u64>,
|
||||
pub post_balances: Vec<u64>,
|
||||
#[serde(deserialize_with = "default_on_eof")]
|
||||
pub inner_instructions: Option<Vec<InnerInstructions>>,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue