Enforce tx metadata upload with static types (#23028)

This commit is contained in:
Justin Starry
2022-02-10 13:28:18 +08:00
committed by GitHub
parent 2ca7ae8e30
commit d5dec989b9
16 changed files with 482 additions and 440 deletions

View File

@ -80,10 +80,10 @@ use {
solana_storage_bigtable::Error as StorageError,
solana_streamer::socket::SocketAddrSpace,
solana_transaction_status::{
ConfirmedTransactionStatusWithSignature, Encodable,
EncodedConfirmedTransactionWithStatusMeta, Reward, RewardType,
TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, UiTransactionEncoding,
VersionedConfirmedBlock,
ConfirmedBlock, ConfirmedTransactionStatusWithSignature,
ConfirmedTransactionWithStatusMeta, Encodable, EncodedConfirmedTransactionWithStatusMeta,
Reward, RewardType, TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock,
UiTransactionEncoding,
},
solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY},
spl_token::{
@ -918,12 +918,8 @@ impl JsonRpcRequestProcessor {
&self,
result: &std::result::Result<T, BlockstoreError>,
slot: Slot,
) -> Result<()>
where
T: std::fmt::Debug,
{
if result.is_err() {
let err = result.as_ref().unwrap_err();
) -> Result<()> {
if let Err(err) = result {
debug!(
"check_blockstore_root, slot: {:?}, max root: {:?}, err: {:?}",
slot,
@ -944,21 +940,16 @@ impl JsonRpcRequestProcessor {
&self,
result: &std::result::Result<T, BlockstoreError>,
slot: Slot,
) -> Result<()>
where
T: std::fmt::Debug,
{
if result.is_err() {
if let BlockstoreError::SlotCleanedUp = result.as_ref().unwrap_err() {
return Err(RpcCustomError::BlockCleanedUp {
slot,
first_available_block: self
.blockstore
.get_first_available_block()
.unwrap_or_default(),
}
.into());
) -> Result<()> {
if let Err(BlockstoreError::SlotCleanedUp) = result {
return Err(RpcCustomError::BlockCleanedUp {
slot,
first_available_block: self
.blockstore
.get_first_available_block()
.unwrap_or_default(),
}
.into());
}
Ok(())
}
@ -966,15 +957,9 @@ impl JsonRpcRequestProcessor {
fn check_bigtable_result<T>(
&self,
result: &std::result::Result<T, solana_storage_bigtable::Error>,
) -> Result<()>
where
T: std::fmt::Debug,
{
if result.is_err() {
let err = result.as_ref().unwrap_err();
if let solana_storage_bigtable::Error::BlockNotFound(slot) = err {
return Err(RpcCustomError::LongTermStorageSlotSkipped { slot: *slot }.into());
}
) -> Result<()> {
if let Err(solana_storage_bigtable::Error::BlockNotFound(slot)) = result {
return Err(RpcCustomError::LongTermStorageSlotSkipped { slot: *slot }.into());
}
Ok(())
}
@ -1017,12 +1002,12 @@ impl JsonRpcRequestProcessor {
self.check_status_is_complete(slot)?;
let result = self.blockstore.get_rooted_block(slot, true);
self.check_blockstore_root(&result, slot)?;
let configure_block = |versioned_block: VersionedConfirmedBlock| {
let confirmed_block = versioned_block
let configure_block = |confirmed_block: ConfirmedBlock| {
let legacy_block = confirmed_block
.into_legacy_block()
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
let mut confirmed_block =
confirmed_block.configure(encoding, transaction_details, show_rewards);
legacy_block.configure(encoding, transaction_details, show_rewards);
if slot == 0 {
confirmed_block.block_time = Some(self.genesis_creation_time());
confirmed_block.block_height = Some(0);
@ -1038,7 +1023,11 @@ impl JsonRpcRequestProcessor {
}
}
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() {
// Check if block is confirmed
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
@ -1047,30 +1036,28 @@ impl JsonRpcRequestProcessor {
let result = self.blockstore.get_complete_block(slot, true);
return result
.ok()
.map(|versioned_block| {
let mut confirmed_block = versioned_block
.map(ConfirmedBlock::from)
.map(|confirmed_block| -> Result<UiConfirmedBlock> {
let mut legacy_block = confirmed_block
.into_legacy_block()
.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 bank = r_bank_forks.get(slot).cloned();
if let Some(bank) = bank {
if confirmed_block.block_time.is_none() {
confirmed_block.block_time =
Some(bank.clock().unix_timestamp);
if legacy_block.block_time.is_none() {
legacy_block.block_time = Some(bank.clock().unix_timestamp);
}
if confirmed_block.block_height.is_none() {
confirmed_block.block_height = Some(bank.block_height());
if legacy_block.block_height.is_none() {
legacy_block.block_height = Some(bank.block_height());
}
}
}
Ok(confirmed_block.configure(
encoding,
transaction_details,
show_rewards,
))
Ok(legacy_block.configure(encoding, transaction_details, show_rewards))
})
.transpose();
}
@ -1397,7 +1384,7 @@ impl JsonRpcRequestProcessor {
if self.config.enable_rpc_transaction_history {
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();
self.blockstore
.get_complete_transaction(signature, highest_confirmed_slot)
@ -1405,12 +1392,16 @@ impl JsonRpcRequestProcessor {
self.blockstore.get_rooted_transaction(signature)
};
match versioned_confirmed_tx.unwrap_or(None) {
Some(versioned_confirmed_tx) => {
let mut confirmed_transaction = versioned_confirmed_tx
.into_legacy_confirmed_transaction()
let encode_transaction =
|confirmed_tx_with_meta: ConfirmedTransactionWithStatusMeta| -> Result<EncodedConfirmedTransactionWithStatusMeta> {
let legacy_tx_with_meta = confirmed_tx_with_meta.into_legacy_confirmed_transaction()
.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()
&& confirmed_bank // should be redundant
.status_cache_ancestors()
@ -1422,8 +1413,9 @@ impl JsonRpcRequestProcessor {
.get(confirmed_transaction.slot)
.map(|bank| bank.clock().unix_timestamp);
}
return Ok(Some(confirmed_transaction.encode(encoding)));
return Ok(Some(encode_transaction(confirmed_transaction)?));
}
if confirmed_transaction.slot
<= self
.block_commitment_cache
@ -1431,7 +1423,7 @@ impl JsonRpcRequestProcessor {
.unwrap()
.highest_confirmed_root()
{
return Ok(Some(confirmed_transaction.encode(encoding)));
return Ok(Some(encode_transaction(confirmed_transaction)?));
}
}
None => {
@ -1440,13 +1432,7 @@ impl JsonRpcRequestProcessor {
.get_confirmed_transaction(&signature)
.await
.unwrap_or(None)
.map(|versioned_confirmed_tx| {
let confirmed_tx = versioned_confirmed_tx
.into_legacy_confirmed_transaction()
.ok_or(RpcCustomError::UnsupportedTransactionVersion)?;
Ok(confirmed_tx.encode(encoding))
})
.map(encode_transaction)
.transpose();
}
}
@ -4328,15 +4314,7 @@ pub fn create_test_transactions_and_populate_blockstore(
);
let ix_error_signature = ix_error_tx.signatures[0];
let entry_2 = solana_entry::entry::next_entry(&entry_1.hash, 1, vec![ix_error_tx]);
// Failed transaction
let fail_tx = solana_sdk::system_transaction::transfer(
mint_keypair,
&keypair2.pubkey(),
rent_exempt_amount,
Hash::default(),
);
let entry_3 = solana_entry::entry::next_entry(&entry_2.hash, 1, vec![fail_tx]);
let entries = vec![entry_1, entry_2, entry_3];
let entries = vec![entry_1, entry_2];
let shreds =
solana_ledger::blockstore::entries_to_test_shreds(&entries, 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
// that they are matched properly by get_rooted_block
let _result = solana_ledger::blockstore_processor::process_entries_for_tests(
&bank,
entries,
true,
Some(
&solana_ledger::blockstore_processor::TransactionStatusSender {
sender: transaction_status_sender,
enable_cpi_and_log_storage: false,
},
assert_eq!(
solana_ledger::blockstore_processor::process_entries_for_tests(
&bank,
entries,
true,
Some(
&solana_ledger::blockstore_processor::TransactionStatusSender {
sender: transaction_status_sender,
enable_cpi_and_log_storage: false,
},
),
Some(&replay_vote_sender),
),
Some(&replay_vote_sender),
Ok(())
);
transaction_status_service.join().unwrap();
@ -6613,7 +6594,7 @@ pub mod tests {
let confirmed_block: Option<EncodedConfirmedBlock> =
serde_json::from_value(result["result"].clone()).unwrap();
let confirmed_block = confirmed_block.unwrap();
assert_eq!(confirmed_block.transactions.len(), 3);
assert_eq!(confirmed_block.transactions.len(), 2);
assert_eq!(confirmed_block.rewards, vec![]);
for EncodedTransactionWithStatusMeta { transaction, meta } in
@ -6658,7 +6639,7 @@ pub mod tests {
let confirmed_block: Option<EncodedConfirmedBlock> =
serde_json::from_value(result["result"].clone()).unwrap();
let confirmed_block = confirmed_block.unwrap();
assert_eq!(confirmed_block.transactions.len(), 3);
assert_eq!(confirmed_block.transactions.len(), 2);
assert_eq!(confirmed_block.rewards, vec![]);
for EncodedTransactionWithStatusMeta { transaction, meta } in

View File

@ -40,7 +40,7 @@ use {
timing::timestamp,
transaction,
},
solana_transaction_status::ConfirmedBlock,
solana_transaction_status::{ConfirmedBlock, LegacyConfirmedBlock},
std::{
cell::RefCell,
collections::{HashMap, VecDeque},
@ -278,30 +278,26 @@ impl RpcNotifier {
}
fn filter_block_result_txs(
block: ConfirmedBlock,
mut block: LegacyConfirmedBlock,
last_modified_slot: Slot,
params: &BlockSubscriptionParams,
) -> Option<RpcBlockUpdate> {
let transactions = match params.kind {
block.transactions = match params.kind {
BlockSubscriptionKind::All => block.transactions,
BlockSubscriptionKind::MentionsAccountOrProgram(pk) => block
.transactions
.into_iter()
.filter(|tx| tx.transaction.message.account_keys.contains(&pk))
.filter(|tx_with_meta| tx_with_meta.transaction.message.account_keys.contains(&pk))
.collect(),
};
if transactions.is_empty() {
if block.transactions.is_empty() {
if let BlockSubscriptionKind::MentionsAccountOrProgram(_) = params.kind {
return None;
}
}
let block = ConfirmedBlock {
transactions,
..block
}
.configure(
let block = block.configure(
params.encoding,
params.transaction_details,
params.show_rewards,
@ -962,26 +958,29 @@ impl RpcSubscriptions {
break;
}
let block_result = blockstore
let block_update_result = blockstore
.get_complete_block(s, false)
.map_err(|e| {
error!("get_complete_block error: {}", e);
RpcBlockUpdateError::BlockStoreError
})
.and_then(|versioned_block| {
versioned_block.into_legacy_block().ok_or(
RpcBlockUpdateError::UnsupportedTransactionVersion,
)
ConfirmedBlock::from(versioned_block)
.into_legacy_block()
.ok_or(
RpcBlockUpdateError::UnsupportedTransactionVersion,
)
});
match block_result {
Ok(block) => {
if let Some(res) = filter_block_result_txs(block, s, params)
match block_update_result {
Ok(block_update) => {
if let Some(block_update) =
filter_block_result_txs(block_update, s, params)
{
notifier.notify(
Response {
context: RpcResponseContext { slot: s },
value: res,
value: block_update,
},
subscription,
false,
@ -1357,8 +1356,13 @@ pub(crate) mod tests {
#[serial]
fn test_check_confirmed_block_subscribe() {
let exit = Arc::new(AtomicBool::new(false));
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(10_000);
let bank = Bank::new_for_tests(&genesis_config);
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
let optimistically_confirmed_bank =
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
@ -1399,10 +1403,11 @@ pub(crate) mod tests {
let keypair1 = Keypair::new();
let keypair2 = Keypair::new();
let keypair3 = Keypair::new();
let keypair4 = Keypair::new();
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey())
.unwrap();
let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore(
vec![&keypair1, &keypair2, &keypair3, &keypair4],
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
0,
bank,
blockstore.clone(),
@ -1414,8 +1419,9 @@ pub(crate) mod tests {
let actual_resp = receiver.recv();
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
let versioned_block = blockstore.get_complete_block(slot, false).unwrap();
let legacy_block = versioned_block.into_legacy_block().unwrap();
let confirmed_block =
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 expected_resp = RpcBlockUpdate {
slot,
@ -1455,8 +1461,13 @@ pub(crate) mod tests {
#[serial]
fn test_check_confirmed_block_subscribe_with_mentions() {
let exit = Arc::new(AtomicBool::new(false));
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(10_000);
let bank = Bank::new_for_tests(&genesis_config);
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
let optimistically_confirmed_bank =
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
@ -1498,10 +1509,11 @@ pub(crate) mod tests {
let bank = bank_forks.read().unwrap().working_bank();
let keypair2 = Keypair::new();
let keypair3 = Keypair::new();
let keypair4 = Keypair::new();
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey())
.unwrap();
let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore(
vec![&keypair1, &keypair2, &keypair3, &keypair4],
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
0,
bank,
blockstore.clone(),
@ -1514,8 +1526,9 @@ pub(crate) mod tests {
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
// make sure it filtered out the other keypairs
let versioned_block = blockstore.get_complete_block(slot, false).unwrap();
let mut legacy_block = versioned_block.into_legacy_block().unwrap();
let confirmed_block =
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| {
tx_with_meta
.transaction
@ -1552,8 +1565,13 @@ pub(crate) mod tests {
#[serial]
fn test_check_finalized_block_subscribe() {
let exit = Arc::new(AtomicBool::new(false));
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(10_000);
let bank = Bank::new_for_tests(&genesis_config);
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
let optimistically_confirmed_bank =
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
@ -1593,10 +1611,11 @@ pub(crate) mod tests {
let keypair1 = Keypair::new();
let keypair2 = Keypair::new();
let keypair3 = Keypair::new();
let keypair4 = Keypair::new();
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey())
.unwrap();
let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore(
vec![&keypair1, &keypair2, &keypair3, &keypair4],
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
0,
bank,
blockstore.clone(),
@ -1613,8 +1632,9 @@ pub(crate) mod tests {
let actual_resp = receiver.recv();
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
let versioned_block = blockstore.get_complete_block(slot, false).unwrap();
let legacy_block = versioned_block.into_legacy_block().unwrap();
let confirmed_block =
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 expected_resp = RpcBlockUpdate {
slot,