Convert blockstore TransactionStatus column family to protobufs (#15733)

* Prevent panic if TransactionStatus can't be deserialized

* Convert Blockstore TransactionStatus column to protobuf

* Add compatability test
This commit is contained in:
Tyera Eulberg 2021-03-05 09:05:35 -07:00 committed by GitHub
parent bd13262b42
commit 7e65289729
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 383 additions and 131 deletions

1
Cargo.lock generated
View File

@ -4710,6 +4710,7 @@ dependencies = [
"serde", "serde",
"serde_bytes", "serde_bytes",
"sha2 0.9.2", "sha2 0.9.2",
"solana-account-decoder",
"solana-bpf-loader-program", "solana-bpf-loader-program",
"solana-budget-program", "solana-budget-program",
"solana-frozen-abi 1.6.0", "solana-frozen-abi 1.6.0",

View File

@ -124,7 +124,7 @@ impl TransactionStatusService {
transaction.signatures[0], transaction.signatures[0],
writable_keys, writable_keys,
readonly_keys, readonly_keys,
&TransactionStatusMeta { TransactionStatusMeta {
status, status,
fee, fee,
pre_balances, pre_balances,

View File

@ -64,6 +64,7 @@ features = ["lz4"]
[dev-dependencies] [dev-dependencies]
assert_matches = "1.3.0" assert_matches = "1.3.0"
matches = "0.1.6" matches = "0.1.6"
solana-account-decoder = { path = "../account-decoder", version = "1.6.0" }
solana-budget-program = { path = "../programs/budget", version = "1.6.0" } solana-budget-program = { path = "../programs/budget", version = "1.6.0" }
[build-dependencies] [build-dependencies]

View File

@ -35,7 +35,7 @@ use solana_sdk::{
timing::timestamp, timing::timestamp,
transaction::Transaction, transaction::Transaction,
}; };
use solana_storage_proto::StoredExtendedRewards; use solana_storage_proto::{StoredExtendedRewards, StoredTransactionStatusMeta};
use solana_transaction_status::{ use solana_transaction_status::{
ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Rewards, ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Rewards,
TransactionStatusMeta, TransactionWithStatusMeta, TransactionStatusMeta, TransactionWithStatusMeta,
@ -44,6 +44,7 @@ use std::{
cell::RefCell, cell::RefCell,
cmp, cmp,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
convert::TryInto,
fs, fs,
io::{Error as IoError, ErrorKind}, io::{Error as IoError, ErrorKind},
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -1783,7 +1784,8 @@ impl Blockstore {
transaction, transaction,
meta: self meta: self
.read_transaction_status((signature, slot)) .read_transaction_status((signature, slot))
.expect("Expect database get to succeed"), .ok()
.flatten(),
} }
}) })
.collect() .collect()
@ -1799,10 +1801,9 @@ impl Blockstore {
self.transaction_status_index_cf self.transaction_status_index_cf
.put(1, &TransactionStatusIndexMeta::default())?; .put(1, &TransactionStatusIndexMeta::default())?;
// This dummy status improves compaction performance // This dummy status improves compaction performance
self.transaction_status_cf.put( let default_status = TransactionStatusMeta::default().into();
cf::TransactionStatus::as_index(2), self.transaction_status_cf
&TransactionStatusMeta::default(), .put_protobuf(cf::TransactionStatus::as_index(2), &default_status)?;
)?;
self.address_signatures_cf.put( self.address_signatures_cf.put(
cf::AddressSignatures::as_index(2), cf::AddressSignatures::as_index(2),
&AddressSignatureMeta::default(), &AddressSignatureMeta::default(),
@ -1878,11 +1879,16 @@ impl Blockstore {
index: (Signature, Slot), index: (Signature, Slot),
) -> Result<Option<TransactionStatusMeta>> { ) -> Result<Option<TransactionStatusMeta>> {
let (signature, slot) = index; let (signature, slot) = index;
let result = self.transaction_status_cf.get((0, signature, slot))?; let result = self
.transaction_status_cf
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((0, signature, slot))?;
if result.is_none() { if result.is_none() {
Ok(self.transaction_status_cf.get((1, signature, slot))?) Ok(self
.transaction_status_cf
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((1, signature, slot))?
.and_then(|meta| meta.try_into().ok()))
} else { } else {
Ok(result) Ok(result.and_then(|meta| meta.try_into().ok()))
} }
} }
@ -1892,15 +1898,16 @@ impl Blockstore {
signature: Signature, signature: Signature,
writable_keys: Vec<&Pubkey>, writable_keys: Vec<&Pubkey>,
readonly_keys: Vec<&Pubkey>, readonly_keys: Vec<&Pubkey>,
status: &TransactionStatusMeta, status: TransactionStatusMeta,
) -> Result<()> { ) -> Result<()> {
let status = status.into();
// This write lock prevents interleaving issues with the transaction_status_index_cf by gating // This write lock prevents interleaving issues with the transaction_status_index_cf by gating
// writes to that column // writes to that column
let mut w_active_transaction_status_index = let mut w_active_transaction_status_index =
self.active_transaction_status_index.write().unwrap(); self.active_transaction_status_index.write().unwrap();
let primary_index = self.get_primary_index(slot, &mut w_active_transaction_status_index)?; let primary_index = self.get_primary_index(slot, &mut w_active_transaction_status_index)?;
self.transaction_status_cf self.transaction_status_cf
.put((primary_index, signature, slot), status)?; .put_protobuf((primary_index, signature, slot), &status)?;
for address in writable_keys { for address in writable_keys {
self.address_signatures_cf.put( self.address_signatures_cf.put(
(primary_index, *address, slot, signature), (primary_index, *address, slot, signature),
@ -1928,14 +1935,18 @@ impl Blockstore {
(transaction_status_cf_primary_index, signature, 0), (transaction_status_cf_primary_index, signature, 0),
IteratorDirection::Forward, IteratorDirection::Forward,
))?; ))?;
for ((i, sig, slot), data) in index_iterator { for ((i, sig, slot), _data) in index_iterator {
counter += 1; counter += 1;
if i != transaction_status_cf_primary_index || sig != signature { if i != transaction_status_cf_primary_index || sig != signature {
break; break;
} }
if self.is_root(slot) { if self.is_root(slot) {
let status: TransactionStatusMeta = deserialize(&data)?; let status = self
return Ok((Some((slot, status)), counter)); .transaction_status_cf
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((i, sig, slot))?
.and_then(|status| status.try_into().ok())
.map(|status| (slot, status));
return Ok((status, counter));
} }
} }
} }
@ -3531,6 +3542,7 @@ pub mod tests {
use bincode::serialize; use bincode::serialize;
use itertools::Itertools; use itertools::Itertools;
use rand::{seq::SliceRandom, thread_rng}; use rand::{seq::SliceRandom, thread_rng};
use solana_account_decoder::parse_token::UiTokenAmount;
use solana_runtime::bank::{Bank, RewardType}; use solana_runtime::bank::{Bank, RewardType};
use solana_sdk::{ use solana_sdk::{
hash::{self, hash, Hash}, hash::{self, hash, Hash},
@ -3541,7 +3553,7 @@ pub mod tests {
transaction::TransactionError, transaction::TransactionError,
}; };
use solana_storage_proto::convert::generated; use solana_storage_proto::convert::generated;
use solana_transaction_status::{InnerInstructions, Reward, Rewards}; use solana_transaction_status::{InnerInstructions, Reward, Rewards, TransactionTokenBalance};
use std::time::Duration; use std::time::Duration;
// used for tests only // used for tests only
@ -5706,37 +5718,35 @@ pub mod tests {
post_balances.push(i as u64 * 11); post_balances.push(i as u64 * 11);
} }
let signature = transaction.signatures[0]; let signature = transaction.signatures[0];
let status = TransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: pre_balances.clone(),
post_balances: post_balances.clone(),
inner_instructions: Some(vec![]),
log_messages: Some(vec![]),
pre_token_balances: Some(vec![]),
post_token_balances: Some(vec![]),
}
.into();
ledger ledger
.transaction_status_cf .transaction_status_cf
.put( .put_protobuf((0, signature, slot), &status)
(0, signature, slot),
&TransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: pre_balances.clone(),
post_balances: post_balances.clone(),
inner_instructions: Some(vec![]),
log_messages: Some(vec![]),
pre_token_balances: Some(vec![]),
post_token_balances: Some(vec![]),
},
)
.unwrap(); .unwrap();
let status = TransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: pre_balances.clone(),
post_balances: post_balances.clone(),
inner_instructions: Some(vec![]),
log_messages: Some(vec![]),
pre_token_balances: Some(vec![]),
post_token_balances: Some(vec![]),
}
.into();
ledger ledger
.transaction_status_cf .transaction_status_cf
.put( .put_protobuf((0, signature, slot + 1), &status)
(0, signature, slot + 1),
&TransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: pre_balances.clone(),
post_balances: post_balances.clone(),
inner_instructions: Some(vec![]),
log_messages: Some(vec![]),
pre_token_balances: Some(vec![]),
post_token_balances: Some(vec![]),
},
)
.unwrap(); .unwrap();
TransactionWithStatusMeta { TransactionWithStatusMeta {
transaction, transaction,
@ -5826,27 +5836,30 @@ pub mod tests {
// result not found // result not found
assert!(transaction_status_cf assert!(transaction_status_cf
.get((0, Signature::default(), 0)) .get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
0,
Signature::default(),
0
))
.unwrap() .unwrap()
.is_none()); .is_none());
// insert value // insert value
let status = TransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Err(
TransactionError::AccountNotFound,
),
fee: 5u64,
pre_balances: pre_balances_vec.clone(),
post_balances: post_balances_vec.clone(),
inner_instructions: Some(inner_instructions_vec.clone()),
log_messages: Some(log_messages_vec.clone()),
pre_token_balances: Some(pre_token_balances_vec.clone()),
post_token_balances: Some(post_token_balances_vec.clone()),
}
.into();
assert!(transaction_status_cf assert!(transaction_status_cf
.put( .put_protobuf((0, Signature::default(), 0), &status,)
(0, Signature::default(), 0),
&TransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Err(
TransactionError::AccountNotFound
),
fee: 5u64,
pre_balances: pre_balances_vec.clone(),
post_balances: post_balances_vec.clone(),
inner_instructions: Some(inner_instructions_vec.clone()),
log_messages: Some(log_messages_vec.clone()),
pre_token_balances: Some(pre_token_balances_vec.clone()),
post_token_balances: Some(post_token_balances_vec.clone())
},
)
.is_ok()); .is_ok());
// result found // result found
@ -5860,8 +5873,14 @@ pub mod tests {
pre_token_balances, pre_token_balances,
post_token_balances, post_token_balances,
} = transaction_status_cf } = transaction_status_cf
.get((0, Signature::default(), 0)) .get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
0,
Signature::default(),
0,
))
.unwrap() .unwrap()
.unwrap()
.try_into()
.unwrap(); .unwrap();
assert_eq!(status, Err(TransactionError::AccountNotFound)); assert_eq!(status, Err(TransactionError::AccountNotFound));
assert_eq!(fee, 5u64); assert_eq!(fee, 5u64);
@ -5873,20 +5892,19 @@ pub mod tests {
assert_eq!(post_token_balances.unwrap(), post_token_balances_vec); assert_eq!(post_token_balances.unwrap(), post_token_balances_vec);
// insert value // insert value
let status = TransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Ok(()),
fee: 9u64,
pre_balances: pre_balances_vec.clone(),
post_balances: post_balances_vec.clone(),
inner_instructions: Some(inner_instructions_vec.clone()),
log_messages: Some(log_messages_vec.clone()),
pre_token_balances: Some(pre_token_balances_vec.clone()),
post_token_balances: Some(post_token_balances_vec.clone()),
}
.into();
assert!(transaction_status_cf assert!(transaction_status_cf
.put( .put_protobuf((0, Signature::new(&[2u8; 64]), 9), &status,)
(0, Signature::new(&[2u8; 64]), 9),
&TransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Ok(()),
fee: 9u64,
pre_balances: pre_balances_vec.clone(),
post_balances: post_balances_vec.clone(),
inner_instructions: Some(inner_instructions_vec.clone()),
log_messages: Some(log_messages_vec.clone()),
pre_token_balances: Some(pre_token_balances_vec.clone()),
post_token_balances: Some(post_token_balances_vec.clone())
},
)
.is_ok()); .is_ok());
// result found // result found
@ -5900,8 +5918,14 @@ pub mod tests {
pre_token_balances, pre_token_balances,
post_token_balances, post_token_balances,
} = transaction_status_cf } = transaction_status_cf
.get((0, Signature::new(&[2u8; 64]), 9)) .get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
0,
Signature::new(&[2u8; 64]),
9,
))
.unwrap() .unwrap()
.unwrap()
.try_into()
.unwrap(); .unwrap();
// deserialize // deserialize
@ -5938,7 +5962,7 @@ pub mod tests {
Signature::new(&random_bytes), Signature::new(&random_bytes),
vec![&Pubkey::new(&random_bytes[0..32])], vec![&Pubkey::new(&random_bytes[0..32])],
vec![&Pubkey::new(&random_bytes[32..])], vec![&Pubkey::new(&random_bytes[32..])],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -6004,7 +6028,7 @@ pub mod tests {
Signature::new(&random_bytes), Signature::new(&random_bytes),
vec![&Pubkey::new(&random_bytes[0..32])], vec![&Pubkey::new(&random_bytes[0..32])],
vec![&Pubkey::new(&random_bytes[32..])], vec![&Pubkey::new(&random_bytes[32..])],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -6143,7 +6167,8 @@ pub mod tests {
log_messages: Some(vec![]), log_messages: Some(vec![]),
pre_token_balances: Some(vec![]), pre_token_balances: Some(vec![]),
post_token_balances: Some(vec![]), post_token_balances: Some(vec![]),
}; }
.into();
let signature1 = Signature::new(&[1u8; 64]); let signature1 = Signature::new(&[1u8; 64]);
let signature2 = Signature::new(&[2u8; 64]); let signature2 = Signature::new(&[2u8; 64]);
@ -6157,46 +6182,46 @@ pub mod tests {
// signature4 in 2 non-roots, // signature4 in 2 non-roots,
// extra entries // extra entries
transaction_status_cf transaction_status_cf
.put((0, signature2, 1), &status) .put_protobuf((0, signature2, 1), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put((0, signature2, 2), &status) .put_protobuf((0, signature2, 2), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put((0, signature4, 0), &status) .put_protobuf((0, signature4, 0), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put((0, signature4, 1), &status) .put_protobuf((0, signature4, 1), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put((0, signature5, 0), &status) .put_protobuf((0, signature5, 0), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put((0, signature5, 1), &status) .put_protobuf((0, signature5, 1), &status)
.unwrap(); .unwrap();
// Initialize index 1, including: // Initialize index 1, including:
// signature4 in non-root and root, // signature4 in non-root and root,
// extra entries // extra entries
transaction_status_cf transaction_status_cf
.put((1, signature4, 1), &status) .put_protobuf((1, signature4, 1), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put((1, signature4, 2), &status) .put_protobuf((1, signature4, 2), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put((1, signature5, 0), &status) .put_protobuf((1, signature5, 0), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put((1, signature5, 1), &status) .put_protobuf((1, signature5, 1), &status)
.unwrap(); .unwrap();
blockstore.set_roots(&[2]).unwrap(); blockstore.set_roots(&[2]).unwrap();
@ -6280,21 +6305,20 @@ pub mod tests {
let pre_token_balances = Some(vec![]); let pre_token_balances = Some(vec![]);
let post_token_balances = Some(vec![]); let post_token_balances = Some(vec![]);
let signature = transaction.signatures[0]; let signature = transaction.signatures[0];
let status = TransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: pre_balances.clone(),
post_balances: post_balances.clone(),
inner_instructions: inner_instructions.clone(),
log_messages: log_messages.clone(),
pre_token_balances: pre_token_balances.clone(),
post_token_balances: post_token_balances.clone(),
}
.into();
blockstore blockstore
.transaction_status_cf .transaction_status_cf
.put( .put_protobuf((0, signature, slot), &status)
(0, signature, slot),
&TransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: pre_balances.clone(),
post_balances: post_balances.clone(),
inner_instructions: inner_instructions.clone(),
log_messages: log_messages.clone(),
pre_token_balances: pre_token_balances.clone(),
post_token_balances: post_token_balances.clone(),
},
)
.unwrap(); .unwrap();
TransactionWithStatusMeta { TransactionWithStatusMeta {
transaction, transaction,
@ -6366,7 +6390,7 @@ pub mod tests {
signature, signature,
vec![&address0], vec![&address0],
vec![&address1], vec![&address1],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -6381,7 +6405,7 @@ pub mod tests {
signature, signature,
vec![&address0], vec![&address0],
vec![&address1], vec![&address1],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -6474,7 +6498,7 @@ pub mod tests {
signature, signature,
vec![&address0], vec![&address0],
vec![&address1], vec![&address1],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -6534,7 +6558,7 @@ pub mod tests {
transaction.signatures[0], transaction.signatures[0],
transaction.message.account_keys.iter().collect(), transaction.message.account_keys.iter().collect(),
vec![], vec![],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -6740,22 +6764,21 @@ pub mod tests {
vec![solana_sdk::pubkey::new_rand()], vec![solana_sdk::pubkey::new_rand()],
vec![CompiledInstruction::new(1, &(), vec![0])], vec![CompiledInstruction::new(1, &(), vec![0])],
); );
let status = TransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Err(
TransactionError::AccountNotFound,
),
fee: x,
pre_balances: vec![],
post_balances: vec![],
inner_instructions: Some(vec![]),
log_messages: Some(vec![]),
pre_token_balances: Some(vec![]),
post_token_balances: Some(vec![]),
}
.into();
transaction_status_cf transaction_status_cf
.put( .put_protobuf((0, transaction.signatures[0], slot), &status)
(0, transaction.signatures[0], slot),
&TransactionStatusMeta {
status: solana_sdk::transaction::Result::<()>::Err(
TransactionError::AccountNotFound,
),
fee: x,
pre_balances: vec![],
post_balances: vec![],
inner_instructions: Some(vec![]),
log_messages: Some(vec![]),
pre_token_balances: Some(vec![]),
post_token_balances: Some(vec![]),
},
)
.unwrap(); .unwrap();
transactions.push(transaction); transactions.push(transaction);
} }
@ -7264,6 +7287,73 @@ pub mod tests {
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction"); Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
} }
#[test]
fn test_transaction_status_protobuf_backward_compatability() {
let blockstore_path = get_tmp_ledger_path!();
{
let blockstore = Blockstore::open(&blockstore_path).unwrap();
let status = TransactionStatusMeta {
status: Ok(()),
fee: 42,
pre_balances: vec![1, 2, 3],
post_balances: vec![1, 2, 3],
inner_instructions: Some(vec![]),
log_messages: Some(vec![]),
pre_token_balances: Some(vec![TransactionTokenBalance {
account_index: 0,
mint: Pubkey::new_unique().to_string(),
ui_token_amount: UiTokenAmount {
ui_amount: Some(1.1),
decimals: 1,
amount: "11".to_string(),
ui_amount_string: "1.1".to_string(),
},
}]),
post_token_balances: Some(vec![TransactionTokenBalance {
account_index: 0,
mint: Pubkey::new_unique().to_string(),
ui_token_amount: UiTokenAmount {
ui_amount: None,
decimals: 1,
amount: "11".to_string(),
ui_amount_string: "1.1".to_string(),
},
}]),
};
let deprecated_status: StoredTransactionStatusMeta = status.clone().into();
let protobuf_status: generated::TransactionStatusMeta = status.into();
for slot in 0..2 {
let data = serialize(&deprecated_status).unwrap();
blockstore
.transaction_status_cf
.put_bytes((0, Signature::default(), slot), &data)
.unwrap();
}
for slot in 2..4 {
blockstore
.transaction_status_cf
.put_protobuf((0, Signature::default(), slot), &protobuf_status)
.unwrap();
}
for slot in 0..4 {
assert_eq!(
blockstore
.transaction_status_cf
.get_protobuf_or_bincode::<StoredTransactionStatusMeta>((
0,
Signature::default(),
slot
))
.unwrap()
.unwrap(),
protobuf_status
);
}
}
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
}
#[test] #[test]
fn test_remove_shred_data_complete_flag() { fn test_remove_shred_data_complete_flag() {
let (mut shreds, entries) = make_slot_entries(0, 0, 1); let (mut shreds, entries) = make_slot_entries(0, 0, 1);

View File

@ -504,7 +504,7 @@ pub mod tests {
Signature::new(&random_bytes), Signature::new(&random_bytes),
vec![&Pubkey::new(&random_bytes[0..32])], vec![&Pubkey::new(&random_bytes[0..32])],
vec![&Pubkey::new(&random_bytes[32..])], vec![&Pubkey::new(&random_bytes[32..])],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -519,7 +519,7 @@ pub mod tests {
Signature::new(&random_bytes), Signature::new(&random_bytes),
vec![&Pubkey::new(&random_bytes[0..32])], vec![&Pubkey::new(&random_bytes[0..32])],
vec![&Pubkey::new(&random_bytes[32..])], vec![&Pubkey::new(&random_bytes[32..])],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -556,7 +556,7 @@ pub mod tests {
Signature::new(&random_bytes), Signature::new(&random_bytes),
vec![&Pubkey::new(&random_bytes[0..32])], vec![&Pubkey::new(&random_bytes[0..32])],
vec![&Pubkey::new(&random_bytes[32..])], vec![&Pubkey::new(&random_bytes[32..])],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -745,7 +745,7 @@ pub mod tests {
signature, signature,
vec![&Pubkey::new(&random_bytes[0..32])], vec![&Pubkey::new(&random_bytes[0..32])],
vec![&Pubkey::new(&random_bytes[32..])], vec![&Pubkey::new(&random_bytes[32..])],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }
@ -781,7 +781,7 @@ pub mod tests {
signature, signature,
vec![&Pubkey::new(&random_bytes[0..32])], vec![&Pubkey::new(&random_bytes[0..32])],
vec![&Pubkey::new(&random_bytes[32..])], vec![&Pubkey::new(&random_bytes[32..])],
&TransactionStatusMeta::default(), TransactionStatusMeta::default(),
) )
.unwrap(); .unwrap();
} }

View File

@ -17,7 +17,6 @@ use solana_sdk::{
signature::Signature, signature::Signature,
}; };
use solana_storage_proto::convert::generated; use solana_storage_proto::convert::generated;
use solana_transaction_status::TransactionStatusMeta;
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc}; use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
use thiserror::Error; use thiserror::Error;
@ -418,10 +417,6 @@ pub trait TypedColumn: Column {
type Type: Serialize + DeserializeOwned; type Type: Serialize + DeserializeOwned;
} }
impl TypedColumn for columns::TransactionStatus {
type Type = TransactionStatusMeta;
}
impl TypedColumn for columns::AddressSignatures { impl TypedColumn for columns::AddressSignatures {
type Type = blockstore_meta::AddressSignatureMeta; type Type = blockstore_meta::AddressSignatureMeta;
} }
@ -492,6 +487,9 @@ impl Column for columns::TransactionStatus {
impl ColumnName for columns::TransactionStatus { impl ColumnName for columns::TransactionStatus {
const NAME: &'static str = TRANSACTION_STATUS_CF; const NAME: &'static str = TRANSACTION_STATUS_CF;
} }
impl ProtobufColumn for columns::TransactionStatus {
type Type = generated::TransactionStatusMeta;
}
impl Column for columns::AddressSignatures { impl Column for columns::AddressSignatures {
type Index = (u64, Pubkey, Slot, Signature); type Index = (u64, Pubkey, Slot, Signature);

View File

@ -1,4 +1,4 @@
use crate::StoredExtendedRewards; use crate::{StoredExtendedRewards, StoredTransactionStatusMeta};
use solana_account_decoder::parse_token::{real_number_string_trimmed, UiTokenAmount}; use solana_account_decoder::parse_token::{real_number_string_trimmed, UiTokenAmount};
use solana_sdk::{ use solana_sdk::{
hash::Hash, hash::Hash,
@ -312,6 +312,13 @@ impl From<TransactionStatusMeta> for generated::TransactionStatusMeta {
} }
} }
impl From<StoredTransactionStatusMeta> for generated::TransactionStatusMeta {
fn from(meta: StoredTransactionStatusMeta) -> Self {
let meta: TransactionStatusMeta = meta.into();
meta.into()
}
}
impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta { impl TryFrom<generated::TransactionStatusMeta> for TransactionStatusMeta {
type Error = bincode::Error; type Error = bincode::Error;

View File

@ -1,6 +1,13 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use solana_sdk::deserialize_utils::default_on_eof; use solana_account_decoder::{
use solana_transaction_status::{Reward, RewardType}; parse_token::{real_number_string_trimmed, UiTokenAmount},
StringAmount,
};
use solana_sdk::{deserialize_utils::default_on_eof, transaction::Result};
use solana_transaction_status::{
InnerInstructions, Reward, RewardType, TransactionStatusMeta, TransactionTokenBalance,
};
use std::str::FromStr;
pub mod convert; pub mod convert;
@ -50,3 +57,151 @@ impl From<Reward> for StoredExtendedReward {
} }
} }
} }
#[derive(Serialize, Deserialize)]
pub struct StoredTokenAmount {
pub ui_amount: f64,
pub decimals: u8,
pub amount: StringAmount,
}
impl From<StoredTokenAmount> for UiTokenAmount {
fn from(value: StoredTokenAmount) -> Self {
let StoredTokenAmount {
ui_amount,
decimals,
amount,
} = value;
let ui_amount_string =
real_number_string_trimmed(u64::from_str(&amount).unwrap_or(0), decimals);
Self {
ui_amount: Some(ui_amount),
decimals,
amount,
ui_amount_string,
}
}
}
impl From<UiTokenAmount> for StoredTokenAmount {
fn from(value: UiTokenAmount) -> Self {
let UiTokenAmount {
ui_amount,
decimals,
amount,
..
} = value;
Self {
ui_amount: ui_amount.unwrap_or(0.0),
decimals,
amount,
}
}
}
#[derive(Serialize, Deserialize)]
pub struct StoredTransactionTokenBalance {
pub account_index: u8,
pub mint: String,
pub ui_token_amount: StoredTokenAmount,
}
impl From<StoredTransactionTokenBalance> for TransactionTokenBalance {
fn from(value: StoredTransactionTokenBalance) -> Self {
let StoredTransactionTokenBalance {
account_index,
mint,
ui_token_amount,
} = value;
Self {
account_index,
mint,
ui_token_amount: ui_token_amount.into(),
}
}
}
impl From<TransactionTokenBalance> for StoredTransactionTokenBalance {
fn from(value: TransactionTokenBalance) -> Self {
let TransactionTokenBalance {
account_index,
mint,
ui_token_amount,
} = value;
Self {
account_index,
mint,
ui_token_amount: ui_token_amount.into(),
}
}
}
#[derive(Serialize, Deserialize)]
pub struct StoredTransactionStatusMeta {
pub status: Result<()>,
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>>,
#[serde(deserialize_with = "default_on_eof")]
pub log_messages: Option<Vec<String>>,
#[serde(deserialize_with = "default_on_eof")]
pub pre_token_balances: Option<Vec<StoredTransactionTokenBalance>>,
#[serde(deserialize_with = "default_on_eof")]
pub post_token_balances: Option<Vec<StoredTransactionTokenBalance>>,
}
impl From<StoredTransactionStatusMeta> for TransactionStatusMeta {
fn from(value: StoredTransactionStatusMeta) -> Self {
let StoredTransactionStatusMeta {
status,
fee,
pre_balances,
post_balances,
inner_instructions,
log_messages,
pre_token_balances,
post_token_balances,
} = value;
Self {
status,
fee,
pre_balances,
post_balances,
inner_instructions,
log_messages,
pre_token_balances: pre_token_balances
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
post_token_balances: post_token_balances
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
}
}
}
impl From<TransactionStatusMeta> for StoredTransactionStatusMeta {
fn from(value: TransactionStatusMeta) -> Self {
let TransactionStatusMeta {
status,
fee,
pre_balances,
post_balances,
inner_instructions,
log_messages,
pre_token_balances,
post_token_balances,
} = value;
Self {
status,
fee,
pre_balances,
post_balances,
inner_instructions,
log_messages,
pre_token_balances: pre_token_balances
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
post_token_balances: post_token_balances
.map(|balances| balances.into_iter().map(|balance| balance.into()).collect()),
}
}
}