diff --git a/client-test/tests/client.rs b/client-test/tests/client.rs index 8f0116e106..5e1e3b1b78 100644 --- a/client-test/tests/client.rs +++ b/client-test/tests/client.rs @@ -8,7 +8,7 @@ use { RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter, RpcProgramAccountsConfig, }, - rpc_response::{RpcBlockUpdate, SlotInfo}, + rpc_response::SlotInfo, }, solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path}, solana_rpc::{ @@ -34,7 +34,9 @@ use { }, solana_streamer::socket::SocketAddrSpace, solana_test_validator::TestValidator, - solana_transaction_status::{TransactionDetails, UiTransactionEncoding}, + solana_transaction_status::{ + ConfirmedBlockWithOptionalMetadata, TransactionDetails, UiTransactionEncoding, + }, std::{ collections::HashSet, net::{IpAddr, SocketAddr}, @@ -212,6 +214,7 @@ fn test_block_subscription() { .. } = create_genesis_config(10_000); let bank = Bank::new_for_tests(&genesis_config); + let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0); let bank_forks = Arc::new(RwLock::new(BankForks::new(bank))); // setup Blockstore @@ -225,6 +228,8 @@ fn test_block_subscription() { let keypair2 = Keypair::new(); let keypair3 = Keypair::new(); let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root())); + bank.transfer(rent_exempt_amount, &alice, &keypair2.pubkey()) + .unwrap(); let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore( vec![&alice, &keypair1, &keypair2, &keypair3], 0, @@ -276,22 +281,12 @@ fn test_block_subscription() { match maybe_actual { Ok(actual) => { let complete_block = blockstore.get_complete_block(slot, false).unwrap(); - let block = complete_block.clone().configure( + let block = ConfirmedBlockWithOptionalMetadata::from(complete_block).configure( UiTransactionEncoding::Json, TransactionDetails::Signatures, false, ); - let expected = RpcBlockUpdate { - slot, - block: Some(block), - err: None, - }; - let block = complete_block.configure( - UiTransactionEncoding::Json, - TransactionDetails::Signatures, - false, - ); - assert_eq!(actual.value.slot, expected.slot); + assert_eq!(actual.value.slot, slot); assert!(block.eq(&actual.value.block.unwrap())); } Err(e) => { diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index 51c62a3b9b..39413c0178 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -2067,7 +2067,7 @@ mod tests { transaction::{Transaction, TransactionError}, }, solana_streamer::{recvmmsg::recv_mmsg, socket::SocketAddrSpace}, - solana_transaction_status::TransactionWithStatusMeta, + solana_transaction_status::TransactionWithMetadata, solana_vote_program::vote_transaction, std::{ net::SocketAddr, @@ -3223,39 +3223,23 @@ mod tests { genesis_config.rent.lamports_per_byte_year = 50; genesis_config.rent.exemption_threshold = 2.0; let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config)); + let rent_exempt_minimum = bank.get_minimum_balance_for_rent_exemption(0); let pubkey = solana_sdk::pubkey::new_rand(); let pubkey1 = solana_sdk::pubkey::new_rand(); let keypair1 = Keypair::new(); - let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0); - - let success_tx = system_transaction::transfer( - &mint_keypair, - &pubkey, - rent_exempt_amount, - genesis_config.hash(), - ); + let success_tx = + system_transaction::transfer(&mint_keypair, &pubkey, 0, genesis_config.hash()); let success_signature = success_tx.signatures[0]; let entry_1 = next_entry(&genesis_config.hash(), 1, vec![success_tx.clone()]); - let ix_error_tx = system_transaction::transfer( - &keypair1, - &pubkey1, - 2 * rent_exempt_amount, - genesis_config.hash(), - ); + let ix_error_tx = + system_transaction::transfer(&keypair1, &pubkey1, std::u64::MAX, genesis_config.hash()); let ix_error_signature = ix_error_tx.signatures[0]; let entry_2 = next_entry(&entry_1.hash, 1, vec![ix_error_tx.clone()]); - let fail_tx = system_transaction::transfer( - &mint_keypair, - &pubkey1, - rent_exempt_amount, - genesis_config.hash(), - ); - let entry_3 = next_entry(&entry_2.hash, 1, vec![fail_tx.clone()]); - let entries = vec![entry_1, entry_2, entry_3]; + let entries = vec![entry_1, entry_2]; - let transactions = sanitize_transactions(vec![success_tx, ix_error_tx, fail_tx]); - bank.transfer(rent_exempt_amount, &mint_keypair, &keypair1.pubkey()) + let transactions = sanitize_transactions(vec![success_tx, ix_error_tx]); + bank.transfer(rent_exempt_minimum, &mint_keypair, &keypair1.pubkey()) .unwrap(); let ledger_path = get_tmp_ledger_path_auto_delete!(); @@ -3314,27 +3298,24 @@ mod tests { transaction_status_service.join().unwrap(); let confirmed_block = blockstore.get_rooted_block(bank.slot(), false).unwrap(); - assert_eq!(confirmed_block.transactions.len(), 3); - - for TransactionWithStatusMeta { transaction, meta } in - confirmed_block.transactions.into_iter() - { - if transaction.signatures[0] == success_signature { - let meta = meta.unwrap(); - assert_eq!(meta.status, Ok(())); - } else if transaction.signatures[0] == ix_error_signature { - let meta = meta.unwrap(); - assert_eq!( - meta.status, - Err(TransactionError::InstructionError( - 0, - InstructionError::Custom(1) - )) - ); - } else { - assert_eq!(meta, None); - } - } + let actual_tx_results: Vec<_> = confirmed_block + .transactions + .into_iter() + .map(|TransactionWithMetadata { transaction, meta }| { + (transaction.signatures[0], meta.status) + }) + .collect(); + let expected_tx_results = vec![ + (success_signature, Ok(())), + ( + ix_error_signature, + Err(TransactionError::InstructionError( + 0, + InstructionError::Custom(1), + )), + ), + ]; + assert_eq!(actual_tx_results, expected_tx_results); poh_recorder .lock() diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index 84c975f058..9166100feb 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -3021,7 +3021,7 @@ pub mod tests { transaction::TransactionError, }, solana_streamer::socket::SocketAddrSpace, - solana_transaction_status::TransactionWithStatusMeta, + solana_transaction_status::TransactionWithMetadata, solana_vote_program::{ vote_state::{VoteState, VoteStateVersions}, vote_transaction, @@ -3871,36 +3871,35 @@ pub mod tests { let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1)); let slot = bank1.slot(); - let signatures = create_test_transactions_and_populate_blockstore( + let mut test_signatures_iter = create_test_transactions_and_populate_blockstore( vec![&mint_keypair, &keypair1, &keypair2, &keypair3], bank0.slot(), bank1, blockstore.clone(), Arc::new(AtomicU64::default()), - ); + ) + .into_iter(); let confirmed_block = blockstore.get_rooted_block(slot, false).unwrap(); - assert_eq!(confirmed_block.transactions.len(), 3); - - for TransactionWithStatusMeta { transaction, meta } in - confirmed_block.transactions.into_iter() - { - if transaction.signatures[0] == signatures[0] { - let meta = meta.unwrap(); - assert_eq!(meta.status, Ok(())); - } else if transaction.signatures[0] == signatures[1] { - let meta = meta.unwrap(); - assert_eq!( - meta.status, - Err(TransactionError::InstructionError( - 0, - InstructionError::Custom(1) - )) - ); - } else { - assert_eq!(meta, None); - } - } + let actual_tx_results: Vec<_> = confirmed_block + .transactions + .into_iter() + .map(|TransactionWithMetadata { transaction, meta }| { + (transaction.signatures[0], meta.status) + }) + .collect(); + let expected_tx_results = vec![ + (test_signatures_iter.next().unwrap(), Ok(())), + ( + test_signatures_iter.next().unwrap(), + Err(TransactionError::InstructionError( + 0, + InstructionError::Custom(1), + )), + ), + ]; + assert_eq!(actual_tx_results, expected_tx_results); + assert!(test_signatures_iter.next().is_none()); } Blockstore::destroy(&ledger_path).unwrap(); } diff --git a/ledger-tool/src/bigtable.rs b/ledger-tool/src/bigtable.rs index 1f01fe3135..9feb25d0ae 100644 --- a/ledger-tool/src/bigtable.rs +++ b/ledger-tool/src/bigtable.rs @@ -16,7 +16,9 @@ use { }, solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType}, solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature}, - solana_transaction_status::{ConfirmedBlock, EncodedTransaction, UiTransactionEncoding}, + solana_transaction_status::{ + ConfirmedBlockWithOptionalMetadata, EncodedTransaction, UiTransactionEncoding, + }, std::{ collections::HashSet, path::Path, @@ -30,7 +32,6 @@ async fn upload( blockstore: Blockstore, starting_slot: Slot, ending_slot: Option, - allow_missing_metadata: bool, force_reupload: bool, ) -> Result<(), Box> { let bigtable = solana_storage_bigtable::LedgerStorage::new(false, None, None) @@ -42,7 +43,6 @@ async fn upload( bigtable, starting_slot, ending_slot, - allow_missing_metadata, force_reupload, Arc::new(AtomicBool::new(false)), ) @@ -194,7 +194,7 @@ pub async fn transaction_history( ) -> Result<(), Box> { let bigtable = solana_storage_bigtable::LedgerStorage::new(true, None, None).await?; - let mut loaded_block: Option<(Slot, ConfirmedBlock)> = None; + let mut loaded_block: Option<(Slot, ConfirmedBlockWithOptionalMetadata)> = None; while limit > 0 { let results = bigtable .get_confirmed_signatures_for_address( @@ -306,12 +306,6 @@ impl BigTableSubCommand for App<'_, '_> { .index(2) .help("Stop uploading at this slot [default: last available slot]"), ) - .arg( - Arg::with_name("allow_missing_metadata") - .long("allow-missing-metadata") - .takes_value(false) - .help("Don't panic if transaction metadata is missing"), - ) .arg( Arg::with_name("force_reupload") .long("force") @@ -506,7 +500,6 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) { ("upload", Some(arg_matches)) => { let starting_slot = value_t!(arg_matches, "starting_slot", Slot).unwrap_or(0); let ending_slot = value_t!(arg_matches, "ending_slot", Slot).ok(); - let allow_missing_metadata = arg_matches.is_present("allow_missing_metadata"); let force_reupload = arg_matches.is_present("force_reupload"); let blockstore = crate::open_blockstore( &canonicalize_ledger_path(ledger_path), @@ -518,7 +511,6 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) { blockstore, starting_slot, ending_slot, - allow_missing_metadata, force_reupload, )) } diff --git a/ledger/src/bigtable_upload.rs b/ledger/src/bigtable_upload.rs index 860a6348bf..fe170da142 100644 --- a/ledger/src/bigtable_upload.rs +++ b/ledger/src/bigtable_upload.rs @@ -25,7 +25,6 @@ pub async fn upload_confirmed_blocks( bigtable: solana_storage_bigtable::LedgerStorage, starting_slot: Slot, ending_slot: Option, - allow_missing_metadata: bool, force_reupload: bool, exit: Arc, ) -> Result<(), Box> { @@ -186,20 +185,7 @@ pub async fn upload_confirmed_blocks( num_blocks -= 1; None } - Some(confirmed_block) => { - if confirmed_block - .transactions - .iter() - .any(|transaction| transaction.meta.is_none()) - { - if allow_missing_metadata { - info!("Transaction metadata missing from slot {}", slot); - } else { - panic!("Transaction metadata missing from slot {}", slot); - } - } - Some(bigtable.upload_confirmed_block(slot, confirmed_block)) - } + Some(confirmed_block) => Some(bigtable.upload_confirmed_block(slot, confirmed_block)), }); for result in futures::future::join_all(uploads).await { diff --git a/ledger/src/bigtable_upload_service.rs b/ledger/src/bigtable_upload_service.rs index 9dba8e483c..bf9eb6085b 100644 --- a/ledger/src/bigtable_upload_service.rs +++ b/ledger/src/bigtable_upload_service.rs @@ -72,7 +72,6 @@ impl BigTableUploadService { bigtable_ledger_storage.clone(), start_slot, Some(end_slot), - true, false, exit.clone(), )); diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index f2cd775fb1..18e6d28017 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -42,7 +42,7 @@ use { solana_storage_proto::{StoredExtendedRewards, StoredTransactionStatusMeta}, solana_transaction_status::{ ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Rewards, - TransactionStatusMeta, TransactionWithStatusMeta, + TransactionStatusMeta, TransactionWithMetadata, }, std::{ borrow::Cow, @@ -1945,18 +1945,17 @@ impl Blockstore { &self, slot: Slot, iterator: impl Iterator, - ) -> Result> { + ) -> Result> { iterator .map(|versioned_tx| { // TODO: add support for versioned transactions if let Some(transaction) = versioned_tx.into_legacy_transaction() { let signature = transaction.signatures[0]; - Ok(TransactionWithStatusMeta { + Ok(TransactionWithMetadata { transaction, meta: self - .read_transaction_status((signature, slot)) - .ok() - .flatten(), + .read_transaction_status((signature, slot))? + .ok_or(BlockstoreError::MissingTransactionMetadata)?, }) } else { Err(BlockstoreError::UnsupportedTransactionVersion) @@ -2243,7 +2242,7 @@ impl Blockstore { signature: Signature, confirmed_unrooted_slots: &[Slot], ) -> Result> { - if let Some((slot, status)) = + if let Some((slot, meta)) = self.get_transaction_status(signature, confirmed_unrooted_slots)? { let transaction = self @@ -2258,10 +2257,7 @@ impl Blockstore { let block_time = self.get_block_time(slot)?; Ok(Some(ConfirmedTransaction { slot, - transaction: TransactionWithStatusMeta { - transaction, - meta: Some(status), - }, + transaction: TransactionWithMetadata { transaction, meta }, block_time, })) } else { @@ -6052,7 +6048,7 @@ pub mod tests { .put_meta_bytes(slot - 1, &serialize(&parent_meta).unwrap()) .unwrap(); - let expected_transactions: Vec = entries + let expected_transactions: Vec = entries .iter() .cloned() .filter(|entry| !entry.is_tick()) @@ -6118,9 +6114,9 @@ pub mod tests { .transaction_status_cf .put_protobuf((0, signature, slot + 2), &status) .unwrap(); - TransactionWithStatusMeta { + TransactionWithMetadata { transaction, - meta: Some(TransactionStatusMeta { + meta: TransactionStatusMeta { status: Ok(()), fee: 42, pre_balances, @@ -6130,21 +6126,22 @@ pub mod tests { pre_token_balances: Some(vec![]), post_token_balances: Some(vec![]), rewards: Some(vec![]), - }), + }, } }) .collect(); // Even if marked as root, a slot that is empty of entries should return an error - let confirmed_block_err = blockstore.get_rooted_block(slot - 1, true).unwrap_err(); - assert_matches!(confirmed_block_err, BlockstoreError::SlotUnavailable); + assert_matches!( + blockstore.get_rooted_block(slot - 1, true), + Err(BlockstoreError::SlotUnavailable) + ); // The previous_blockhash of `expected_block` is default because its parent slot is a root, // but empty of entries (eg. snapshot root slots). This now returns an error. - let confirmed_block_err = blockstore.get_rooted_block(slot, true).unwrap_err(); assert_matches!( - confirmed_block_err, - BlockstoreError::ParentEntriesUnavailable + blockstore.get_rooted_block(slot, true), + Err(BlockstoreError::ParentEntriesUnavailable) ); // Test if require_previous_blockhash is false @@ -6908,7 +6905,7 @@ pub mod tests { blockstore.insert_shreds(shreds, None, false).unwrap(); blockstore.set_roots(vec![slot - 1, slot].iter()).unwrap(); - let expected_transactions: Vec = entries + let expected_transactions: Vec = entries .iter() .cloned() .filter(|entry| !entry.is_tick()) @@ -6949,9 +6946,9 @@ pub mod tests { .transaction_status_cf .put_protobuf((0, signature, slot), &status) .unwrap(); - TransactionWithStatusMeta { + TransactionWithMetadata { transaction, - meta: Some(TransactionStatusMeta { + meta: TransactionStatusMeta { status: Ok(()), fee: 42, pre_balances, @@ -6961,7 +6958,7 @@ pub mod tests { pre_token_balances, post_token_balances, rewards, - }), + }, } }) .collect(); @@ -6990,7 +6987,7 @@ pub mod tests { blockstore.run_purge(0, 2, PurgeType::PrimaryIndex).unwrap(); *blockstore.lowest_cleanup_slot.write().unwrap() = slot; - for TransactionWithStatusMeta { transaction, .. } in expected_transactions { + for TransactionWithMetadata { transaction, .. } in expected_transactions { let signature = transaction.signatures[0]; assert_eq!(blockstore.get_rooted_transaction(signature).unwrap(), None,); assert_eq!( @@ -7012,7 +7009,7 @@ pub mod tests { let shreds = entries_to_test_shreds(entries.clone(), slot, slot - 1, true, 0); blockstore.insert_shreds(shreds, None, false).unwrap(); - let expected_transactions: Vec = entries + let expected_transactions: Vec = entries .iter() .cloned() .filter(|entry| !entry.is_tick()) @@ -7053,9 +7050,9 @@ pub mod tests { .transaction_status_cf .put_protobuf((0, signature, slot), &status) .unwrap(); - TransactionWithStatusMeta { + TransactionWithMetadata { transaction, - meta: Some(TransactionStatusMeta { + meta: TransactionStatusMeta { status: Ok(()), fee: 42, pre_balances, @@ -7065,7 +7062,7 @@ pub mod tests { pre_token_balances, post_token_balances, rewards, - }), + }, } }) .collect(); @@ -7087,7 +7084,7 @@ pub mod tests { blockstore.run_purge(0, 2, PurgeType::PrimaryIndex).unwrap(); *blockstore.lowest_cleanup_slot.write().unwrap() = slot; - for TransactionWithStatusMeta { transaction, .. } in expected_transactions { + for TransactionWithMetadata { transaction, .. } in expected_transactions { let signature = transaction.signatures[0]; assert_eq!( blockstore @@ -7809,7 +7806,6 @@ pub mod tests { fn test_map_transactions_to_statuses() { let ledger_path = get_tmp_ledger_path_auto_delete!(); let blockstore = Blockstore::open(ledger_path.path()).unwrap(); - let transaction_status_cf = &blockstore.transaction_status_cf; let slot = 0; @@ -7841,6 +7837,16 @@ pub mod tests { .unwrap(); transactions.push(transaction.into()); } + + let map_result = + blockstore.map_transactions_to_statuses(slot, transactions.clone().into_iter()); + assert!(map_result.is_ok()); + let map = map_result.unwrap(); + assert_eq!(map.len(), 4); + for (x, m) in map.iter().enumerate() { + assert_eq!(m.meta.fee, x as u64); + } + // Push transaction that will not have matching status, as a test case transactions.push( Transaction::new_with_compiled_instructions( @@ -7854,13 +7860,7 @@ pub mod tests { ); let map_result = blockstore.map_transactions_to_statuses(slot, transactions.into_iter()); - assert!(map_result.is_ok()); - let map = map_result.unwrap(); - assert_eq!(map.len(), 5); - for (x, m) in map.iter().take(4).enumerate() { - assert_eq!(m.meta.as_ref().unwrap().fee, x as u64); - } - assert_eq!(map[4].meta, None); + assert_matches!(map_result, Err(BlockstoreError::MissingTransactionMetadata)); } #[test] diff --git a/ledger/src/blockstore_db.rs b/ledger/src/blockstore_db.rs index c7632931f4..4b20eb81ec 100644 --- a/ledger/src/blockstore_db.rs +++ b/ledger/src/blockstore_db.rs @@ -102,6 +102,7 @@ pub enum BlockstoreError { ParentEntriesUnavailable, SlotUnavailable, UnsupportedTransactionVersion, + MissingTransactionMetadata, } pub type Result = std::result::Result; diff --git a/local-cluster/tests/local_cluster_slow.rs b/local-cluster/tests/local_cluster_slow.rs index 3800d749bf..e92f42e911 100644 --- a/local-cluster/tests/local_cluster_slow.rs +++ b/local-cluster/tests/local_cluster_slow.rs @@ -877,46 +877,27 @@ fn find_latest_replayed_slot_from_ledger( latest_slot = new_latest_slot; info!("Checking latest_slot {}", latest_slot); // Wait for the slot to be fully received by the validator - let entries; loop { info!("Waiting for slot {} to be full", latest_slot); if blockstore.is_full(latest_slot) { - entries = blockstore.get_slot_entries(latest_slot, 0).unwrap(); - assert!(!entries.is_empty()); break; } else { sleep(Duration::from_millis(50)); blockstore = open_blockstore(ledger_path); } } - // Check the slot has been replayed - let non_tick_entry = entries.into_iter().find(|e| !e.transactions.is_empty()); - if let Some(non_tick_entry) = non_tick_entry { - // Wait for the slot to be replayed - loop { - info!("Waiting for slot {} to be replayed", latest_slot); - if !blockstore - .map_transactions_to_statuses( - latest_slot, - non_tick_entry.transactions.clone().into_iter(), - ) - .unwrap() - .is_empty() - { - return ( - latest_slot, - AncestorIterator::new(latest_slot, &blockstore).collect(), - ); - } else { - sleep(Duration::from_millis(50)); - blockstore = open_blockstore(ledger_path); - } + // Wait for the slot to be replayed + loop { + info!("Waiting for slot {} to be replayed", latest_slot); + if blockstore.get_bank_hash(latest_slot).is_some() { + return ( + latest_slot, + AncestorIterator::new(latest_slot, &blockstore).collect(), + ); + } else { + sleep(Duration::from_millis(50)); + blockstore = open_blockstore(ledger_path); } - } else { - info!( - "No transactions in slot {}, can't tell if it was replayed", - latest_slot - ); } } sleep(Duration::from_millis(50)); diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index ea52eee217..7d7e93739e 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -61,7 +61,8 @@ use solana_sdk::{ }; use solana_transaction_status::{ token_balances::collect_token_balances, ConfirmedTransaction, InnerInstructions, - TransactionStatusMeta, TransactionWithStatusMeta, + TransactionStatusMeta, + TransactionWithMetadata, }; use std::{collections::HashMap, env, fs::File, io::Read, path::PathBuf, str::FromStr, sync::Arc}; @@ -420,9 +421,9 @@ fn execute_transactions( Ok(ConfirmedTransaction { slot: bank.slot(), - transaction: TransactionWithStatusMeta { + transaction: TransactionWithMetadata { transaction: tx.clone(), - meta: Some(tx_status_meta), + meta: tx_status_meta, }, block_time: None, }) @@ -2466,8 +2467,8 @@ fn test_program_upgradeable_locks() { assert!(matches!( results1[0], Ok(ConfirmedTransaction { - transaction: TransactionWithStatusMeta { - meta: Some(TransactionStatusMeta { status: Ok(()), .. }), + transaction: TransactionWithMetadata { + meta: TransactionStatusMeta { status: Ok(()), .. }, .. }, .. @@ -2478,14 +2479,14 @@ fn test_program_upgradeable_locks() { assert!(matches!( results2[0], Ok(ConfirmedTransaction { - transaction: TransactionWithStatusMeta { - meta: Some(TransactionStatusMeta { + transaction: TransactionWithMetadata { + meta: TransactionStatusMeta { status: Err(TransactionError::InstructionError( 0, InstructionError::ProgramFailedToComplete )), .. - }), + }, .. }, .. diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 12415ea494..90c7e5713f 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -76,9 +76,9 @@ use { solana_storage_bigtable::Error as StorageError, solana_streamer::socket::SocketAddrSpace, solana_transaction_status::{ - ConfirmedBlock, ConfirmedTransactionStatusWithSignature, EncodedConfirmedTransaction, - Reward, RewardType, TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, - UiTransactionEncoding, + ConfirmedBlockWithOptionalMetadata, ConfirmedTransactionStatusWithSignature, + ConfirmedTransactionWithOptionalMetadata, EncodedConfirmedTransaction, Reward, RewardType, + TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, UiTransactionEncoding, }, solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY}, spl_token::{ @@ -914,12 +914,8 @@ impl JsonRpcRequestProcessor { &self, result: &std::result::Result, slot: Slot, - ) -> Result<()> - where - T: std::fmt::Debug, - { - if result.is_err() { - let err = result.as_ref().unwrap_err(); + ) -> Result<()> { + if let Err(err) = result { debug!( "check_blockstore_root, slot: {:?}, max root: {:?}, err: {:?}", slot, @@ -940,21 +936,16 @@ impl JsonRpcRequestProcessor { &self, result: &std::result::Result, slot: Slot, - ) -> Result<()> - where - T: std::fmt::Debug, - { - if result.is_err() { - if let BlockstoreError::SlotCleanedUp = result.as_ref().unwrap_err() { - return Err(RpcCustomError::BlockCleanedUp { - slot, - first_available_block: self - .blockstore - .get_first_available_block() - .unwrap_or_default(), - } - .into()); + ) -> Result<()> { + if let Err(BlockstoreError::SlotCleanedUp) = result { + return Err(RpcCustomError::BlockCleanedUp { + slot, + first_available_block: self + .blockstore + .get_first_available_block() + .unwrap_or_default(), } + .into()); } Ok(()) } @@ -962,15 +953,9 @@ impl JsonRpcRequestProcessor { fn check_bigtable_result( &self, result: &std::result::Result, - ) -> Result<()> - where - T: std::fmt::Debug, - { - if result.is_err() { - let err = result.as_ref().unwrap_err(); - if let solana_storage_bigtable::Error::BlockNotFound(slot) = err { - return Err(RpcCustomError::LongTermStorageSlotSkipped { slot: *slot }.into()); - } + ) -> Result<()> { + if let Err(solana_storage_bigtable::Error::BlockNotFound(slot)) = result { + return Err(RpcCustomError::LongTermStorageSlotSkipped { slot: *slot }.into()); } Ok(()) } @@ -1013,7 +998,7 @@ impl JsonRpcRequestProcessor { self.check_status_is_complete(slot)?; let result = self.blockstore.get_rooted_block(slot, true); self.check_blockstore_root(&result, slot)?; - let configure_block = |confirmed_block: ConfirmedBlock| { + let configure_block = |confirmed_block: ConfirmedBlockWithOptionalMetadata| { let mut confirmed_block = confirmed_block.configure(encoding, transaction_details, show_rewards); if slot == 0 { @@ -1031,7 +1016,10 @@ impl JsonRpcRequestProcessor { } } self.check_slot_cleaned_up(&result, slot)?; - return Ok(result.ok().map(configure_block)); + return Ok(result + .ok() + .map(ConfirmedBlockWithOptionalMetadata::from) + .map(configure_block)); } else if commitment.is_confirmed() { // Check if block is confirmed let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed())); @@ -1053,7 +1041,11 @@ impl JsonRpcRequestProcessor { } } } - confirmed_block.configure(encoding, transaction_details, show_rewards) + ConfirmedBlockWithOptionalMetadata::from(confirmed_block).configure( + encoding, + transaction_details, + show_rewards, + ) })); } } @@ -1399,7 +1391,10 @@ impl JsonRpcRequestProcessor { .get(confirmed_transaction.slot) .map(|bank| bank.clock().unix_timestamp); } - return Ok(Some(confirmed_transaction.encode(encoding))); + return Ok(Some( + ConfirmedTransactionWithOptionalMetadata::from(confirmed_transaction) + .encode(encoding), + )); } if confirmed_transaction.slot <= self @@ -1408,7 +1403,10 @@ impl JsonRpcRequestProcessor { .unwrap() .highest_confirmed_root() { - return Ok(Some(confirmed_transaction.encode(encoding))); + return Ok(Some( + ConfirmedTransactionWithOptionalMetadata::from(confirmed_transaction) + .encode(encoding), + )); } } None => { @@ -4315,15 +4313,7 @@ pub fn create_test_transactions_and_populate_blockstore( ); let ix_error_signature = ix_error_tx.signatures[0]; let entry_2 = solana_entry::entry::next_entry(&entry_1.hash, 1, vec![ix_error_tx]); - // Failed transaction - let fail_tx = solana_sdk::system_transaction::transfer( - mint_keypair, - &keypair2.pubkey(), - rent_exempt_amount, - Hash::default(), - ); - let entry_3 = solana_entry::entry::next_entry(&entry_2.hash, 1, vec![fail_tx]); - let entries = vec![entry_1, entry_2, entry_3]; + let entries = vec![entry_1, entry_2]; let shreds = solana_ledger::blockstore::entries_to_test_shreds( entries.clone(), @@ -4349,17 +4339,20 @@ pub fn create_test_transactions_and_populate_blockstore( // Check that process_entries successfully writes can_commit transactions statuses, and // that they are matched properly by get_rooted_block - let _result = solana_ledger::blockstore_processor::process_entries_for_tests( - &bank, - entries, - true, - Some( - &solana_ledger::blockstore_processor::TransactionStatusSender { - sender: transaction_status_sender, - enable_cpi_and_log_storage: false, - }, + assert_eq!( + solana_ledger::blockstore_processor::process_entries_for_tests( + &bank, + entries, + true, + Some( + &solana_ledger::blockstore_processor::TransactionStatusSender { + sender: transaction_status_sender, + enable_cpi_and_log_storage: false, + }, + ), + Some(&replay_vote_sender), ), - Some(&replay_vote_sender), + Ok(()) ); transaction_status_service.join().unwrap(); @@ -6605,7 +6598,7 @@ pub mod tests { let confirmed_block: Option = serde_json::from_value(result["result"].clone()).unwrap(); let confirmed_block = confirmed_block.unwrap(); - assert_eq!(confirmed_block.transactions.len(), 3); + assert_eq!(confirmed_block.transactions.len(), 2); assert_eq!(confirmed_block.rewards, vec![]); for EncodedTransactionWithStatusMeta { transaction, meta } in @@ -6650,7 +6643,7 @@ pub mod tests { let confirmed_block: Option = serde_json::from_value(result["result"].clone()).unwrap(); let confirmed_block = confirmed_block.unwrap(); - assert_eq!(confirmed_block.transactions.len(), 3); + assert_eq!(confirmed_block.transactions.len(), 2); assert_eq!(confirmed_block.rewards, vec![]); for EncodedTransactionWithStatusMeta { transaction, meta } in diff --git a/rpc/src/rpc_subscriptions.rs b/rpc/src/rpc_subscriptions.rs index 3b22244fc8..4be2dcde3f 100644 --- a/rpc/src/rpc_subscriptions.rs +++ b/rpc/src/rpc_subscriptions.rs @@ -39,7 +39,7 @@ use { timing::timestamp, transaction, }, - solana_transaction_status::ConfirmedBlock, + solana_transaction_status::{ConfirmedBlock, ConfirmedBlockWithOptionalMetadata}, solana_vote_program::vote_state::Vote, std::{ cell::RefCell, @@ -278,30 +278,26 @@ impl RpcNotifier { } fn filter_block_result_txs( - block: ConfirmedBlock, + mut block: ConfirmedBlock, last_modified_slot: Slot, params: &BlockSubscriptionParams, ) -> Option { - let transactions = match params.kind { + block.transactions = match params.kind { BlockSubscriptionKind::All => block.transactions, BlockSubscriptionKind::MentionsAccountOrProgram(pk) => block .transactions .into_iter() - .filter(|tx| tx.transaction.message.account_keys.contains(&pk)) + .filter(|tx_with_meta| tx_with_meta.transaction.message.account_keys.contains(&pk)) .collect(), }; - if transactions.is_empty() { + if block.transactions.is_empty() { if let BlockSubscriptionKind::MentionsAccountOrProgram(_) = params.kind { return None; } } - let block = ConfirmedBlock { - transactions, - ..block - } - .configure( + let block = ConfirmedBlockWithOptionalMetadata::from(block).configure( params.encoding, params.transaction_details, params.show_rewards, @@ -964,12 +960,13 @@ impl RpcSubscriptions { } match blockstore.get_complete_block(s, false) { Ok(block) => { - if let Some(res) = filter_block_result_txs(block, s, params) + if let Some(block_update) = + filter_block_result_txs(block, s, params) { notifier.notify( Response { context: RpcResponseContext { slot: s }, - value: res, + value: block_update, }, subscription, false, @@ -1346,8 +1343,13 @@ pub(crate) mod tests { #[serial] fn test_check_confirmed_block_subscribe() { let exit = Arc::new(AtomicBool::new(false)); - let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000); + let GenesisConfigInfo { + genesis_config, + mint_keypair, + .. + } = create_genesis_config(10_000); let bank = Bank::new_for_tests(&genesis_config); + let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0); let bank_forks = Arc::new(RwLock::new(BankForks::new(bank))); let optimistically_confirmed_bank = OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks); @@ -1388,10 +1390,11 @@ pub(crate) mod tests { let keypair1 = Keypair::new(); let keypair2 = Keypair::new(); let keypair3 = Keypair::new(); - let keypair4 = Keypair::new(); let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root())); + bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey()) + .unwrap(); let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore( - vec![&keypair1, &keypair2, &keypair3, &keypair4], + vec![&mint_keypair, &keypair1, &keypair2, &keypair3], 0, bank, blockstore.clone(), @@ -1404,7 +1407,11 @@ pub(crate) mod tests { let actual_resp = serde_json::from_str::(&actual_resp).unwrap(); let block = blockstore.get_complete_block(slot, false).unwrap(); - let block = block.configure(params.encoding, params.transaction_details, false); + let block = ConfirmedBlockWithOptionalMetadata::from(block).configure( + params.encoding, + params.transaction_details, + false, + ); let expected_resp = RpcBlockUpdate { slot, block: Some(block), @@ -1443,8 +1450,13 @@ pub(crate) mod tests { #[serial] fn test_check_confirmed_block_subscribe_with_mentions() { let exit = Arc::new(AtomicBool::new(false)); - let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000); + let GenesisConfigInfo { + genesis_config, + mint_keypair, + .. + } = create_genesis_config(10_000); let bank = Bank::new_for_tests(&genesis_config); + let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0); let bank_forks = Arc::new(RwLock::new(BankForks::new(bank))); let optimistically_confirmed_bank = OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks); @@ -1486,10 +1498,11 @@ pub(crate) mod tests { let bank = bank_forks.read().unwrap().working_bank(); let keypair2 = Keypair::new(); let keypair3 = Keypair::new(); - let keypair4 = Keypair::new(); let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root())); + bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey()) + .unwrap(); let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore( - vec![&keypair1, &keypair2, &keypair3, &keypair4], + vec![&mint_keypair, &keypair1, &keypair2, &keypair3], 0, bank, blockstore.clone(), @@ -1509,7 +1522,11 @@ pub(crate) mod tests { .account_keys .contains(&keypair1.pubkey()) }); - let block = block.configure(params.encoding, params.transaction_details, false); + let block = ConfirmedBlockWithOptionalMetadata::from(block).configure( + params.encoding, + params.transaction_details, + false, + ); let expected_resp = RpcBlockUpdate { slot, block: Some(block), @@ -1538,8 +1555,13 @@ pub(crate) mod tests { #[serial] fn test_check_finalized_block_subscribe() { let exit = Arc::new(AtomicBool::new(false)); - let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000); + let GenesisConfigInfo { + genesis_config, + mint_keypair, + .. + } = create_genesis_config(10_000); let bank = Bank::new_for_tests(&genesis_config); + let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0); let bank_forks = Arc::new(RwLock::new(BankForks::new(bank))); let optimistically_confirmed_bank = OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks); @@ -1579,10 +1601,11 @@ pub(crate) mod tests { let keypair1 = Keypair::new(); let keypair2 = Keypair::new(); let keypair3 = Keypair::new(); - let keypair4 = Keypair::new(); let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root())); + bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey()) + .unwrap(); let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore( - vec![&keypair1, &keypair2, &keypair3, &keypair4], + vec![&mint_keypair, &keypair1, &keypair2, &keypair3], 0, bank, blockstore.clone(), @@ -1600,7 +1623,11 @@ pub(crate) mod tests { let actual_resp = serde_json::from_str::(&actual_resp).unwrap(); let block = blockstore.get_complete_block(slot, false).unwrap(); - let block = block.configure(params.encoding, params.transaction_details, false); + let block = ConfirmedBlockWithOptionalMetadata::from(block).configure( + params.encoding, + params.transaction_details, + false, + ); let expected_resp = RpcBlockUpdate { slot, block: Some(block), diff --git a/storage-bigtable/src/bigtable.rs b/storage-bigtable/src/bigtable.rs index bdd3e766e5..7cf864e3f1 100644 --- a/storage-bigtable/src/bigtable.rs +++ b/storage-bigtable/src/bigtable.rs @@ -793,19 +793,42 @@ mod tests { solana_sdk::{hash::Hash, signature::Keypair, system_transaction}, solana_storage_proto::convert::generated, solana_transaction_status::{ - ConfirmedBlock, TransactionStatusMeta, TransactionWithStatusMeta, + ConfirmedBlock, ConfirmedBlockWithOptionalMetadata, TransactionStatusMeta, + TransactionWithMetadata, }, std::convert::TryInto, }; + fn confirmed_block_into_protobuf(confirmed_block: ConfirmedBlock) -> generated::ConfirmedBlock { + let ConfirmedBlock { + previous_blockhash, + blockhash, + parent_slot, + transactions, + rewards, + block_time, + block_height, + } = confirmed_block; + + generated::ConfirmedBlock { + previous_blockhash, + blockhash, + parent_slot, + transactions: transactions.into_iter().map(Into::into).collect(), + rewards: rewards.into_iter().map(|r| r.into()).collect(), + block_time: block_time.map(|timestamp| generated::UnixTimestamp { timestamp }), + block_height: block_height.map(|block_height| generated::BlockHeight { block_height }), + } + } + #[test] fn test_deserialize_protobuf_or_bincode_cell_data() { let from = Keypair::new(); let recipient = solana_sdk::pubkey::new_rand(); let transaction = system_transaction::transfer(&from, &recipient, 42, Hash::default()); - let with_meta = TransactionWithStatusMeta { + let with_meta = TransactionWithMetadata { transaction, - meta: Some(TransactionStatusMeta { + meta: TransactionStatusMeta { status: Ok(()), fee: 1, pre_balances: vec![43, 0, 1], @@ -815,9 +838,9 @@ mod tests { pre_token_balances: Some(vec![]), post_token_balances: Some(vec![]), rewards: Some(vec![]), - }), + }, }; - let block = ConfirmedBlock { + let expected_block = ConfirmedBlock { transactions: vec![with_meta], parent_slot: 1, blockhash: Hash::default().to_string(), @@ -827,11 +850,14 @@ mod tests { block_height: Some(1), }; let bincode_block = compress_best( - &bincode::serialize::(&block.clone().into()).unwrap(), + &bincode::serialize::( + &ConfirmedBlockWithOptionalMetadata::from(expected_block.clone()).into(), + ) + .unwrap(), ) .unwrap(); - let protobuf_block = generated::ConfirmedBlock::from(block.clone()); + let protobuf_block = confirmed_block_into_protobuf(expected_block.clone()); let mut buf = Vec::with_capacity(protobuf_block.encoded_len()); protobuf_block.encode(&mut buf).unwrap(); let protobuf_block = compress_best(&buf).unwrap(); @@ -846,7 +872,10 @@ mod tests { ) .unwrap(); if let CellData::Protobuf(protobuf_block) = deserialized { - assert_eq!(block, protobuf_block.try_into().unwrap()); + assert_eq!( + ConfirmedBlockWithOptionalMetadata::from(expected_block.clone()), + protobuf_block.try_into().unwrap(), + ); } else { panic!("deserialization should produce CellData::Protobuf"); } @@ -861,15 +890,19 @@ mod tests { ) .unwrap(); if let CellData::Bincode(bincode_block) = deserialized { - let mut block = block; - if let Some(meta) = &mut block.transactions[0].meta { + let mut block = expected_block; + { + let mut meta = &mut block.transactions[0].meta; meta.inner_instructions = None; // Legacy bincode implementation does not support inner_instructions meta.log_messages = None; // Legacy bincode implementation does not support log_messages meta.pre_token_balances = None; // Legacy bincode implementation does not support token balances meta.post_token_balances = None; // Legacy bincode implementation does not support token balances meta.rewards = None; // Legacy bincode implementation does not support rewards } - assert_eq!(block, bincode_block.into()); + assert_eq!( + ConfirmedBlockWithOptionalMetadata::from(block), + ConfirmedBlockWithOptionalMetadata::from(bincode_block) + ); } else { panic!("deserialization should produce CellData::Bincode"); } diff --git a/storage-bigtable/src/lib.rs b/storage-bigtable/src/lib.rs index 1c8a91f57e..02c27c4167 100644 --- a/storage-bigtable/src/lib.rs +++ b/storage-bigtable/src/lib.rs @@ -13,10 +13,10 @@ use { }, solana_storage_proto::convert::{generated, tx_by_addr}, solana_transaction_status::{ - extract_and_fmt_memos, ConfirmedBlock, ConfirmedTransaction, - ConfirmedTransactionStatusWithSignature, Reward, TransactionByAddrInfo, - TransactionConfirmationStatus, TransactionStatus, TransactionStatusMeta, - TransactionWithStatusMeta, + extract_and_fmt_memos, ConfirmedBlock, ConfirmedBlockWithOptionalMetadata, + ConfirmedTransactionStatusWithSignature, ConfirmedTransactionWithOptionalMetadata, Reward, + TransactionByAddrInfo, TransactionConfirmationStatus, TransactionStatus, + TransactionStatusMeta, TransactionWithMetadata, TransactionWithOptionalMetadata, }, std::{ collections::{HashMap, HashSet}, @@ -114,9 +114,10 @@ struct StoredConfirmedBlock { block_height: Option, } -impl From for StoredConfirmedBlock { - fn from(confirmed_block: ConfirmedBlock) -> Self { - let ConfirmedBlock { +#[cfg(test)] +impl From for StoredConfirmedBlock { + fn from(confirmed_block: ConfirmedBlockWithOptionalMetadata) -> Self { + let ConfirmedBlockWithOptionalMetadata { previous_blockhash, blockhash, parent_slot, @@ -138,7 +139,7 @@ impl From for StoredConfirmedBlock { } } -impl From for ConfirmedBlock { +impl From for ConfirmedBlockWithOptionalMetadata { fn from(confirmed_block: StoredConfirmedBlock) -> Self { let StoredConfirmedBlock { previous_blockhash, @@ -168,8 +169,9 @@ struct StoredConfirmedBlockTransaction { meta: Option, } -impl From for StoredConfirmedBlockTransaction { - fn from(value: TransactionWithStatusMeta) -> Self { +#[cfg(test)] +impl From for StoredConfirmedBlockTransaction { + fn from(value: TransactionWithOptionalMetadata) -> Self { Self { transaction: value.transaction, meta: value.meta.map(|meta| meta.into()), @@ -177,7 +179,7 @@ impl From for StoredConfirmedBlockTransaction { } } -impl From for TransactionWithStatusMeta { +impl From for TransactionWithOptionalMetadata { fn from(value: StoredConfirmedBlockTransaction) -> Self { Self { transaction: value.transaction, @@ -392,7 +394,10 @@ impl LedgerStorage { } /// Fetch the confirmed block from the desired slot - pub async fn get_confirmed_block(&self, slot: Slot) -> Result { + pub async fn get_confirmed_block( + &self, + slot: Slot, + ) -> Result { debug!( "LedgerStorage::get_confirmed_block request received: {:?}", slot @@ -438,7 +443,7 @@ impl LedgerStorage { pub async fn get_confirmed_transaction( &self, signature: &Signature, - ) -> Result> { + ) -> Result> { debug!( "LedgerStorage::get_confirmed_transaction request received: {:?}", signature @@ -471,7 +476,7 @@ impl LedgerStorage { ); Ok(None) } else { - Ok(Some(ConfirmedTransaction { + Ok(Some(ConfirmedTransactionWithOptionalMetadata { slot, transaction: bucket_block_transaction, block_time: block.block_time, @@ -635,8 +640,8 @@ impl LedgerStorage { let mut tx_cells = vec![]; for (index, transaction_with_meta) in confirmed_block.transactions.iter().enumerate() { - let TransactionWithStatusMeta { meta, transaction } = transaction_with_meta; - let err = meta.as_ref().and_then(|meta| meta.status.clone().err()); + let TransactionWithMetadata { meta, transaction } = transaction_with_meta; + let err = meta.status.clone().err(); let index = index as u32; let signature = transaction.signatures[0]; let memo = extract_and_fmt_memos(&transaction.message); @@ -723,7 +728,7 @@ impl LedgerStorage { let mut expected_tx_infos: HashMap = HashMap::new(); let confirmed_block = self.get_confirmed_block(slot).await?; for (index, transaction_with_meta) in confirmed_block.transactions.iter().enumerate() { - let TransactionWithStatusMeta { meta, transaction } = transaction_with_meta; + let TransactionWithOptionalMetadata { meta, transaction } = transaction_with_meta; let signature = transaction.signatures[0]; let index = index as u32; let err = meta.as_ref().and_then(|meta| meta.status.clone().err()); diff --git a/storage-proto/src/convert.rs b/storage-proto/src/convert.rs index 0b4823a62e..6253e8e37c 100644 --- a/storage-proto/src/convert.rs +++ b/storage-proto/src/convert.rs @@ -10,8 +10,9 @@ use { transaction::{Transaction, TransactionError}, }, solana_transaction_status::{ - ConfirmedBlock, InnerInstructions, Reward, RewardType, TransactionByAddrInfo, - TransactionStatusMeta, TransactionTokenBalance, TransactionWithStatusMeta, + ConfirmedBlock, ConfirmedBlockWithOptionalMetadata, InnerInstructions, Reward, RewardType, + TransactionByAddrInfo, TransactionStatusMeta, TransactionTokenBalance, + TransactionWithMetadata, TransactionWithOptionalMetadata, }, std::{ convert::{TryFrom, TryInto}, @@ -135,7 +136,7 @@ impl From for generated::ConfirmedBlock { } } -impl TryFrom for ConfirmedBlock { +impl TryFrom for ConfirmedBlockWithOptionalMetadata { type Error = bincode::Error; fn try_from( confirmed_block: generated::ConfirmedBlock, @@ -157,7 +158,8 @@ impl TryFrom for ConfirmedBlock { transactions: transactions .into_iter() .map(|tx| tx.try_into()) - .collect::, Self::Error>>()?, + .collect::, Self::Error>>( + )?, rewards: rewards.into_iter().map(|r| r.into()).collect(), block_time: block_time.map(|generated::UnixTimestamp { timestamp }| timestamp), block_height: block_height.map(|generated::BlockHeight { block_height }| block_height), @@ -165,17 +167,16 @@ impl TryFrom for ConfirmedBlock { } } -impl From for generated::ConfirmedTransaction { - fn from(value: TransactionWithStatusMeta) -> Self { - let meta = value.meta.map(|meta| meta.into()); +impl From for generated::ConfirmedTransaction { + fn from(value: TransactionWithMetadata) -> Self { Self { transaction: Some(value.transaction.into()), - meta, + meta: Some(value.meta.into()), } } } -impl TryFrom for TransactionWithStatusMeta { +impl TryFrom for TransactionWithOptionalMetadata { type Error = bincode::Error; fn try_from(value: generated::ConfirmedTransaction) -> std::result::Result { let meta = value.meta.map(|meta| meta.try_into()).transpose()?; diff --git a/transaction-status/src/lib.rs b/transaction-status/src/lib.rs index 77e5aea85a..d06b9d3206 100644 --- a/transaction-status/src/lib.rs +++ b/transaction-status/src/lib.rs @@ -355,19 +355,43 @@ pub struct Reward { pub type Rewards = Vec; -#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[derive(Clone, Debug, PartialEq)] pub struct ConfirmedBlock { pub previous_blockhash: String, pub blockhash: String, pub parent_slot: Slot, - pub transactions: Vec, + pub transactions: Vec, pub rewards: Rewards, pub block_time: Option, pub block_height: Option, } -impl ConfirmedBlock { +#[derive(Clone, Debug, PartialEq)] +pub struct ConfirmedBlockWithOptionalMetadata { + pub previous_blockhash: String, + pub blockhash: String, + pub parent_slot: Slot, + pub transactions: Vec, + pub rewards: Rewards, + pub block_time: Option, + pub block_height: Option, +} + +impl From for ConfirmedBlockWithOptionalMetadata { + fn from(block: ConfirmedBlock) -> Self { + Self { + previous_blockhash: block.previous_blockhash, + blockhash: block.blockhash, + parent_slot: block.parent_slot, + transactions: block.transactions.into_iter().map(Into::into).collect(), + rewards: block.rewards, + block_time: block.block_time, + block_height: block.block_height, + } + } +} + +impl ConfirmedBlockWithOptionalMetadata { pub fn encode(self, encoding: UiTransactionEncoding) -> EncodedConfirmedBlock { EncodedConfirmedBlock { previous_blockhash: self.previous_blockhash, @@ -499,16 +523,31 @@ impl Default for TransactionDetails { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Clone, PartialEq)] pub struct ConfirmedTransaction { pub slot: Slot, - #[serde(flatten)] - pub transaction: TransactionWithStatusMeta, + pub transaction: TransactionWithMetadata, pub block_time: Option, } -impl ConfirmedTransaction { +#[derive(Debug, Clone, PartialEq)] +pub struct ConfirmedTransactionWithOptionalMetadata { + pub slot: Slot, + pub transaction: TransactionWithOptionalMetadata, + pub block_time: Option, +} + +impl From for ConfirmedTransactionWithOptionalMetadata { + fn from(confirmed_tx: ConfirmedTransaction) -> Self { + Self { + slot: confirmed_tx.slot, + transaction: confirmed_tx.transaction.into(), + block_time: confirmed_tx.block_time, + } + } +} + +impl ConfirmedTransactionWithOptionalMetadata { pub fn encode(self, encoding: UiTransactionEncoding) -> EncodedConfirmedTransaction { EncodedConfirmedTransaction { slot: self.slot, @@ -561,14 +600,28 @@ pub struct UiParsedMessage { pub instructions: Vec, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TransactionWithStatusMeta { +#[derive(Clone, Debug, PartialEq)] +pub struct TransactionWithMetadata { + pub transaction: Transaction, + pub meta: TransactionStatusMeta, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct TransactionWithOptionalMetadata { pub transaction: Transaction, pub meta: Option, } -impl TransactionWithStatusMeta { +impl From for TransactionWithOptionalMetadata { + fn from(tx_with_meta: TransactionWithMetadata) -> Self { + Self { + transaction: tx_with_meta.transaction, + meta: Some(tx_with_meta.meta), + } + } +} + +impl TransactionWithOptionalMetadata { fn encode(self, encoding: UiTransactionEncoding) -> EncodedTransactionWithStatusMeta { let message = self.transaction.message(); let meta = self.meta.map(|meta| meta.encode(encoding, message));