Enforce tx metadata upload with static types (#23028)
This commit is contained in:
@@ -10,7 +10,7 @@ use {
|
|||||||
RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter,
|
RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter,
|
||||||
RpcProgramAccountsConfig,
|
RpcProgramAccountsConfig,
|
||||||
},
|
},
|
||||||
rpc_response::{RpcBlockUpdate, SlotInfo},
|
rpc_response::SlotInfo,
|
||||||
},
|
},
|
||||||
solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path},
|
solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path},
|
||||||
solana_rpc::{
|
solana_rpc::{
|
||||||
@@ -36,7 +36,7 @@ use {
|
|||||||
},
|
},
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::socket::SocketAddrSpace,
|
||||||
solana_test_validator::TestValidator,
|
solana_test_validator::TestValidator,
|
||||||
solana_transaction_status::{TransactionDetails, UiTransactionEncoding},
|
solana_transaction_status::{ConfirmedBlock, TransactionDetails, UiTransactionEncoding},
|
||||||
std::{
|
std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
net::{IpAddr, SocketAddr},
|
net::{IpAddr, SocketAddr},
|
||||||
@@ -214,6 +214,7 @@ fn test_block_subscription() {
|
|||||||
..
|
..
|
||||||
} = create_genesis_config(10_000);
|
} = create_genesis_config(10_000);
|
||||||
let bank = Bank::new_for_tests(&genesis_config);
|
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 bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||||
|
|
||||||
// setup Blockstore
|
// setup Blockstore
|
||||||
@@ -227,6 +228,8 @@ fn test_block_subscription() {
|
|||||||
let keypair2 = Keypair::new();
|
let keypair2 = Keypair::new();
|
||||||
let keypair3 = Keypair::new();
|
let keypair3 = Keypair::new();
|
||||||
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
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(
|
let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore(
|
||||||
vec![&alice, &keypair1, &keypair2, &keypair3],
|
vec![&alice, &keypair1, &keypair2, &keypair3],
|
||||||
0,
|
0,
|
||||||
@@ -278,23 +281,15 @@ fn test_block_subscription() {
|
|||||||
match maybe_actual {
|
match maybe_actual {
|
||||||
Ok(actual) => {
|
Ok(actual) => {
|
||||||
let versioned_block = blockstore.get_complete_block(slot, false).unwrap();
|
let versioned_block = blockstore.get_complete_block(slot, false).unwrap();
|
||||||
let legacy_block = versioned_block.into_legacy_block().unwrap();
|
let legacy_block = ConfirmedBlock::from(versioned_block)
|
||||||
let block = legacy_block.clone().configure(
|
.into_legacy_block()
|
||||||
UiTransactionEncoding::Json,
|
.unwrap();
|
||||||
TransactionDetails::Signatures,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let expected = RpcBlockUpdate {
|
|
||||||
slot,
|
|
||||||
block: Some(block),
|
|
||||||
err: None,
|
|
||||||
};
|
|
||||||
let block = legacy_block.configure(
|
let block = legacy_block.configure(
|
||||||
UiTransactionEncoding::Json,
|
UiTransactionEncoding::Json,
|
||||||
TransactionDetails::Signatures,
|
TransactionDetails::Signatures,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
assert_eq!(actual.value.slot, expected.slot);
|
assert_eq!(actual.value.slot, slot);
|
||||||
assert!(block.eq(&actual.value.block.unwrap()));
|
assert!(block.eq(&actual.value.block.unwrap()));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@@ -2955,16 +2955,9 @@ mod tests {
|
|||||||
);
|
);
|
||||||
let ix_error_signature = ix_error_tx.signatures[0];
|
let ix_error_signature = ix_error_tx.signatures[0];
|
||||||
let entry_2 = next_entry(&entry_1.hash, 1, vec![ix_error_tx.clone()]);
|
let entry_2 = next_entry(&entry_1.hash, 1, vec![ix_error_tx.clone()]);
|
||||||
let fail_tx = system_transaction::transfer(
|
let entries = vec![entry_1, entry_2];
|
||||||
&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 transactions = sanitize_transactions(vec![success_tx, ix_error_tx, fail_tx]);
|
let transactions = sanitize_transactions(vec![success_tx, ix_error_tx]);
|
||||||
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair1.pubkey())
|
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair1.pubkey())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -3024,27 +3017,24 @@ mod tests {
|
|||||||
transaction_status_service.join().unwrap();
|
transaction_status_service.join().unwrap();
|
||||||
|
|
||||||
let confirmed_block = blockstore.get_rooted_block(bank.slot(), false).unwrap();
|
let confirmed_block = blockstore.get_rooted_block(bank.slot(), false).unwrap();
|
||||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
let actual_tx_results: Vec<_> = confirmed_block
|
||||||
|
.transactions
|
||||||
for VersionedTransactionWithStatusMeta { transaction, meta } in
|
.into_iter()
|
||||||
confirmed_block.transactions.into_iter()
|
.map(|VersionedTransactionWithStatusMeta { transaction, meta }| {
|
||||||
{
|
(transaction.signatures[0], meta.status)
|
||||||
if transaction.signatures[0] == success_signature {
|
})
|
||||||
let meta = meta.unwrap();
|
.collect();
|
||||||
assert_eq!(meta.status, Ok(()));
|
let expected_tx_results = vec![
|
||||||
} else if transaction.signatures[0] == ix_error_signature {
|
(success_signature, Ok(())),
|
||||||
let meta = meta.unwrap();
|
(
|
||||||
assert_eq!(
|
ix_error_signature,
|
||||||
meta.status,
|
Err(TransactionError::InstructionError(
|
||||||
Err(TransactionError::InstructionError(
|
0,
|
||||||
0,
|
InstructionError::Custom(1),
|
||||||
InstructionError::Custom(1)
|
)),
|
||||||
))
|
),
|
||||||
);
|
];
|
||||||
} else {
|
assert_eq!(actual_tx_results, expected_tx_results);
|
||||||
assert_eq!(meta, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
poh_recorder
|
poh_recorder
|
||||||
.lock()
|
.lock()
|
||||||
@@ -3191,7 +3181,7 @@ mod tests {
|
|||||||
let recorded_meta = confirmed_block.transactions.pop().unwrap().meta;
|
let recorded_meta = confirmed_block.transactions.pop().unwrap().meta;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
recorded_meta,
|
recorded_meta,
|
||||||
Some(TransactionStatusMeta {
|
TransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
pre_balances: vec![1, 0, 0],
|
pre_balances: vec![1, 0, 0],
|
||||||
post_balances: vec![1, 0, 0],
|
post_balances: vec![1, 0, 0],
|
||||||
@@ -3200,7 +3190,7 @@ mod tests {
|
|||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: sanitized_tx.get_loaded_addresses(),
|
loaded_addresses: sanitized_tx.get_loaded_addresses(),
|
||||||
..TransactionStatusMeta::default()
|
..TransactionStatusMeta::default()
|
||||||
})
|
}
|
||||||
);
|
);
|
||||||
poh_recorder
|
poh_recorder
|
||||||
.lock()
|
.lock()
|
||||||
|
@@ -3984,36 +3984,35 @@ pub mod tests {
|
|||||||
let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1));
|
let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1));
|
||||||
let slot = bank1.slot();
|
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],
|
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
|
||||||
bank0.slot(),
|
bank0.slot(),
|
||||||
bank1,
|
bank1,
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
Arc::new(AtomicU64::default()),
|
Arc::new(AtomicU64::default()),
|
||||||
);
|
)
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
let confirmed_block = blockstore.get_rooted_block(slot, false).unwrap();
|
let confirmed_block = blockstore.get_rooted_block(slot, false).unwrap();
|
||||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
let actual_tx_results: Vec<_> = confirmed_block
|
||||||
|
.transactions
|
||||||
for VersionedTransactionWithStatusMeta { transaction, meta } in
|
.into_iter()
|
||||||
confirmed_block.transactions.into_iter()
|
.map(|VersionedTransactionWithStatusMeta { transaction, meta }| {
|
||||||
{
|
(transaction.signatures[0], meta.status)
|
||||||
if transaction.signatures[0] == signatures[0] {
|
})
|
||||||
let meta = meta.unwrap();
|
.collect();
|
||||||
assert_eq!(meta.status, Ok(()));
|
let expected_tx_results = vec![
|
||||||
} else if transaction.signatures[0] == signatures[1] {
|
(test_signatures_iter.next().unwrap(), Ok(())),
|
||||||
let meta = meta.unwrap();
|
(
|
||||||
assert_eq!(
|
test_signatures_iter.next().unwrap(),
|
||||||
meta.status,
|
Err(TransactionError::InstructionError(
|
||||||
Err(TransactionError::InstructionError(
|
0,
|
||||||
0,
|
InstructionError::Custom(1),
|
||||||
InstructionError::Custom(1)
|
)),
|
||||||
))
|
),
|
||||||
);
|
];
|
||||||
} else {
|
assert_eq!(actual_tx_results, expected_tx_results);
|
||||||
assert_eq!(meta, None);
|
assert!(test_signatures_iter.next().is_none());
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Blockstore::destroy(&ledger_path).unwrap();
|
Blockstore::destroy(&ledger_path).unwrap();
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@ use {
|
|||||||
},
|
},
|
||||||
solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType},
|
solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType},
|
||||||
solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature},
|
solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature},
|
||||||
solana_transaction_status::{ConfirmedBlock, Encodable, UiTransactionEncoding},
|
solana_transaction_status::{Encodable, LegacyConfirmedBlock, UiTransactionEncoding},
|
||||||
std::{
|
std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
path::Path,
|
path::Path,
|
||||||
@@ -30,7 +30,6 @@ async fn upload(
|
|||||||
blockstore: Blockstore,
|
blockstore: Blockstore,
|
||||||
starting_slot: Slot,
|
starting_slot: Slot,
|
||||||
ending_slot: Option<Slot>,
|
ending_slot: Option<Slot>,
|
||||||
allow_missing_metadata: bool,
|
|
||||||
force_reupload: bool,
|
force_reupload: bool,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let bigtable = solana_storage_bigtable::LedgerStorage::new(false, None, None)
|
let bigtable = solana_storage_bigtable::LedgerStorage::new(false, None, None)
|
||||||
@@ -42,7 +41,6 @@ async fn upload(
|
|||||||
bigtable,
|
bigtable,
|
||||||
starting_slot,
|
starting_slot,
|
||||||
ending_slot,
|
ending_slot,
|
||||||
allow_missing_metadata,
|
|
||||||
force_reupload,
|
force_reupload,
|
||||||
Arc::new(AtomicBool::new(false)),
|
Arc::new(AtomicBool::new(false)),
|
||||||
)
|
)
|
||||||
@@ -73,13 +71,13 @@ async fn block(slot: Slot, output_format: OutputFormat) -> Result<(), Box<dyn st
|
|||||||
.await
|
.await
|
||||||
.map_err(|err| format!("Failed to connect to storage: {:?}", err))?;
|
.map_err(|err| format!("Failed to connect to storage: {:?}", err))?;
|
||||||
|
|
||||||
let versioned_block = bigtable.get_confirmed_block(slot).await?;
|
let confirmed_block = bigtable.get_confirmed_block(slot).await?;
|
||||||
let block = versioned_block
|
let legacy_block = confirmed_block
|
||||||
.into_legacy_block()
|
.into_legacy_block()
|
||||||
.ok_or_else(|| "Failed to read versioned transaction in block".to_string())?;
|
.ok_or_else(|| "Failed to read versioned transaction in block".to_string())?;
|
||||||
|
|
||||||
let cli_block = CliBlock {
|
let cli_block = CliBlock {
|
||||||
encoded_confirmed_block: block.encode(UiTransactionEncoding::Base64),
|
encoded_confirmed_block: legacy_block.encode(UiTransactionEncoding::Base64),
|
||||||
slot,
|
slot,
|
||||||
};
|
};
|
||||||
println!("{}", output_format.formatted_string(&cli_block));
|
println!("{}", output_format.formatted_string(&cli_block));
|
||||||
@@ -156,20 +154,20 @@ async fn confirm(
|
|||||||
let mut get_transaction_error = None;
|
let mut get_transaction_error = None;
|
||||||
if verbose {
|
if verbose {
|
||||||
match bigtable.get_confirmed_transaction(signature).await {
|
match bigtable.get_confirmed_transaction(signature).await {
|
||||||
Ok(Some(versioned_confirmed_tx)) => {
|
Ok(Some(confirmed_tx)) => {
|
||||||
let confirmed_transaction = versioned_confirmed_tx
|
let legacy_confirmed_tx = confirmed_tx
|
||||||
.into_legacy_confirmed_transaction()
|
.into_legacy_confirmed_transaction()
|
||||||
.ok_or_else(|| "Failed to read versioned transaction in block".to_string())?;
|
.ok_or_else(|| "Failed to read versioned transaction in block".to_string())?;
|
||||||
|
|
||||||
transaction = Some(CliTransaction {
|
transaction = Some(CliTransaction {
|
||||||
transaction: confirmed_transaction
|
transaction: legacy_confirmed_tx
|
||||||
.transaction
|
.tx_with_meta
|
||||||
.transaction
|
.transaction
|
||||||
.encode(UiTransactionEncoding::Json),
|
.encode(UiTransactionEncoding::Json),
|
||||||
meta: confirmed_transaction.transaction.meta.map(|m| m.into()),
|
meta: legacy_confirmed_tx.tx_with_meta.meta.map(|m| m.into()),
|
||||||
block_time: confirmed_transaction.block_time,
|
block_time: legacy_confirmed_tx.block_time,
|
||||||
slot: Some(confirmed_transaction.slot),
|
slot: Some(legacy_confirmed_tx.slot),
|
||||||
decoded_transaction: confirmed_transaction.transaction.transaction,
|
decoded_transaction: legacy_confirmed_tx.tx_with_meta.transaction,
|
||||||
prefix: " ".to_string(),
|
prefix: " ".to_string(),
|
||||||
sigverify_status: vec![],
|
sigverify_status: vec![],
|
||||||
});
|
});
|
||||||
@@ -201,7 +199,7 @@ pub async fn transaction_history(
|
|||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let bigtable = solana_storage_bigtable::LedgerStorage::new(true, None, None).await?;
|
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, LegacyConfirmedBlock)> = None;
|
||||||
while limit > 0 {
|
while limit > 0 {
|
||||||
let results = bigtable
|
let results = bigtable
|
||||||
.get_confirmed_signatures_for_address(
|
.get_confirmed_signatures_for_address(
|
||||||
@@ -267,8 +265,8 @@ pub async fn transaction_history(
|
|||||||
println!(" Unable to get confirmed transaction details: {}", err);
|
println!(" Unable to get confirmed transaction details: {}", err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(versioned_block) => {
|
Ok(confirmed_block) => {
|
||||||
let block = versioned_block.into_legacy_block().ok_or_else(|| {
|
let block = confirmed_block.into_legacy_block().ok_or_else(|| {
|
||||||
"Failed to read versioned transaction in block".to_string()
|
"Failed to read versioned transaction in block".to_string()
|
||||||
})?;
|
})?;
|
||||||
loaded_block = Some((result.slot, block));
|
loaded_block = Some((result.slot, block));
|
||||||
@@ -316,12 +314,6 @@ impl BigTableSubCommand for App<'_, '_> {
|
|||||||
.index(2)
|
.index(2)
|
||||||
.help("Stop uploading at this slot [default: last available slot]"),
|
.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(
|
||||||
Arg::with_name("force_reupload")
|
Arg::with_name("force_reupload")
|
||||||
.long("force")
|
.long("force")
|
||||||
@@ -516,7 +508,6 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
|||||||
("upload", Some(arg_matches)) => {
|
("upload", Some(arg_matches)) => {
|
||||||
let starting_slot = value_t!(arg_matches, "starting_slot", Slot).unwrap_or(0);
|
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 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 force_reupload = arg_matches.is_present("force_reupload");
|
||||||
let blockstore = crate::open_blockstore(
|
let blockstore = crate::open_blockstore(
|
||||||
&canonicalize_ledger_path(ledger_path),
|
&canonicalize_ledger_path(ledger_path),
|
||||||
@@ -528,7 +519,6 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
|||||||
blockstore,
|
blockstore,
|
||||||
starting_slot,
|
starting_slot,
|
||||||
ending_slot,
|
ending_slot,
|
||||||
allow_missing_metadata,
|
|
||||||
force_reupload,
|
force_reupload,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,6 @@ pub async fn upload_confirmed_blocks(
|
|||||||
bigtable: solana_storage_bigtable::LedgerStorage,
|
bigtable: solana_storage_bigtable::LedgerStorage,
|
||||||
starting_slot: Slot,
|
starting_slot: Slot,
|
||||||
ending_slot: Option<Slot>,
|
ending_slot: Option<Slot>,
|
||||||
allow_missing_metadata: bool,
|
|
||||||
force_reupload: bool,
|
force_reupload: bool,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
@@ -187,20 +186,7 @@ pub async fn upload_confirmed_blocks(
|
|||||||
num_blocks -= 1;
|
num_blocks -= 1;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Some(confirmed_block) => {
|
Some(confirmed_block) => Some(bigtable.upload_confirmed_block(slot, 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))
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for result in futures::future::join_all(uploads).await {
|
for result in futures::future::join_all(uploads).await {
|
||||||
|
@@ -72,7 +72,6 @@ impl BigTableUploadService {
|
|||||||
bigtable_ledger_storage.clone(),
|
bigtable_ledger_storage.clone(),
|
||||||
start_slot,
|
start_slot,
|
||||||
Some(end_slot),
|
Some(end_slot),
|
||||||
true,
|
|
||||||
false,
|
false,
|
||||||
exit.clone(),
|
exit.clone(),
|
||||||
));
|
));
|
||||||
|
@@ -42,8 +42,8 @@ use {
|
|||||||
},
|
},
|
||||||
solana_storage_proto::{StoredExtendedRewards, StoredTransactionStatusMeta},
|
solana_storage_proto::{StoredExtendedRewards, StoredTransactionStatusMeta},
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
ConfirmedTransactionStatusWithSignature, Rewards, TransactionStatusMeta,
|
ConfirmedTransactionStatusWithSignature, ConfirmedTransactionWithStatusMeta, Rewards,
|
||||||
VersionedConfirmedBlock, VersionedConfirmedTransactionWithStatusMeta,
|
TransactionStatusMeta, TransactionWithStatusMeta, VersionedConfirmedBlock,
|
||||||
VersionedTransactionWithStatusMeta,
|
VersionedTransactionWithStatusMeta,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
@@ -2043,9 +2043,8 @@ impl Blockstore {
|
|||||||
Ok(VersionedTransactionWithStatusMeta {
|
Ok(VersionedTransactionWithStatusMeta {
|
||||||
transaction,
|
transaction,
|
||||||
meta: self
|
meta: self
|
||||||
.read_transaction_status((signature, slot))
|
.read_transaction_status((signature, slot))?
|
||||||
.ok()
|
.ok_or(BlockstoreError::MissingTransactionMetadata)?,
|
||||||
.flatten(),
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@@ -2294,7 +2293,7 @@ impl Blockstore {
|
|||||||
pub fn get_rooted_transaction(
|
pub fn get_rooted_transaction(
|
||||||
&self,
|
&self,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
) -> Result<Option<VersionedConfirmedTransactionWithStatusMeta>> {
|
) -> Result<Option<ConfirmedTransactionWithStatusMeta>> {
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
"blockstore-rpc-api",
|
"blockstore-rpc-api",
|
||||||
("method", "get_rooted_transaction", String)
|
("method", "get_rooted_transaction", String)
|
||||||
@@ -2307,7 +2306,7 @@ impl Blockstore {
|
|||||||
&self,
|
&self,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
highest_confirmed_slot: Slot,
|
highest_confirmed_slot: Slot,
|
||||||
) -> Result<Option<VersionedConfirmedTransactionWithStatusMeta>> {
|
) -> Result<Option<ConfirmedTransactionWithStatusMeta>> {
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
"blockstore-rpc-api",
|
"blockstore-rpc-api",
|
||||||
("method", "get_complete_transaction", String)
|
("method", "get_complete_transaction", String)
|
||||||
@@ -2324,8 +2323,8 @@ impl Blockstore {
|
|||||||
&self,
|
&self,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
confirmed_unrooted_slots: &[Slot],
|
confirmed_unrooted_slots: &[Slot],
|
||||||
) -> Result<Option<VersionedConfirmedTransactionWithStatusMeta>> {
|
) -> Result<Option<ConfirmedTransactionWithStatusMeta>> {
|
||||||
if let Some((slot, status)) =
|
if let Some((slot, meta)) =
|
||||||
self.get_transaction_status(signature, confirmed_unrooted_slots)?
|
self.get_transaction_status(signature, confirmed_unrooted_slots)?
|
||||||
{
|
{
|
||||||
let transaction = self
|
let transaction = self
|
||||||
@@ -2333,12 +2332,11 @@ impl Blockstore {
|
|||||||
.ok_or(BlockstoreError::TransactionStatusSlotMismatch)?; // Should not happen
|
.ok_or(BlockstoreError::TransactionStatusSlotMismatch)?; // Should not happen
|
||||||
|
|
||||||
let block_time = self.get_block_time(slot)?;
|
let block_time = self.get_block_time(slot)?;
|
||||||
Ok(Some(VersionedConfirmedTransactionWithStatusMeta {
|
Ok(Some(ConfirmedTransactionWithStatusMeta {
|
||||||
slot,
|
slot,
|
||||||
tx_with_meta: VersionedTransactionWithStatusMeta {
|
tx_with_meta: TransactionWithStatusMeta::Complete(
|
||||||
transaction,
|
VersionedTransactionWithStatusMeta { transaction, meta },
|
||||||
meta: Some(status),
|
),
|
||||||
},
|
|
||||||
block_time,
|
block_time,
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
@@ -6327,7 +6325,7 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
VersionedTransactionWithStatusMeta {
|
VersionedTransactionWithStatusMeta {
|
||||||
transaction,
|
transaction,
|
||||||
meta: Some(TransactionStatusMeta {
|
meta: TransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances,
|
pre_balances,
|
||||||
@@ -6338,21 +6336,22 @@ pub mod tests {
|
|||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
}),
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Even if marked as root, a slot that is empty of entries should return an error
|
// 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!(
|
||||||
assert_matches!(confirmed_block_err, BlockstoreError::SlotUnavailable);
|
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,
|
// 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.
|
// 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!(
|
assert_matches!(
|
||||||
confirmed_block_err,
|
blockstore.get_rooted_block(slot, true),
|
||||||
BlockstoreError::ParentEntriesUnavailable
|
Err(BlockstoreError::ParentEntriesUnavailable)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test if require_previous_blockhash is false
|
// Test if require_previous_blockhash is false
|
||||||
@@ -7168,7 +7167,7 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
VersionedTransactionWithStatusMeta {
|
VersionedTransactionWithStatusMeta {
|
||||||
transaction,
|
transaction,
|
||||||
meta: Some(TransactionStatusMeta {
|
meta: TransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances,
|
pre_balances,
|
||||||
@@ -7179,7 +7178,7 @@ pub mod tests {
|
|||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
}),
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@@ -7188,9 +7187,9 @@ pub mod tests {
|
|||||||
let signature = tx_with_meta.transaction.signatures[0];
|
let signature = tx_with_meta.transaction.signatures[0];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blockstore.get_rooted_transaction(signature).unwrap(),
|
blockstore.get_rooted_transaction(signature).unwrap(),
|
||||||
Some(VersionedConfirmedTransactionWithStatusMeta {
|
Some(ConfirmedTransactionWithStatusMeta {
|
||||||
slot,
|
slot,
|
||||||
tx_with_meta: tx_with_meta.clone(),
|
tx_with_meta: TransactionWithStatusMeta::Complete(tx_with_meta.clone()),
|
||||||
block_time: None
|
block_time: None
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -7198,9 +7197,9 @@ pub mod tests {
|
|||||||
blockstore
|
blockstore
|
||||||
.get_complete_transaction(signature, slot + 1)
|
.get_complete_transaction(signature, slot + 1)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Some(VersionedConfirmedTransactionWithStatusMeta {
|
Some(ConfirmedTransactionWithStatusMeta {
|
||||||
slot,
|
slot,
|
||||||
tx_with_meta,
|
tx_with_meta: TransactionWithStatusMeta::Complete(tx_with_meta),
|
||||||
block_time: None
|
block_time: None
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -7270,7 +7269,7 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
VersionedTransactionWithStatusMeta {
|
VersionedTransactionWithStatusMeta {
|
||||||
transaction,
|
transaction,
|
||||||
meta: Some(TransactionStatusMeta {
|
meta: TransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 42,
|
fee: 42,
|
||||||
pre_balances,
|
pre_balances,
|
||||||
@@ -7281,7 +7280,7 @@ pub mod tests {
|
|||||||
post_token_balances,
|
post_token_balances,
|
||||||
rewards,
|
rewards,
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
}),
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@@ -7292,9 +7291,9 @@ pub mod tests {
|
|||||||
blockstore
|
blockstore
|
||||||
.get_complete_transaction(signature, slot)
|
.get_complete_transaction(signature, slot)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Some(VersionedConfirmedTransactionWithStatusMeta {
|
Some(ConfirmedTransactionWithStatusMeta {
|
||||||
slot,
|
slot,
|
||||||
tx_with_meta,
|
tx_with_meta: TransactionWithStatusMeta::Complete(tx_with_meta),
|
||||||
block_time: None
|
block_time: None
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -8052,6 +8051,16 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
transactions.push(transaction.into());
|
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
|
// Push transaction that will not have matching status, as a test case
|
||||||
transactions.push(
|
transactions.push(
|
||||||
Transaction::new_with_compiled_instructions(
|
Transaction::new_with_compiled_instructions(
|
||||||
@@ -8064,14 +8073,9 @@ pub mod tests {
|
|||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let map_result = blockstore.map_transactions_to_statuses(slot, transactions.into_iter());
|
let map_result =
|
||||||
assert!(map_result.is_ok());
|
blockstore.map_transactions_to_statuses(slot, transactions.clone().into_iter());
|
||||||
let map = map_result.unwrap();
|
assert_matches!(map_result, Err(BlockstoreError::MissingTransactionMetadata));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@@ -102,6 +102,7 @@ pub enum BlockstoreError {
|
|||||||
ParentEntriesUnavailable,
|
ParentEntriesUnavailable,
|
||||||
SlotUnavailable,
|
SlotUnavailable,
|
||||||
UnsupportedTransactionVersion,
|
UnsupportedTransactionVersion,
|
||||||
|
MissingTransactionMetadata,
|
||||||
}
|
}
|
||||||
pub type Result<T> = std::result::Result<T, BlockstoreError>;
|
pub type Result<T> = std::result::Result<T, BlockstoreError>;
|
||||||
|
|
||||||
|
@@ -878,46 +878,27 @@ fn find_latest_replayed_slot_from_ledger(
|
|||||||
latest_slot = new_latest_slot;
|
latest_slot = new_latest_slot;
|
||||||
info!("Checking latest_slot {}", latest_slot);
|
info!("Checking latest_slot {}", latest_slot);
|
||||||
// Wait for the slot to be fully received by the validator
|
// Wait for the slot to be fully received by the validator
|
||||||
let entries;
|
|
||||||
loop {
|
loop {
|
||||||
info!("Waiting for slot {} to be full", latest_slot);
|
info!("Waiting for slot {} to be full", latest_slot);
|
||||||
if blockstore.is_full(latest_slot) {
|
if blockstore.is_full(latest_slot) {
|
||||||
entries = blockstore.get_slot_entries(latest_slot, 0).unwrap();
|
|
||||||
assert!(!entries.is_empty());
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
sleep(Duration::from_millis(50));
|
sleep(Duration::from_millis(50));
|
||||||
blockstore = open_blockstore(ledger_path);
|
blockstore = open_blockstore(ledger_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check the slot has been replayed
|
// Wait for the slot to be replayed
|
||||||
let non_tick_entry = entries.into_iter().find(|e| !e.transactions.is_empty());
|
loop {
|
||||||
if let Some(non_tick_entry) = non_tick_entry {
|
info!("Waiting for slot {} to be replayed", latest_slot);
|
||||||
// Wait for the slot to be replayed
|
if blockstore.get_bank_hash(latest_slot).is_some() {
|
||||||
loop {
|
return (
|
||||||
info!("Waiting for slot {} to be replayed", latest_slot);
|
latest_slot,
|
||||||
if !blockstore
|
AncestorIterator::new(latest_slot, &blockstore).collect(),
|
||||||
.map_transactions_to_statuses(
|
);
|
||||||
latest_slot,
|
} else {
|
||||||
non_tick_entry.transactions.clone().into_iter(),
|
sleep(Duration::from_millis(50));
|
||||||
)
|
blockstore = open_blockstore(ledger_path);
|
||||||
.unwrap()
|
|
||||||
.is_empty()
|
|
||||||
{
|
|
||||||
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));
|
sleep(Duration::from_millis(50));
|
||||||
|
@@ -54,11 +54,11 @@ use solana_sdk::{
|
|||||||
system_instruction::{self, MAX_PERMITTED_DATA_LENGTH},
|
system_instruction::{self, MAX_PERMITTED_DATA_LENGTH},
|
||||||
system_program, sysvar,
|
system_program, sysvar,
|
||||||
sysvar::{clock, rent},
|
sysvar::{clock, rent},
|
||||||
transaction::{SanitizedTransaction, Transaction, TransactionError},
|
transaction::{SanitizedTransaction, Transaction, TransactionError, VersionedTransaction},
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
token_balances::collect_token_balances, ConfirmedTransactionWithStatusMeta, InnerInstructions,
|
token_balances::collect_token_balances, ConfirmedTransactionWithStatusMeta, InnerInstructions,
|
||||||
TransactionStatusMeta, TransactionWithStatusMeta,
|
TransactionStatusMeta, TransactionWithStatusMeta, VersionedTransactionWithStatusMeta,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, env, fs::File, io::Read, path::PathBuf, str::FromStr, sync::Arc};
|
use std::{collections::HashMap, env, fs::File, io::Read, path::PathBuf, str::FromStr, sync::Arc};
|
||||||
|
|
||||||
@@ -429,10 +429,12 @@ fn execute_transactions(
|
|||||||
|
|
||||||
Ok(ConfirmedTransactionWithStatusMeta {
|
Ok(ConfirmedTransactionWithStatusMeta {
|
||||||
slot: bank.slot(),
|
slot: bank.slot(),
|
||||||
transaction: TransactionWithStatusMeta {
|
tx_with_meta: TransactionWithStatusMeta::Complete(
|
||||||
transaction: tx.clone(),
|
VersionedTransactionWithStatusMeta {
|
||||||
meta: Some(tx_status_meta),
|
transaction: VersionedTransaction::from(tx.clone()),
|
||||||
},
|
meta: tx_status_meta,
|
||||||
|
},
|
||||||
|
),
|
||||||
block_time: None,
|
block_time: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -2476,10 +2478,10 @@ fn test_program_upgradeable_locks() {
|
|||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
results1[0],
|
results1[0],
|
||||||
Ok(ConfirmedTransactionWithStatusMeta {
|
Ok(ConfirmedTransactionWithStatusMeta {
|
||||||
transaction: TransactionWithStatusMeta {
|
tx_with_meta: TransactionWithStatusMeta::Complete(VersionedTransactionWithStatusMeta {
|
||||||
meta: Some(TransactionStatusMeta { status: Ok(()), .. }),
|
meta: TransactionStatusMeta { status: Ok(()), .. },
|
||||||
..
|
..
|
||||||
},
|
}),
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
));
|
));
|
||||||
@@ -2488,16 +2490,16 @@ fn test_program_upgradeable_locks() {
|
|||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
results2[0],
|
results2[0],
|
||||||
Ok(ConfirmedTransactionWithStatusMeta {
|
Ok(ConfirmedTransactionWithStatusMeta {
|
||||||
transaction: TransactionWithStatusMeta {
|
tx_with_meta: TransactionWithStatusMeta::Complete(VersionedTransactionWithStatusMeta {
|
||||||
meta: Some(TransactionStatusMeta {
|
meta: TransactionStatusMeta {
|
||||||
status: Err(TransactionError::InstructionError(
|
status: Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::ProgramFailedToComplete
|
InstructionError::ProgramFailedToComplete
|
||||||
)),
|
)),
|
||||||
..
|
..
|
||||||
}),
|
},
|
||||||
..
|
..
|
||||||
},
|
}),
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
));
|
));
|
||||||
|
153
rpc/src/rpc.rs
153
rpc/src/rpc.rs
@@ -80,10 +80,10 @@ use {
|
|||||||
solana_storage_bigtable::Error as StorageError,
|
solana_storage_bigtable::Error as StorageError,
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::socket::SocketAddrSpace,
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
ConfirmedTransactionStatusWithSignature, Encodable,
|
ConfirmedBlock, ConfirmedTransactionStatusWithSignature,
|
||||||
EncodedConfirmedTransactionWithStatusMeta, Reward, RewardType,
|
ConfirmedTransactionWithStatusMeta, Encodable, EncodedConfirmedTransactionWithStatusMeta,
|
||||||
TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, UiTransactionEncoding,
|
Reward, RewardType, TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock,
|
||||||
VersionedConfirmedBlock,
|
UiTransactionEncoding,
|
||||||
},
|
},
|
||||||
solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY},
|
solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY},
|
||||||
spl_token::{
|
spl_token::{
|
||||||
@@ -918,12 +918,8 @@ impl JsonRpcRequestProcessor {
|
|||||||
&self,
|
&self,
|
||||||
result: &std::result::Result<T, BlockstoreError>,
|
result: &std::result::Result<T, BlockstoreError>,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
) -> Result<()>
|
) -> Result<()> {
|
||||||
where
|
if let Err(err) = result {
|
||||||
T: std::fmt::Debug,
|
|
||||||
{
|
|
||||||
if result.is_err() {
|
|
||||||
let err = result.as_ref().unwrap_err();
|
|
||||||
debug!(
|
debug!(
|
||||||
"check_blockstore_root, slot: {:?}, max root: {:?}, err: {:?}",
|
"check_blockstore_root, slot: {:?}, max root: {:?}, err: {:?}",
|
||||||
slot,
|
slot,
|
||||||
@@ -944,21 +940,16 @@ impl JsonRpcRequestProcessor {
|
|||||||
&self,
|
&self,
|
||||||
result: &std::result::Result<T, BlockstoreError>,
|
result: &std::result::Result<T, BlockstoreError>,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
) -> Result<()>
|
) -> Result<()> {
|
||||||
where
|
if let Err(BlockstoreError::SlotCleanedUp) = result {
|
||||||
T: std::fmt::Debug,
|
return Err(RpcCustomError::BlockCleanedUp {
|
||||||
{
|
slot,
|
||||||
if result.is_err() {
|
first_available_block: self
|
||||||
if let BlockstoreError::SlotCleanedUp = result.as_ref().unwrap_err() {
|
.blockstore
|
||||||
return Err(RpcCustomError::BlockCleanedUp {
|
.get_first_available_block()
|
||||||
slot,
|
.unwrap_or_default(),
|
||||||
first_available_block: self
|
|
||||||
.blockstore
|
|
||||||
.get_first_available_block()
|
|
||||||
.unwrap_or_default(),
|
|
||||||
}
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -966,15 +957,9 @@ impl JsonRpcRequestProcessor {
|
|||||||
fn check_bigtable_result<T>(
|
fn check_bigtable_result<T>(
|
||||||
&self,
|
&self,
|
||||||
result: &std::result::Result<T, solana_storage_bigtable::Error>,
|
result: &std::result::Result<T, solana_storage_bigtable::Error>,
|
||||||
) -> Result<()>
|
) -> Result<()> {
|
||||||
where
|
if let Err(solana_storage_bigtable::Error::BlockNotFound(slot)) = result {
|
||||||
T: std::fmt::Debug,
|
return Err(RpcCustomError::LongTermStorageSlotSkipped { slot: *slot }.into());
|
||||||
{
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1017,12 +1002,12 @@ impl JsonRpcRequestProcessor {
|
|||||||
self.check_status_is_complete(slot)?;
|
self.check_status_is_complete(slot)?;
|
||||||
let result = self.blockstore.get_rooted_block(slot, true);
|
let result = self.blockstore.get_rooted_block(slot, true);
|
||||||
self.check_blockstore_root(&result, slot)?;
|
self.check_blockstore_root(&result, slot)?;
|
||||||
let configure_block = |versioned_block: VersionedConfirmedBlock| {
|
let configure_block = |confirmed_block: ConfirmedBlock| {
|
||||||
let confirmed_block = versioned_block
|
let legacy_block = confirmed_block
|
||||||
.into_legacy_block()
|
.into_legacy_block()
|
||||||
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
|
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
|
||||||
let mut confirmed_block =
|
let mut confirmed_block =
|
||||||
confirmed_block.configure(encoding, transaction_details, show_rewards);
|
legacy_block.configure(encoding, transaction_details, show_rewards);
|
||||||
if slot == 0 {
|
if slot == 0 {
|
||||||
confirmed_block.block_time = Some(self.genesis_creation_time());
|
confirmed_block.block_time = Some(self.genesis_creation_time());
|
||||||
confirmed_block.block_height = Some(0);
|
confirmed_block.block_height = Some(0);
|
||||||
@@ -1038,7 +1023,11 @@ impl JsonRpcRequestProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.check_slot_cleaned_up(&result, slot)?;
|
self.check_slot_cleaned_up(&result, slot)?;
|
||||||
return result.ok().map(configure_block).transpose();
|
return result
|
||||||
|
.ok()
|
||||||
|
.map(ConfirmedBlock::from)
|
||||||
|
.map(configure_block)
|
||||||
|
.transpose();
|
||||||
} else if commitment.is_confirmed() {
|
} else if commitment.is_confirmed() {
|
||||||
// Check if block is confirmed
|
// Check if block is confirmed
|
||||||
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
|
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
|
||||||
@@ -1047,30 +1036,28 @@ impl JsonRpcRequestProcessor {
|
|||||||
let result = self.blockstore.get_complete_block(slot, true);
|
let result = self.blockstore.get_complete_block(slot, true);
|
||||||
return result
|
return result
|
||||||
.ok()
|
.ok()
|
||||||
.map(|versioned_block| {
|
.map(ConfirmedBlock::from)
|
||||||
let mut confirmed_block = versioned_block
|
.map(|confirmed_block| -> Result<UiConfirmedBlock> {
|
||||||
|
let mut legacy_block = confirmed_block
|
||||||
.into_legacy_block()
|
.into_legacy_block()
|
||||||
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
|
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
|
||||||
if confirmed_block.block_time.is_none()
|
|
||||||
|| confirmed_block.block_height.is_none()
|
if legacy_block.block_time.is_none()
|
||||||
|
|| legacy_block.block_height.is_none()
|
||||||
{
|
{
|
||||||
let r_bank_forks = self.bank_forks.read().unwrap();
|
let r_bank_forks = self.bank_forks.read().unwrap();
|
||||||
let bank = r_bank_forks.get(slot).cloned();
|
let bank = r_bank_forks.get(slot).cloned();
|
||||||
if let Some(bank) = bank {
|
if let Some(bank) = bank {
|
||||||
if confirmed_block.block_time.is_none() {
|
if legacy_block.block_time.is_none() {
|
||||||
confirmed_block.block_time =
|
legacy_block.block_time = Some(bank.clock().unix_timestamp);
|
||||||
Some(bank.clock().unix_timestamp);
|
|
||||||
}
|
}
|
||||||
if confirmed_block.block_height.is_none() {
|
if legacy_block.block_height.is_none() {
|
||||||
confirmed_block.block_height = Some(bank.block_height());
|
legacy_block.block_height = Some(bank.block_height());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(confirmed_block.configure(
|
|
||||||
encoding,
|
Ok(legacy_block.configure(encoding, transaction_details, show_rewards))
|
||||||
transaction_details,
|
|
||||||
show_rewards,
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
.transpose();
|
.transpose();
|
||||||
}
|
}
|
||||||
@@ -1397,7 +1384,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
|
|
||||||
if self.config.enable_rpc_transaction_history {
|
if self.config.enable_rpc_transaction_history {
|
||||||
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
|
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
|
||||||
let versioned_confirmed_tx = if commitment.is_confirmed() {
|
let confirmed_transaction = if commitment.is_confirmed() {
|
||||||
let highest_confirmed_slot = confirmed_bank.slot();
|
let highest_confirmed_slot = confirmed_bank.slot();
|
||||||
self.blockstore
|
self.blockstore
|
||||||
.get_complete_transaction(signature, highest_confirmed_slot)
|
.get_complete_transaction(signature, highest_confirmed_slot)
|
||||||
@@ -1405,12 +1392,16 @@ impl JsonRpcRequestProcessor {
|
|||||||
self.blockstore.get_rooted_transaction(signature)
|
self.blockstore.get_rooted_transaction(signature)
|
||||||
};
|
};
|
||||||
|
|
||||||
match versioned_confirmed_tx.unwrap_or(None) {
|
let encode_transaction =
|
||||||
Some(versioned_confirmed_tx) => {
|
|confirmed_tx_with_meta: ConfirmedTransactionWithStatusMeta| -> Result<EncodedConfirmedTransactionWithStatusMeta> {
|
||||||
let mut confirmed_transaction = versioned_confirmed_tx
|
let legacy_tx_with_meta = confirmed_tx_with_meta.into_legacy_confirmed_transaction()
|
||||||
.into_legacy_confirmed_transaction()
|
|
||||||
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
|
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
|
||||||
|
|
||||||
|
Ok(legacy_tx_with_meta.encode(encoding))
|
||||||
|
};
|
||||||
|
|
||||||
|
match confirmed_transaction.unwrap_or(None) {
|
||||||
|
Some(mut confirmed_transaction) => {
|
||||||
if commitment.is_confirmed()
|
if commitment.is_confirmed()
|
||||||
&& confirmed_bank // should be redundant
|
&& confirmed_bank // should be redundant
|
||||||
.status_cache_ancestors()
|
.status_cache_ancestors()
|
||||||
@@ -1422,8 +1413,9 @@ impl JsonRpcRequestProcessor {
|
|||||||
.get(confirmed_transaction.slot)
|
.get(confirmed_transaction.slot)
|
||||||
.map(|bank| bank.clock().unix_timestamp);
|
.map(|bank| bank.clock().unix_timestamp);
|
||||||
}
|
}
|
||||||
return Ok(Some(confirmed_transaction.encode(encoding)));
|
return Ok(Some(encode_transaction(confirmed_transaction)?));
|
||||||
}
|
}
|
||||||
|
|
||||||
if confirmed_transaction.slot
|
if confirmed_transaction.slot
|
||||||
<= self
|
<= self
|
||||||
.block_commitment_cache
|
.block_commitment_cache
|
||||||
@@ -1431,7 +1423,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.highest_confirmed_root()
|
.highest_confirmed_root()
|
||||||
{
|
{
|
||||||
return Ok(Some(confirmed_transaction.encode(encoding)));
|
return Ok(Some(encode_transaction(confirmed_transaction)?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@@ -1440,13 +1432,7 @@ impl JsonRpcRequestProcessor {
|
|||||||
.get_confirmed_transaction(&signature)
|
.get_confirmed_transaction(&signature)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(None)
|
.unwrap_or(None)
|
||||||
.map(|versioned_confirmed_tx| {
|
.map(encode_transaction)
|
||||||
let confirmed_tx = versioned_confirmed_tx
|
|
||||||
.into_legacy_confirmed_transaction()
|
|
||||||
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
|
|
||||||
|
|
||||||
Ok(confirmed_tx.encode(encoding))
|
|
||||||
})
|
|
||||||
.transpose();
|
.transpose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4328,15 +4314,7 @@ pub fn create_test_transactions_and_populate_blockstore(
|
|||||||
);
|
);
|
||||||
let ix_error_signature = ix_error_tx.signatures[0];
|
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]);
|
let entry_2 = solana_entry::entry::next_entry(&entry_1.hash, 1, vec![ix_error_tx]);
|
||||||
// Failed transaction
|
let entries = vec![entry_1, entry_2];
|
||||||
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 shreds =
|
let shreds =
|
||||||
solana_ledger::blockstore::entries_to_test_shreds(&entries, slot, previous_slot, true, 0);
|
solana_ledger::blockstore::entries_to_test_shreds(&entries, slot, previous_slot, true, 0);
|
||||||
@@ -4357,17 +4335,20 @@ pub fn create_test_transactions_and_populate_blockstore(
|
|||||||
|
|
||||||
// Check that process_entries successfully writes can_commit transactions statuses, and
|
// Check that process_entries successfully writes can_commit transactions statuses, and
|
||||||
// that they are matched properly by get_rooted_block
|
// that they are matched properly by get_rooted_block
|
||||||
let _result = solana_ledger::blockstore_processor::process_entries_for_tests(
|
assert_eq!(
|
||||||
&bank,
|
solana_ledger::blockstore_processor::process_entries_for_tests(
|
||||||
entries,
|
&bank,
|
||||||
true,
|
entries,
|
||||||
Some(
|
true,
|
||||||
&solana_ledger::blockstore_processor::TransactionStatusSender {
|
Some(
|
||||||
sender: transaction_status_sender,
|
&solana_ledger::blockstore_processor::TransactionStatusSender {
|
||||||
enable_cpi_and_log_storage: false,
|
sender: transaction_status_sender,
|
||||||
},
|
enable_cpi_and_log_storage: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Some(&replay_vote_sender),
|
||||||
),
|
),
|
||||||
Some(&replay_vote_sender),
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
transaction_status_service.join().unwrap();
|
transaction_status_service.join().unwrap();
|
||||||
@@ -6613,7 +6594,7 @@ pub mod tests {
|
|||||||
let confirmed_block: Option<EncodedConfirmedBlock> =
|
let confirmed_block: Option<EncodedConfirmedBlock> =
|
||||||
serde_json::from_value(result["result"].clone()).unwrap();
|
serde_json::from_value(result["result"].clone()).unwrap();
|
||||||
let confirmed_block = confirmed_block.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![]);
|
assert_eq!(confirmed_block.rewards, vec![]);
|
||||||
|
|
||||||
for EncodedTransactionWithStatusMeta { transaction, meta } in
|
for EncodedTransactionWithStatusMeta { transaction, meta } in
|
||||||
@@ -6658,7 +6639,7 @@ pub mod tests {
|
|||||||
let confirmed_block: Option<EncodedConfirmedBlock> =
|
let confirmed_block: Option<EncodedConfirmedBlock> =
|
||||||
serde_json::from_value(result["result"].clone()).unwrap();
|
serde_json::from_value(result["result"].clone()).unwrap();
|
||||||
let confirmed_block = confirmed_block.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![]);
|
assert_eq!(confirmed_block.rewards, vec![]);
|
||||||
|
|
||||||
for EncodedTransactionWithStatusMeta { transaction, meta } in
|
for EncodedTransactionWithStatusMeta { transaction, meta } in
|
||||||
|
@@ -40,7 +40,7 @@ use {
|
|||||||
timing::timestamp,
|
timing::timestamp,
|
||||||
transaction,
|
transaction,
|
||||||
},
|
},
|
||||||
solana_transaction_status::ConfirmedBlock,
|
solana_transaction_status::{ConfirmedBlock, LegacyConfirmedBlock},
|
||||||
std::{
|
std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
@@ -278,30 +278,26 @@ impl RpcNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn filter_block_result_txs(
|
fn filter_block_result_txs(
|
||||||
block: ConfirmedBlock,
|
mut block: LegacyConfirmedBlock,
|
||||||
last_modified_slot: Slot,
|
last_modified_slot: Slot,
|
||||||
params: &BlockSubscriptionParams,
|
params: &BlockSubscriptionParams,
|
||||||
) -> Option<RpcBlockUpdate> {
|
) -> Option<RpcBlockUpdate> {
|
||||||
let transactions = match params.kind {
|
block.transactions = match params.kind {
|
||||||
BlockSubscriptionKind::All => block.transactions,
|
BlockSubscriptionKind::All => block.transactions,
|
||||||
BlockSubscriptionKind::MentionsAccountOrProgram(pk) => block
|
BlockSubscriptionKind::MentionsAccountOrProgram(pk) => block
|
||||||
.transactions
|
.transactions
|
||||||
.into_iter()
|
.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(),
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if transactions.is_empty() {
|
if block.transactions.is_empty() {
|
||||||
if let BlockSubscriptionKind::MentionsAccountOrProgram(_) = params.kind {
|
if let BlockSubscriptionKind::MentionsAccountOrProgram(_) = params.kind {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let block = ConfirmedBlock {
|
let block = block.configure(
|
||||||
transactions,
|
|
||||||
..block
|
|
||||||
}
|
|
||||||
.configure(
|
|
||||||
params.encoding,
|
params.encoding,
|
||||||
params.transaction_details,
|
params.transaction_details,
|
||||||
params.show_rewards,
|
params.show_rewards,
|
||||||
@@ -962,26 +958,29 @@ impl RpcSubscriptions {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let block_result = blockstore
|
let block_update_result = blockstore
|
||||||
.get_complete_block(s, false)
|
.get_complete_block(s, false)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("get_complete_block error: {}", e);
|
error!("get_complete_block error: {}", e);
|
||||||
RpcBlockUpdateError::BlockStoreError
|
RpcBlockUpdateError::BlockStoreError
|
||||||
})
|
})
|
||||||
.and_then(|versioned_block| {
|
.and_then(|versioned_block| {
|
||||||
versioned_block.into_legacy_block().ok_or(
|
ConfirmedBlock::from(versioned_block)
|
||||||
RpcBlockUpdateError::UnsupportedTransactionVersion,
|
.into_legacy_block()
|
||||||
)
|
.ok_or(
|
||||||
|
RpcBlockUpdateError::UnsupportedTransactionVersion,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
match block_result {
|
match block_update_result {
|
||||||
Ok(block) => {
|
Ok(block_update) => {
|
||||||
if let Some(res) = filter_block_result_txs(block, s, params)
|
if let Some(block_update) =
|
||||||
|
filter_block_result_txs(block_update, s, params)
|
||||||
{
|
{
|
||||||
notifier.notify(
|
notifier.notify(
|
||||||
Response {
|
Response {
|
||||||
context: RpcResponseContext { slot: s },
|
context: RpcResponseContext { slot: s },
|
||||||
value: res,
|
value: block_update,
|
||||||
},
|
},
|
||||||
subscription,
|
subscription,
|
||||||
false,
|
false,
|
||||||
@@ -1357,8 +1356,13 @@ pub(crate) mod tests {
|
|||||||
#[serial]
|
#[serial]
|
||||||
fn test_check_confirmed_block_subscribe() {
|
fn test_check_confirmed_block_subscribe() {
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
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 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 bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||||
let optimistically_confirmed_bank =
|
let optimistically_confirmed_bank =
|
||||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
||||||
@@ -1399,10 +1403,11 @@ pub(crate) mod tests {
|
|||||||
let keypair1 = Keypair::new();
|
let keypair1 = Keypair::new();
|
||||||
let keypair2 = Keypair::new();
|
let keypair2 = Keypair::new();
|
||||||
let keypair3 = Keypair::new();
|
let keypair3 = Keypair::new();
|
||||||
let keypair4 = Keypair::new();
|
|
||||||
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
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(
|
let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore(
|
||||||
vec![&keypair1, &keypair2, &keypair3, &keypair4],
|
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
|
||||||
0,
|
0,
|
||||||
bank,
|
bank,
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
@@ -1414,8 +1419,9 @@ pub(crate) mod tests {
|
|||||||
let actual_resp = receiver.recv();
|
let actual_resp = receiver.recv();
|
||||||
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
||||||
|
|
||||||
let versioned_block = blockstore.get_complete_block(slot, false).unwrap();
|
let confirmed_block =
|
||||||
let legacy_block = versioned_block.into_legacy_block().unwrap();
|
ConfirmedBlock::from(blockstore.get_complete_block(slot, false).unwrap());
|
||||||
|
let legacy_block = confirmed_block.into_legacy_block().unwrap();
|
||||||
let block = legacy_block.configure(params.encoding, params.transaction_details, false);
|
let block = legacy_block.configure(params.encoding, params.transaction_details, false);
|
||||||
let expected_resp = RpcBlockUpdate {
|
let expected_resp = RpcBlockUpdate {
|
||||||
slot,
|
slot,
|
||||||
@@ -1455,8 +1461,13 @@ pub(crate) mod tests {
|
|||||||
#[serial]
|
#[serial]
|
||||||
fn test_check_confirmed_block_subscribe_with_mentions() {
|
fn test_check_confirmed_block_subscribe_with_mentions() {
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
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 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 bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||||
let optimistically_confirmed_bank =
|
let optimistically_confirmed_bank =
|
||||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
||||||
@@ -1498,10 +1509,11 @@ pub(crate) mod tests {
|
|||||||
let bank = bank_forks.read().unwrap().working_bank();
|
let bank = bank_forks.read().unwrap().working_bank();
|
||||||
let keypair2 = Keypair::new();
|
let keypair2 = Keypair::new();
|
||||||
let keypair3 = Keypair::new();
|
let keypair3 = Keypair::new();
|
||||||
let keypair4 = Keypair::new();
|
|
||||||
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
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(
|
let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore(
|
||||||
vec![&keypair1, &keypair2, &keypair3, &keypair4],
|
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
|
||||||
0,
|
0,
|
||||||
bank,
|
bank,
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
@@ -1514,8 +1526,9 @@ pub(crate) mod tests {
|
|||||||
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
||||||
|
|
||||||
// make sure it filtered out the other keypairs
|
// make sure it filtered out the other keypairs
|
||||||
let versioned_block = blockstore.get_complete_block(slot, false).unwrap();
|
let confirmed_block =
|
||||||
let mut legacy_block = versioned_block.into_legacy_block().unwrap();
|
ConfirmedBlock::from(blockstore.get_complete_block(slot, false).unwrap());
|
||||||
|
let mut legacy_block = confirmed_block.into_legacy_block().unwrap();
|
||||||
legacy_block.transactions.retain(|tx_with_meta| {
|
legacy_block.transactions.retain(|tx_with_meta| {
|
||||||
tx_with_meta
|
tx_with_meta
|
||||||
.transaction
|
.transaction
|
||||||
@@ -1552,8 +1565,13 @@ pub(crate) mod tests {
|
|||||||
#[serial]
|
#[serial]
|
||||||
fn test_check_finalized_block_subscribe() {
|
fn test_check_finalized_block_subscribe() {
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
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 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 bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||||
let optimistically_confirmed_bank =
|
let optimistically_confirmed_bank =
|
||||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
||||||
@@ -1593,10 +1611,11 @@ pub(crate) mod tests {
|
|||||||
let keypair1 = Keypair::new();
|
let keypair1 = Keypair::new();
|
||||||
let keypair2 = Keypair::new();
|
let keypair2 = Keypair::new();
|
||||||
let keypair3 = Keypair::new();
|
let keypair3 = Keypair::new();
|
||||||
let keypair4 = Keypair::new();
|
|
||||||
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
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(
|
let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore(
|
||||||
vec![&keypair1, &keypair2, &keypair3, &keypair4],
|
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
|
||||||
0,
|
0,
|
||||||
bank,
|
bank,
|
||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
@@ -1613,8 +1632,9 @@ pub(crate) mod tests {
|
|||||||
let actual_resp = receiver.recv();
|
let actual_resp = receiver.recv();
|
||||||
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
||||||
|
|
||||||
let versioned_block = blockstore.get_complete_block(slot, false).unwrap();
|
let confirmed_block =
|
||||||
let legacy_block = versioned_block.into_legacy_block().unwrap();
|
ConfirmedBlock::from(blockstore.get_complete_block(slot, false).unwrap());
|
||||||
|
let legacy_block = confirmed_block.into_legacy_block().unwrap();
|
||||||
let block = legacy_block.configure(params.encoding, params.transaction_details, false);
|
let block = legacy_block.configure(params.encoding, params.transaction_details, false);
|
||||||
let expected_resp = RpcBlockUpdate {
|
let expected_resp = RpcBlockUpdate {
|
||||||
slot,
|
slot,
|
||||||
|
@@ -792,23 +792,46 @@ mod tests {
|
|||||||
prost::Message,
|
prost::Message,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
hash::Hash, message::v0::LoadedAddresses, signature::Keypair, system_transaction,
|
hash::Hash, message::v0::LoadedAddresses, signature::Keypair, system_transaction,
|
||||||
|
transaction::VersionedTransaction,
|
||||||
},
|
},
|
||||||
solana_storage_proto::convert::generated,
|
solana_storage_proto::convert::generated,
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
ConfirmedBlock, TransactionStatusMeta, TransactionWithStatusMeta,
|
ConfirmedBlock, TransactionStatusMeta, TransactionWithStatusMeta,
|
||||||
VersionedConfirmedBlock,
|
VersionedTransactionWithStatusMeta,
|
||||||
},
|
},
|
||||||
std::convert::TryInto,
|
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(|tx| tx.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]
|
#[test]
|
||||||
fn test_deserialize_protobuf_or_bincode_cell_data() {
|
fn test_deserialize_protobuf_or_bincode_cell_data() {
|
||||||
let from = Keypair::new();
|
let from = Keypair::new();
|
||||||
let recipient = solana_sdk::pubkey::new_rand();
|
let recipient = solana_sdk::pubkey::new_rand();
|
||||||
let transaction = system_transaction::transfer(&from, &recipient, 42, Hash::default());
|
let transaction = system_transaction::transfer(&from, &recipient, 42, Hash::default());
|
||||||
let with_meta = TransactionWithStatusMeta {
|
let with_meta = TransactionWithStatusMeta::Complete(VersionedTransactionWithStatusMeta {
|
||||||
transaction,
|
transaction: VersionedTransaction::from(transaction),
|
||||||
meta: Some(TransactionStatusMeta {
|
meta: TransactionStatusMeta {
|
||||||
status: Ok(()),
|
status: Ok(()),
|
||||||
fee: 1,
|
fee: 1,
|
||||||
pre_balances: vec![43, 0, 1],
|
pre_balances: vec![43, 0, 1],
|
||||||
@@ -819,9 +842,9 @@ mod tests {
|
|||||||
post_token_balances: Some(vec![]),
|
post_token_balances: Some(vec![]),
|
||||||
rewards: Some(vec![]),
|
rewards: Some(vec![]),
|
||||||
loaded_addresses: LoadedAddresses::default(),
|
loaded_addresses: LoadedAddresses::default(),
|
||||||
}),
|
},
|
||||||
};
|
});
|
||||||
let block = ConfirmedBlock {
|
let expected_block = ConfirmedBlock {
|
||||||
transactions: vec![with_meta],
|
transactions: vec![with_meta],
|
||||||
parent_slot: 1,
|
parent_slot: 1,
|
||||||
blockhash: Hash::default().to_string(),
|
blockhash: Hash::default().to_string(),
|
||||||
@@ -831,11 +854,11 @@ mod tests {
|
|||||||
block_height: Some(1),
|
block_height: Some(1),
|
||||||
};
|
};
|
||||||
let bincode_block = compress_best(
|
let bincode_block = compress_best(
|
||||||
&bincode::serialize::<StoredConfirmedBlock>(&block.clone().into()).unwrap(),
|
&bincode::serialize::<StoredConfirmedBlock>(&expected_block.clone().into()).unwrap(),
|
||||||
)
|
)
|
||||||
.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());
|
let mut buf = Vec::with_capacity(protobuf_block.encoded_len());
|
||||||
protobuf_block.encode(&mut buf).unwrap();
|
protobuf_block.encode(&mut buf).unwrap();
|
||||||
let protobuf_block = compress_best(&buf).unwrap();
|
let protobuf_block = compress_best(&buf).unwrap();
|
||||||
@@ -849,7 +872,6 @@ mod tests {
|
|||||||
"".to_string(),
|
"".to_string(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_block: VersionedConfirmedBlock = block.into();
|
|
||||||
if let CellData::Protobuf(protobuf_block) = deserialized {
|
if let CellData::Protobuf(protobuf_block) = deserialized {
|
||||||
assert_eq!(expected_block, protobuf_block.try_into().unwrap());
|
assert_eq!(expected_block, protobuf_block.try_into().unwrap());
|
||||||
} else {
|
} else {
|
||||||
@@ -867,7 +889,11 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
if let CellData::Bincode(bincode_block) = deserialized {
|
if let CellData::Bincode(bincode_block) = deserialized {
|
||||||
let mut block = expected_block;
|
let mut block = expected_block;
|
||||||
if let Some(meta) = &mut block.transactions[0].meta {
|
if let TransactionWithStatusMeta::Complete(VersionedTransactionWithStatusMeta {
|
||||||
|
meta,
|
||||||
|
..
|
||||||
|
}) = &mut block.transactions[0]
|
||||||
|
{
|
||||||
meta.inner_instructions = None; // Legacy bincode implementation does not support inner_instructions
|
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.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.pre_token_balances = None; // Legacy bincode implementation does not support token balances
|
||||||
|
@@ -14,10 +14,10 @@ use {
|
|||||||
},
|
},
|
||||||
solana_storage_proto::convert::{generated, tx_by_addr},
|
solana_storage_proto::convert::{generated, tx_by_addr},
|
||||||
solana_transaction_status::{
|
solana_transaction_status::{
|
||||||
extract_and_fmt_memos, ConfirmedBlock, ConfirmedTransactionStatusWithSignature, Reward,
|
extract_and_fmt_memos, ConfirmedBlock, ConfirmedTransactionStatusWithSignature,
|
||||||
TransactionByAddrInfo, TransactionConfirmationStatus, TransactionStatus,
|
ConfirmedTransactionWithStatusMeta, Reward, TransactionByAddrInfo,
|
||||||
TransactionStatusMeta, TransactionWithStatusMeta, VersionedConfirmedBlock,
|
TransactionConfirmationStatus, TransactionStatus, TransactionStatusMeta,
|
||||||
VersionedConfirmedTransactionWithStatusMeta, VersionedTransactionWithStatusMeta,
|
TransactionWithStatusMeta, VersionedConfirmedBlock, VersionedTransactionWithStatusMeta,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
@@ -115,6 +115,7 @@ struct StoredConfirmedBlock {
|
|||||||
block_height: Option<u64>,
|
block_height: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
impl From<ConfirmedBlock> for StoredConfirmedBlock {
|
impl From<ConfirmedBlock> for StoredConfirmedBlock {
|
||||||
fn from(confirmed_block: ConfirmedBlock) -> Self {
|
fn from(confirmed_block: ConfirmedBlock) -> Self {
|
||||||
let ConfirmedBlock {
|
let ConfirmedBlock {
|
||||||
@@ -139,7 +140,7 @@ impl From<ConfirmedBlock> for StoredConfirmedBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StoredConfirmedBlock> for VersionedConfirmedBlock {
|
impl From<StoredConfirmedBlock> for ConfirmedBlock {
|
||||||
fn from(confirmed_block: StoredConfirmedBlock) -> Self {
|
fn from(confirmed_block: StoredConfirmedBlock) -> Self {
|
||||||
let StoredConfirmedBlock {
|
let StoredConfirmedBlock {
|
||||||
previous_blockhash,
|
previous_blockhash,
|
||||||
@@ -169,20 +170,38 @@ struct StoredConfirmedBlockTransaction {
|
|||||||
meta: Option<StoredConfirmedBlockTransactionStatusMeta>,
|
meta: Option<StoredConfirmedBlockTransactionStatusMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
impl From<TransactionWithStatusMeta> for StoredConfirmedBlockTransaction {
|
impl From<TransactionWithStatusMeta> for StoredConfirmedBlockTransaction {
|
||||||
fn from(value: TransactionWithStatusMeta) -> Self {
|
fn from(value: TransactionWithStatusMeta) -> Self {
|
||||||
Self {
|
match value {
|
||||||
transaction: value.transaction.into(),
|
TransactionWithStatusMeta::MissingMetadata(transaction) => Self {
|
||||||
meta: value.meta.map(|meta| meta.into()),
|
transaction: VersionedTransaction::from(transaction),
|
||||||
|
meta: None,
|
||||||
|
},
|
||||||
|
TransactionWithStatusMeta::Complete(VersionedTransactionWithStatusMeta {
|
||||||
|
transaction,
|
||||||
|
meta,
|
||||||
|
}) => Self {
|
||||||
|
transaction,
|
||||||
|
meta: Some(meta.into()),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StoredConfirmedBlockTransaction> for VersionedTransactionWithStatusMeta {
|
impl From<StoredConfirmedBlockTransaction> for TransactionWithStatusMeta {
|
||||||
fn from(value: StoredConfirmedBlockTransaction) -> Self {
|
fn from(tx_with_meta: StoredConfirmedBlockTransaction) -> Self {
|
||||||
Self {
|
let StoredConfirmedBlockTransaction { transaction, meta } = tx_with_meta;
|
||||||
transaction: value.transaction,
|
match meta {
|
||||||
meta: value.meta.map(|meta| meta.into()),
|
None => Self::MissingMetadata(
|
||||||
|
transaction
|
||||||
|
.into_legacy_transaction()
|
||||||
|
.expect("versioned transactions always have meta"),
|
||||||
|
),
|
||||||
|
Some(meta) => Self::Complete(VersionedTransactionWithStatusMeta {
|
||||||
|
transaction,
|
||||||
|
meta: meta.into(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -394,7 +413,7 @@ impl LedgerStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch the confirmed block from the desired slot
|
/// Fetch the confirmed block from the desired slot
|
||||||
pub async fn get_confirmed_block(&self, slot: Slot) -> Result<VersionedConfirmedBlock> {
|
pub async fn get_confirmed_block(&self, slot: Slot) -> Result<ConfirmedBlock> {
|
||||||
debug!(
|
debug!(
|
||||||
"LedgerStorage::get_confirmed_block request received: {:?}",
|
"LedgerStorage::get_confirmed_block request received: {:?}",
|
||||||
slot
|
slot
|
||||||
@@ -440,7 +459,7 @@ impl LedgerStorage {
|
|||||||
pub async fn get_confirmed_transaction(
|
pub async fn get_confirmed_transaction(
|
||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
) -> Result<Option<VersionedConfirmedTransactionWithStatusMeta>> {
|
) -> Result<Option<ConfirmedTransactionWithStatusMeta>> {
|
||||||
debug!(
|
debug!(
|
||||||
"LedgerStorage::get_confirmed_transaction request received: {:?}",
|
"LedgerStorage::get_confirmed_transaction request received: {:?}",
|
||||||
signature
|
signature
|
||||||
@@ -465,17 +484,17 @@ impl LedgerStorage {
|
|||||||
warn!("Transaction info for {} is corrupt", signature);
|
warn!("Transaction info for {} is corrupt", signature);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
Some(bucket_block_transaction) => {
|
Some(tx_with_meta) => {
|
||||||
if bucket_block_transaction.transaction.signatures[0] != *signature {
|
if tx_with_meta.transaction_signature() != signature {
|
||||||
warn!(
|
warn!(
|
||||||
"Transaction info or confirmed block for {} is corrupt",
|
"Transaction info or confirmed block for {} is corrupt",
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(VersionedConfirmedTransactionWithStatusMeta {
|
Ok(Some(ConfirmedTransactionWithStatusMeta {
|
||||||
slot,
|
slot,
|
||||||
tx_with_meta: bucket_block_transaction,
|
tx_with_meta,
|
||||||
block_time: block.block_time,
|
block_time: block.block_time,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -638,7 +657,7 @@ impl LedgerStorage {
|
|||||||
let mut tx_cells = vec![];
|
let mut tx_cells = vec![];
|
||||||
for (index, transaction_with_meta) in confirmed_block.transactions.iter().enumerate() {
|
for (index, transaction_with_meta) in confirmed_block.transactions.iter().enumerate() {
|
||||||
let VersionedTransactionWithStatusMeta { meta, transaction } = transaction_with_meta;
|
let VersionedTransactionWithStatusMeta { meta, transaction } = transaction_with_meta;
|
||||||
let err = meta.as_ref().and_then(|meta| meta.status.clone().err());
|
let err = meta.status.clone().err();
|
||||||
let index = index as u32;
|
let index = index as u32;
|
||||||
let signature = transaction.signatures[0];
|
let signature = transaction.signatures[0];
|
||||||
let memo = extract_and_fmt_memos(transaction_with_meta);
|
let memo = extract_and_fmt_memos(transaction_with_meta);
|
||||||
@@ -725,21 +744,41 @@ impl LedgerStorage {
|
|||||||
let mut expected_tx_infos: HashMap<String, UploadedTransaction> = HashMap::new();
|
let mut expected_tx_infos: HashMap<String, UploadedTransaction> = HashMap::new();
|
||||||
let confirmed_block = self.get_confirmed_block(slot).await?;
|
let confirmed_block = self.get_confirmed_block(slot).await?;
|
||||||
for (index, transaction_with_meta) in confirmed_block.transactions.iter().enumerate() {
|
for (index, transaction_with_meta) in confirmed_block.transactions.iter().enumerate() {
|
||||||
let VersionedTransactionWithStatusMeta { transaction, meta } = transaction_with_meta;
|
match transaction_with_meta {
|
||||||
let signature = transaction.signatures[0];
|
TransactionWithStatusMeta::MissingMetadata(transaction) => {
|
||||||
let index = index as u32;
|
let signature = transaction.signatures[0];
|
||||||
let err = meta.as_ref().and_then(|meta| meta.status.clone().err());
|
let index = index as u32;
|
||||||
|
let err = None;
|
||||||
|
|
||||||
for address in transaction_with_meta.account_keys().iter() {
|
for address in transaction.message.account_keys.iter() {
|
||||||
if !is_sysvar_id(address) {
|
if !is_sysvar_id(address) {
|
||||||
addresses.insert(address);
|
addresses.insert(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_tx_infos.insert(
|
||||||
|
signature.to_string(),
|
||||||
|
UploadedTransaction { slot, index, err },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
TransactionWithStatusMeta::Complete(tx_with_meta) => {
|
||||||
|
let VersionedTransactionWithStatusMeta { transaction, meta } = tx_with_meta;
|
||||||
|
let signature = transaction.signatures[0];
|
||||||
|
let index = index as u32;
|
||||||
|
let err = meta.status.clone().err();
|
||||||
|
|
||||||
|
for address in tx_with_meta.account_keys().iter() {
|
||||||
|
if !is_sysvar_id(address) {
|
||||||
|
addresses.insert(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_tx_infos.insert(
|
||||||
|
signature.to_string(),
|
||||||
|
UploadedTransaction { slot, index, err },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expected_tx_infos.insert(
|
|
||||||
signature.to_string(),
|
|
||||||
UploadedTransaction { slot, index, err },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let address_slot_rows: Vec<_> = addresses
|
let address_slot_rows: Vec<_> = addresses
|
||||||
|
@@ -140,31 +140,7 @@ impl From<VersionedConfirmedBlock> for generated::ConfirmedBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ConfirmedBlock> for generated::ConfirmedBlock {
|
impl TryFrom<generated::ConfirmedBlock> for ConfirmedBlock {
|
||||||
fn from(confirmed_block: ConfirmedBlock) -> Self {
|
|
||||||
let ConfirmedBlock {
|
|
||||||
previous_blockhash,
|
|
||||||
blockhash,
|
|
||||||
parent_slot,
|
|
||||||
transactions,
|
|
||||||
rewards,
|
|
||||||
block_time,
|
|
||||||
block_height,
|
|
||||||
} = confirmed_block;
|
|
||||||
|
|
||||||
Self {
|
|
||||||
previous_blockhash,
|
|
||||||
blockhash,
|
|
||||||
parent_slot,
|
|
||||||
transactions: transactions.into_iter().map(|tx| tx.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 }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<generated::ConfirmedBlock> for VersionedConfirmedBlock {
|
|
||||||
type Error = bincode::Error;
|
type Error = bincode::Error;
|
||||||
fn try_from(
|
fn try_from(
|
||||||
confirmed_block: generated::ConfirmedBlock,
|
confirmed_block: generated::ConfirmedBlock,
|
||||||
@@ -195,32 +171,38 @@ impl TryFrom<generated::ConfirmedBlock> for VersionedConfirmedBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<TransactionWithStatusMeta> for generated::ConfirmedTransaction {
|
impl From<TransactionWithStatusMeta> for generated::ConfirmedTransaction {
|
||||||
fn from(value: TransactionWithStatusMeta) -> Self {
|
fn from(tx_with_meta: TransactionWithStatusMeta) -> Self {
|
||||||
let meta = value.meta.map(|meta| meta.into());
|
match tx_with_meta {
|
||||||
Self {
|
TransactionWithStatusMeta::MissingMetadata(transaction) => Self {
|
||||||
transaction: Some(value.transaction.into()),
|
transaction: Some(generated::Transaction::from(transaction)),
|
||||||
meta,
|
meta: None,
|
||||||
|
},
|
||||||
|
TransactionWithStatusMeta::Complete(tx_with_meta) => Self::from(tx_with_meta),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<VersionedTransactionWithStatusMeta> for generated::ConfirmedTransaction {
|
impl From<VersionedTransactionWithStatusMeta> for generated::ConfirmedTransaction {
|
||||||
fn from(value: VersionedTransactionWithStatusMeta) -> Self {
|
fn from(value: VersionedTransactionWithStatusMeta) -> Self {
|
||||||
let meta = value.meta.map(|meta| meta.into());
|
|
||||||
Self {
|
Self {
|
||||||
transaction: Some(value.transaction.into()),
|
transaction: Some(value.transaction.into()),
|
||||||
meta,
|
meta: Some(value.meta.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<generated::ConfirmedTransaction> for VersionedTransactionWithStatusMeta {
|
impl TryFrom<generated::ConfirmedTransaction> for TransactionWithStatusMeta {
|
||||||
type Error = bincode::Error;
|
type Error = bincode::Error;
|
||||||
fn try_from(value: generated::ConfirmedTransaction) -> std::result::Result<Self, Self::Error> {
|
fn try_from(value: generated::ConfirmedTransaction) -> std::result::Result<Self, Self::Error> {
|
||||||
let meta = value.meta.map(|meta| meta.try_into()).transpose()?;
|
let meta = value.meta.map(|meta| meta.try_into()).transpose()?;
|
||||||
Ok(Self {
|
let transaction = value.transaction.expect("transaction is required").into();
|
||||||
transaction: value.transaction.expect("transaction is required").into(),
|
Ok(match meta {
|
||||||
meta,
|
Some(meta) => Self::Complete(VersionedTransactionWithStatusMeta { transaction, meta }),
|
||||||
|
None => Self::MissingMetadata(
|
||||||
|
transaction
|
||||||
|
.into_legacy_transaction()
|
||||||
|
.expect("meta is required for versioned transactions"),
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -388,7 +388,7 @@ pub struct Reward {
|
|||||||
|
|
||||||
pub type Rewards = Vec<Reward>;
|
pub type Rewards = Vec<Reward>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct ConfirmedBlock {
|
pub struct ConfirmedBlock {
|
||||||
pub previous_blockhash: String,
|
pub previous_blockhash: String,
|
||||||
pub blockhash: String,
|
pub blockhash: String,
|
||||||
@@ -399,7 +399,9 @@ pub struct ConfirmedBlock {
|
|||||||
pub block_height: Option<u64>,
|
pub block_height: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
// Confirmed block with type guarantees that transaction metadata
|
||||||
|
// is always present. Used for uploading to BigTable.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct VersionedConfirmedBlock {
|
pub struct VersionedConfirmedBlock {
|
||||||
pub previous_blockhash: String,
|
pub previous_blockhash: String,
|
||||||
pub blockhash: String,
|
pub blockhash: String,
|
||||||
@@ -410,11 +412,23 @@ pub struct VersionedConfirmedBlock {
|
|||||||
pub block_height: Option<u64>,
|
pub block_height: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionedConfirmedBlock {
|
// Confirmed block which only supports legacy transactions. Used
|
||||||
|
// until migration to versioned transactions is completed.
|
||||||
|
pub struct LegacyConfirmedBlock {
|
||||||
|
pub previous_blockhash: String,
|
||||||
|
pub blockhash: String,
|
||||||
|
pub parent_slot: Slot,
|
||||||
|
pub transactions: Vec<LegacyTransactionWithStatusMeta>,
|
||||||
|
pub rewards: Rewards,
|
||||||
|
pub block_time: Option<UnixTimestamp>,
|
||||||
|
pub block_height: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfirmedBlock {
|
||||||
/// Downgrades a versioned block into a legacy block type
|
/// Downgrades a versioned block into a legacy block type
|
||||||
/// if it only contains legacy transactions
|
/// if it only contains legacy transactions
|
||||||
pub fn into_legacy_block(self) -> Option<ConfirmedBlock> {
|
pub fn into_legacy_block(self) -> Option<LegacyConfirmedBlock> {
|
||||||
Some(ConfirmedBlock {
|
Some(LegacyConfirmedBlock {
|
||||||
previous_blockhash: self.previous_blockhash,
|
previous_blockhash: self.previous_blockhash,
|
||||||
blockhash: self.blockhash,
|
blockhash: self.blockhash,
|
||||||
parent_slot: self.parent_slot,
|
parent_slot: self.parent_slot,
|
||||||
@@ -430,13 +444,17 @@ impl VersionedConfirmedBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ConfirmedBlock> for VersionedConfirmedBlock {
|
impl From<VersionedConfirmedBlock> for ConfirmedBlock {
|
||||||
fn from(block: ConfirmedBlock) -> Self {
|
fn from(block: VersionedConfirmedBlock) -> Self {
|
||||||
VersionedConfirmedBlock {
|
Self {
|
||||||
previous_blockhash: block.previous_blockhash,
|
previous_blockhash: block.previous_blockhash,
|
||||||
blockhash: block.blockhash,
|
blockhash: block.blockhash,
|
||||||
parent_slot: block.parent_slot,
|
parent_slot: block.parent_slot,
|
||||||
transactions: block.transactions.into_iter().map(|tx| tx.into()).collect(),
|
transactions: block
|
||||||
|
.transactions
|
||||||
|
.into_iter()
|
||||||
|
.map(TransactionWithStatusMeta::Complete)
|
||||||
|
.collect(),
|
||||||
rewards: block.rewards,
|
rewards: block.rewards,
|
||||||
block_time: block.block_time,
|
block_time: block.block_time,
|
||||||
block_height: block.block_height,
|
block_height: block.block_height,
|
||||||
@@ -444,7 +462,7 @@ impl From<ConfirmedBlock> for VersionedConfirmedBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for ConfirmedBlock {
|
impl Encodable for LegacyConfirmedBlock {
|
||||||
type Encoded = EncodedConfirmedBlock;
|
type Encoded = EncodedConfirmedBlock;
|
||||||
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
|
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
|
||||||
Self::Encoded {
|
Self::Encoded {
|
||||||
@@ -463,7 +481,7 @@ impl Encodable for ConfirmedBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfirmedBlock {
|
impl LegacyConfirmedBlock {
|
||||||
pub fn configure(
|
pub fn configure(
|
||||||
self,
|
self,
|
||||||
encoding: UiTransactionEncoding,
|
encoding: UiTransactionEncoding,
|
||||||
@@ -565,44 +583,68 @@ impl From<EncodedConfirmedBlock> for UiConfirmedBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
pub enum TransactionWithStatusMeta {
|
||||||
|
// Very old transactions may be missing metadata
|
||||||
|
MissingMetadata(Transaction),
|
||||||
|
// Versioned stored transaction always have metadata
|
||||||
|
Complete(VersionedTransactionWithStatusMeta),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct VersionedTransactionWithStatusMeta {
|
pub struct VersionedTransactionWithStatusMeta {
|
||||||
pub transaction: VersionedTransaction,
|
pub transaction: VersionedTransaction,
|
||||||
|
pub meta: TransactionStatusMeta,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LegacyTransactionWithStatusMeta {
|
||||||
|
pub transaction: Transaction,
|
||||||
pub meta: Option<TransactionStatusMeta>,
|
pub meta: Option<TransactionStatusMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TransactionWithStatusMeta {
|
||||||
|
pub fn transaction_signature(&self) -> &Signature {
|
||||||
|
match self {
|
||||||
|
Self::MissingMetadata(transaction) => &transaction.signatures[0],
|
||||||
|
Self::Complete(VersionedTransactionWithStatusMeta { transaction, .. }) => {
|
||||||
|
&transaction.signatures[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_legacy_transaction_with_meta(self) -> Option<LegacyTransactionWithStatusMeta> {
|
||||||
|
match self {
|
||||||
|
TransactionWithStatusMeta::MissingMetadata(transaction) => {
|
||||||
|
Some(LegacyTransactionWithStatusMeta {
|
||||||
|
transaction,
|
||||||
|
meta: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
TransactionWithStatusMeta::Complete(tx_with_meta) => {
|
||||||
|
tx_with_meta.into_legacy_transaction_with_meta()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl VersionedTransactionWithStatusMeta {
|
impl VersionedTransactionWithStatusMeta {
|
||||||
pub fn account_keys(&self) -> AccountKeys {
|
pub fn account_keys(&self) -> AccountKeys {
|
||||||
AccountKeys::new(
|
AccountKeys::new(
|
||||||
self.transaction.message.static_account_keys(),
|
self.transaction.message.static_account_keys(),
|
||||||
self.meta.as_ref().map(|meta| &meta.loaded_addresses),
|
Some(&self.meta.loaded_addresses),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_legacy_transaction_with_meta(self) -> Option<TransactionWithStatusMeta> {
|
pub fn into_legacy_transaction_with_meta(self) -> Option<LegacyTransactionWithStatusMeta> {
|
||||||
Some(TransactionWithStatusMeta {
|
Some(LegacyTransactionWithStatusMeta {
|
||||||
transaction: self.transaction.into_legacy_transaction()?,
|
transaction: self.transaction.into_legacy_transaction()?,
|
||||||
meta: self.meta,
|
meta: Some(self.meta),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TransactionWithStatusMeta> for VersionedTransactionWithStatusMeta {
|
impl Encodable for LegacyTransactionWithStatusMeta {
|
||||||
fn from(tx_with_meta: TransactionWithStatusMeta) -> Self {
|
|
||||||
Self {
|
|
||||||
transaction: tx_with_meta.transaction.into(),
|
|
||||||
meta: tx_with_meta.meta,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct TransactionWithStatusMeta {
|
|
||||||
pub transaction: Transaction,
|
|
||||||
pub meta: Option<TransactionStatusMeta>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Encodable for TransactionWithStatusMeta {
|
|
||||||
type Encoded = EncodedTransactionWithStatusMeta;
|
type Encoded = EncodedTransactionWithStatusMeta;
|
||||||
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
|
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
|
||||||
Self::Encoded {
|
Self::Encoded {
|
||||||
@@ -627,21 +669,10 @@ pub struct EncodedTransactionWithStatusMeta {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ConfirmedTransactionWithStatusMeta {
|
pub struct ConfirmedTransactionWithStatusMeta {
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
pub transaction: TransactionWithStatusMeta,
|
pub tx_with_meta: TransactionWithStatusMeta,
|
||||||
pub block_time: Option<UnixTimestamp>,
|
pub block_time: Option<UnixTimestamp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for ConfirmedTransactionWithStatusMeta {
|
|
||||||
type Encoded = EncodedConfirmedTransactionWithStatusMeta;
|
|
||||||
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
|
|
||||||
Self::Encoded {
|
|
||||||
slot: self.slot,
|
|
||||||
transaction: self.transaction.encode(encoding),
|
|
||||||
block_time: self.block_time,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct VersionedConfirmedTransactionWithStatusMeta {
|
pub struct VersionedConfirmedTransactionWithStatusMeta {
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
@@ -649,15 +680,31 @@ pub struct VersionedConfirmedTransactionWithStatusMeta {
|
|||||||
pub block_time: Option<UnixTimestamp>,
|
pub block_time: Option<UnixTimestamp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VersionedConfirmedTransactionWithStatusMeta {
|
pub struct LegacyConfirmedTransactionWithStatusMeta {
|
||||||
|
pub slot: Slot,
|
||||||
|
pub tx_with_meta: LegacyTransactionWithStatusMeta,
|
||||||
|
pub block_time: Option<UnixTimestamp>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for LegacyConfirmedTransactionWithStatusMeta {
|
||||||
|
type Encoded = EncodedConfirmedTransactionWithStatusMeta;
|
||||||
|
fn encode(self, encoding: UiTransactionEncoding) -> Self::Encoded {
|
||||||
|
Self::Encoded {
|
||||||
|
slot: self.slot,
|
||||||
|
transaction: self.tx_with_meta.encode(encoding),
|
||||||
|
block_time: self.block_time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfirmedTransactionWithStatusMeta {
|
||||||
/// Downgrades a versioned confirmed transaction into a legacy
|
/// Downgrades a versioned confirmed transaction into a legacy
|
||||||
/// confirmed transaction if it contains a legacy transaction.
|
/// confirmed transaction if it contains a legacy transaction.
|
||||||
pub fn into_legacy_confirmed_transaction(self) -> Option<ConfirmedTransactionWithStatusMeta> {
|
pub fn into_legacy_confirmed_transaction(
|
||||||
Some(ConfirmedTransactionWithStatusMeta {
|
self,
|
||||||
transaction: TransactionWithStatusMeta {
|
) -> Option<LegacyConfirmedTransactionWithStatusMeta> {
|
||||||
transaction: self.tx_with_meta.transaction.into_legacy_transaction()?,
|
Some(LegacyConfirmedTransactionWithStatusMeta {
|
||||||
meta: self.tx_with_meta.meta,
|
tx_with_meta: self.tx_with_meta.into_legacy_transaction_with_meta()?,
|
||||||
},
|
|
||||||
block_time: self.block_time,
|
block_time: self.block_time,
|
||||||
slot: self.slot,
|
slot: self.slot,
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user