Rpc: fix getConfirmedTransaction slot (#16288)

* Fix transaction blockstore apis

* Update blockstore apis in rpc
This commit is contained in:
Tyera Eulberg 2021-03-31 21:04:00 -06:00 committed by GitHub
parent 3f63ed9a72
commit 18bd47dbe1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 80 deletions

View File

@ -1005,7 +1005,7 @@ impl JsonRpcRequestProcessor {
Some(status) Some(status)
} else if self.config.enable_rpc_transaction_history && search_transaction_history { } else if self.config.enable_rpc_transaction_history && search_transaction_history {
self.blockstore self.blockstore
.get_transaction_status(signature, true) .get_rooted_transaction_status(signature)
.map_err(|_| Error::internal_error())? .map_err(|_| Error::internal_error())?
.filter(|(slot, _status_meta)| { .filter(|(slot, _status_meta)| {
slot <= &self slot <= &self
@ -1092,20 +1092,22 @@ impl JsonRpcRequestProcessor {
check_is_at_least_confirmed(commitment)?; check_is_at_least_confirmed(commitment)?;
if self.config.enable_rpc_transaction_history { if self.config.enable_rpc_transaction_history {
match self let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
.blockstore let transaction = if commitment.is_confirmed() {
.get_complete_transaction(signature) let highest_confirmed_slot = confirmed_bank.slot();
.unwrap_or(None) self.blockstore
{ .get_complete_transaction(signature, highest_confirmed_slot)
} else {
self.blockstore.get_rooted_transaction(signature)
};
match transaction.unwrap_or(None) {
Some(confirmed_transaction) => { Some(confirmed_transaction) => {
if commitment.is_confirmed() { if commitment.is_confirmed()
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed())); && confirmed_bank // should be redundant
if confirmed_bank
.status_cache_ancestors() .status_cache_ancestors()
.contains(&confirmed_transaction.slot) .contains(&confirmed_transaction.slot)
{ {
return Ok(Some(confirmed_transaction.encode(encoding))); return Ok(Some(confirmed_transaction.encode(encoding)));
}
} }
if confirmed_transaction.slot if confirmed_transaction.slot
<= self <= self

View File

@ -1,8 +1,8 @@
//! The `blockstore` module provides functions for parallel verification of the //! The `blockstore` module provides functions for parallel verification of the
//! Proof of History ledger as well as iterative read, append write, and random //! Proof of History ledger as well as iterative read, append write, and random
//! access read to a persistent file-based ledger. //! access read to a persistent file-based ledger.
pub use crate::{blockstore_db::BlockstoreError, blockstore_meta::SlotMeta};
use crate::{ use crate::{
ancestor_iterator::AncestorIterator,
blockstore_db::{ blockstore_db::{
columns as cf, AccessType, BlockstoreRecoveryMode, Column, Database, IteratorDirection, columns as cf, AccessType, BlockstoreRecoveryMode, Column, Database, IteratorDirection,
IteratorMode, LedgerColumn, Result, WriteBatch, IteratorMode, LedgerColumn, Result, WriteBatch,
@ -14,6 +14,7 @@ use crate::{
next_slots_iterator::NextSlotsIterator, next_slots_iterator::NextSlotsIterator,
shred::{Result as ShredResult, Shred, Shredder}, shred::{Result as ShredResult, Shred, Shredder},
}; };
pub use crate::{blockstore_db::BlockstoreError, blockstore_meta::SlotMeta};
use bincode::deserialize; use bincode::deserialize;
use log::*; use log::*;
use rayon::{ use rayon::{
@ -1973,7 +1974,7 @@ impl Blockstore {
fn get_transaction_status_with_counter( fn get_transaction_status_with_counter(
&self, &self,
signature: Signature, signature: Signature,
require_root: bool, confirmed_unrooted_slots: &[Slot],
) -> Result<(Option<(Slot, TransactionStatusMeta)>, u64)> { ) -> Result<(Option<(Slot, TransactionStatusMeta)>, u64)> {
let mut counter = 0; let mut counter = 0;
for transaction_status_cf_primary_index in 0..=1 { for transaction_status_cf_primary_index in 0..=1 {
@ -1986,7 +1987,7 @@ impl Blockstore {
if i != transaction_status_cf_primary_index || sig != signature { if i != transaction_status_cf_primary_index || sig != signature {
break; break;
} }
if require_root && !self.is_root(slot) || self.meta(slot)?.is_none() { if !self.is_root(slot) && !confirmed_unrooted_slots.contains(&slot) {
continue; continue;
} }
let status = self let status = self
@ -2000,50 +2001,73 @@ impl Blockstore {
Ok((None, counter)) Ok((None, counter))
} }
/// Returns a transaction status
pub fn get_rooted_transaction_status(
&self,
signature: Signature,
) -> Result<Option<(Slot, TransactionStatusMeta)>> {
datapoint_info!(
"blockstore-rpc-api",
(
"method",
"get_rooted_transaction_status".to_string(),
String
)
);
self.get_transaction_status(signature, &[])
}
/// Returns a transaction status /// Returns a transaction status
pub fn get_transaction_status( pub fn get_transaction_status(
&self, &self,
signature: Signature, signature: Signature,
require_root: bool, confirmed_unrooted_slots: &[Slot],
) -> Result<Option<(Slot, TransactionStatusMeta)>> { ) -> Result<Option<(Slot, TransactionStatusMeta)>> {
datapoint_info!( datapoint_info!(
"blockstore-rpc-api", "blockstore-rpc-api",
("method", "get_transaction_status".to_string(), String) ("method", "get_transaction_status".to_string(), String)
); );
self.get_transaction_status_with_counter(signature, require_root) self.get_transaction_status_with_counter(signature, confirmed_unrooted_slots)
.map(|(status, _)| status) .map(|(status, _)| status)
} }
/// Returns a complete transaction if it was processed in a root /// Returns a complete transaction if it was processed in a root
pub fn get_confirmed_transaction( pub fn get_rooted_transaction(
&self, &self,
signature: Signature, signature: Signature,
) -> Result<Option<ConfirmedTransaction>> { ) -> Result<Option<ConfirmedTransaction>> {
datapoint_info!( datapoint_info!(
"blockstore-rpc-api", "blockstore-rpc-api",
("method", "get_confirmed_transaction".to_string(), String) ("method", "get_rooted_transaction".to_string(), String)
); );
self.get_transaction_with_status(signature, true) self.get_transaction_with_status(signature, &[])
} }
/// Returns a complete transaction /// Returns a complete transaction
pub fn get_complete_transaction( pub fn get_complete_transaction(
&self, &self,
signature: Signature, signature: Signature,
highest_confirmed_slot: Slot,
) -> Result<Option<ConfirmedTransaction>> { ) -> Result<Option<ConfirmedTransaction>> {
datapoint_info!( datapoint_info!(
"blockstore-rpc-api", "blockstore-rpc-api",
("method", "get_complete_transaction".to_string(), String) ("method", "get_complete_transaction".to_string(), String)
); );
self.get_transaction_with_status(signature, false) let confirmed_unrooted_slots: Vec<_> =
AncestorIterator::new_inclusive(highest_confirmed_slot, self)
.filter(|&slot| slot > self.last_root())
.collect();
self.get_transaction_with_status(signature, &confirmed_unrooted_slots)
} }
fn get_transaction_with_status( fn get_transaction_with_status(
&self, &self,
signature: Signature, signature: Signature,
require_root: bool, confirmed_unrooted_slots: &[Slot],
) -> Result<Option<ConfirmedTransaction>> { ) -> Result<Option<ConfirmedTransaction>> {
if let Some((slot, status)) = self.get_transaction_status(signature, require_root)? { if let Some((slot, status)) =
self.get_transaction_status(signature, confirmed_unrooted_slots)?
{
let transaction = self let transaction = self
.find_transaction_in_slot(slot, signature)? .find_transaction_in_slot(slot, signature)?
.ok_or(BlockstoreError::TransactionStatusSlotMismatch)?; // Should not happen .ok_or(BlockstoreError::TransactionStatusSlotMismatch)?; // Should not happen
@ -2161,7 +2185,7 @@ impl Blockstore {
let (slot, mut before_excluded_signatures) = match before { let (slot, mut before_excluded_signatures) = match before {
None => (highest_confirmed_root, None), None => (highest_confirmed_root, None),
Some(before) => { Some(before) => {
let transaction_status = self.get_transaction_status(before, true)?; let transaction_status = self.get_transaction_status(before, &[])?;
match transaction_status { match transaction_status {
None => return Ok(vec![]), None => return Ok(vec![]),
Some((slot, _)) => { Some((slot, _)) => {
@ -2212,7 +2236,7 @@ impl Blockstore {
let (lowest_slot, until_excluded_signatures) = match until { let (lowest_slot, until_excluded_signatures) = match until {
None => (0, HashSet::new()), None => (0, HashSet::new()),
Some(until) => { Some(until) => {
let transaction_status = self.get_transaction_status(until, true)?; let transaction_status = self.get_transaction_status(until, &[])?;
match transaction_status { match transaction_status {
None => (0, HashSet::new()), None => (0, HashSet::new()),
Some((slot, _)) => { Some((slot, _)) => {
@ -2357,7 +2381,7 @@ impl Blockstore {
let mut get_status_info_timer = Measure::start("get_status_info_timer"); let mut get_status_info_timer = Measure::start("get_status_info_timer");
let mut infos = vec![]; let mut infos = vec![];
for (slot, signature) in address_signatures.into_iter() { for (slot, signature) in address_signatures.into_iter() {
let transaction_status = self.get_transaction_status(signature, true)?; let transaction_status = self.get_transaction_status(signature, &[])?;
let err = match transaction_status { let err = match transaction_status {
None => None, None => None,
Some((_slot, status)) => status.status.err(), Some((_slot, status)) => status.status.err(),
@ -6295,11 +6319,31 @@ pub mod tests {
let signature4 = Signature::new(&[4u8; 64]); let signature4 = Signature::new(&[4u8; 64]);
let signature5 = Signature::new(&[5u8; 64]); let signature5 = Signature::new(&[5u8; 64]);
let signature6 = Signature::new(&[6u8; 64]); let signature6 = Signature::new(&[6u8; 64]);
let signature7 = Signature::new(&[7u8; 64]);
// Insert slots with fork
// 0 (root)
// / \
// 1 |
// 2 (root)
// |
// 3
let meta0 = SlotMeta::new(0, 0);
blockstore.meta_cf.put(0, &meta0).unwrap();
let meta1 = SlotMeta::new(1, 0);
blockstore.meta_cf.put(1, &meta1).unwrap();
let meta2 = SlotMeta::new(2, 0);
blockstore.meta_cf.put(2, &meta2).unwrap();
let meta3 = SlotMeta::new(3, 2);
blockstore.meta_cf.put(3, &meta3).unwrap();
blockstore.set_roots(&[0, 2]).unwrap();
// Initialize index 0, including: // Initialize index 0, including:
// signature2 in non-root and root, // signature2 in non-root and root,
// signature4 in 2 non-roots, // signature4 in non-root,
// extra entries // signature5 in skipped slot and non-root,
// signature6 in skipped slot,
transaction_status_cf transaction_status_cf
.put_protobuf((0, signature2, 1), &status) .put_protobuf((0, signature2, 1), &status)
.unwrap(); .unwrap();
@ -6308,121 +6352,129 @@ pub mod tests {
.put_protobuf((0, signature2, 2), &status) .put_protobuf((0, signature2, 2), &status)
.unwrap(); .unwrap();
transaction_status_cf
.put_protobuf((0, signature4, 0), &status)
.unwrap();
transaction_status_cf transaction_status_cf
.put_protobuf((0, signature4, 1), &status) .put_protobuf((0, signature4, 1), &status)
.unwrap(); .unwrap();
transaction_status_cf
.put_protobuf((0, signature5, 0), &status)
.unwrap();
transaction_status_cf transaction_status_cf
.put_protobuf((0, signature5, 1), &status) .put_protobuf((0, signature5, 1), &status)
.unwrap(); .unwrap();
// Initialize index 1, including:
// signature4 in non-root and root,
// extra entries
transaction_status_cf transaction_status_cf
.put_protobuf((1, signature4, 1), &status) .put_protobuf((0, signature5, 3), &status)
.unwrap(); .unwrap();
transaction_status_cf
.put_protobuf((0, signature6, 1), &status)
.unwrap();
// Initialize index 1, including:
// signature4 in root,
// signature6 in non-root,
// signature5 extra entries
transaction_status_cf transaction_status_cf
.put_protobuf((1, signature4, 2), &status) .put_protobuf((1, signature4, 2), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put_protobuf((1, signature5, 0), &status) .put_protobuf((1, signature5, 4), &status)
.unwrap(); .unwrap();
transaction_status_cf transaction_status_cf
.put_protobuf((1, signature5, 1), &status) .put_protobuf((1, signature5, 5), &status)
.unwrap(); .unwrap();
blockstore.set_roots(&[2]).unwrap(); transaction_status_cf
.put_protobuf((1, signature6, 3), &status)
.unwrap();
// Signature exists, root found in index 0 // Signature exists, root found in index 0
if let (Some((slot, _status)), counter) = blockstore if let (Some((slot, _status)), counter) = blockstore
.get_transaction_status_with_counter(signature2, true) .get_transaction_status_with_counter(signature2, &[])
.unwrap() .unwrap()
{ {
assert_eq!(slot, 2); assert_eq!(slot, 2);
assert_eq!(counter, 2); assert_eq!(counter, 2);
} }
// Signature exists, root not required // Signature exists, root found although not required
if let (Some((slot, _status)), counter) = blockstore if let (Some((slot, _status)), counter) = blockstore
.get_transaction_status_with_counter(signature2, false) .get_transaction_status_with_counter(signature2, &[3])
.unwrap() .unwrap()
{ {
assert_eq!(slot, 1); assert_eq!(slot, 2);
assert_eq!(counter, 1); assert_eq!(counter, 2);
} }
// Signature exists, root found in index 1 // Signature exists, root found in index 1
if let (Some((slot, _status)), counter) = blockstore if let (Some((slot, _status)), counter) = blockstore
.get_transaction_status_with_counter(signature4, true) .get_transaction_status_with_counter(signature4, &[])
.unwrap() .unwrap()
{ {
assert_eq!(slot, 2); assert_eq!(slot, 2);
assert_eq!(counter, 5); assert_eq!(counter, 3);
}
// Signature exists, root found although not required, in index 1
if let (Some((slot, _status)), counter) = blockstore
.get_transaction_status_with_counter(signature4, &[3])
.unwrap()
{
assert_eq!(slot, 2);
assert_eq!(counter, 3);
} }
// Signature exists, no root found // Signature exists, no root found
let (status, counter) = blockstore let (status, counter) = blockstore
.get_transaction_status_with_counter(signature5, true) .get_transaction_status_with_counter(signature5, &[])
.unwrap(); .unwrap();
assert_eq!(status, None); assert_eq!(status, None);
assert_eq!(counter, 6); assert_eq!(counter, 6);
// Signature exists, root not required // Signature exists, root not required
if let (Some((slot, _status)), counter) = blockstore if let (Some((slot, _status)), counter) = blockstore
.get_transaction_status_with_counter(signature5, false) .get_transaction_status_with_counter(signature5, &[3])
.unwrap() .unwrap()
{ {
assert_eq!(slot, 0); assert_eq!(slot, 3);
assert_eq!(counter, 1); assert_eq!(counter, 2);
} }
// Signature does not exist, smaller than existing entries // Signature does not exist, smaller than existing entries
let (status, counter) = blockstore let (status, counter) = blockstore
.get_transaction_status_with_counter(signature1, true) .get_transaction_status_with_counter(signature1, &[])
.unwrap(); .unwrap();
assert_eq!(status, None); assert_eq!(status, None);
assert_eq!(counter, 2); assert_eq!(counter, 2);
let (status, counter) = blockstore let (status, counter) = blockstore
.get_transaction_status_with_counter(signature1, false) .get_transaction_status_with_counter(signature1, &[3])
.unwrap(); .unwrap();
assert_eq!(status, None); assert_eq!(status, None);
assert_eq!(counter, 2); assert_eq!(counter, 2);
// Signature does not exist, between existing entries // Signature does not exist, between existing entries
let (status, counter) = blockstore let (status, counter) = blockstore
.get_transaction_status_with_counter(signature3, true) .get_transaction_status_with_counter(signature3, &[])
.unwrap(); .unwrap();
assert_eq!(status, None); assert_eq!(status, None);
assert_eq!(counter, 2); assert_eq!(counter, 2);
let (status, counter) = blockstore let (status, counter) = blockstore
.get_transaction_status_with_counter(signature3, false) .get_transaction_status_with_counter(signature3, &[3])
.unwrap(); .unwrap();
assert_eq!(status, None); assert_eq!(status, None);
assert_eq!(counter, 2); assert_eq!(counter, 2);
// Signature does not exist, larger than existing entries // Signature does not exist, larger than existing entries
let (status, counter) = blockstore let (status, counter) = blockstore
.get_transaction_status_with_counter(signature6, true) .get_transaction_status_with_counter(signature7, &[])
.unwrap(); .unwrap();
assert_eq!(status, None); assert_eq!(status, None);
assert_eq!(counter, 2); assert_eq!(counter, 2);
let (status, counter) = blockstore let (status, counter) = blockstore
.get_transaction_status_with_counter(signature6, false) .get_transaction_status_with_counter(signature7, &[3])
.unwrap(); .unwrap();
assert_eq!(status, None); assert_eq!(status, None);
assert_eq!(counter, 2); assert_eq!(counter, 2);
@ -6431,7 +6483,7 @@ pub mod tests {
} }
#[test] #[test]
fn test_get_confirmed_transaction() { fn test_get_rooted_transaction() {
let slot = 2; let slot = 2;
let entries = make_slot_entries_with_transactions(5); let entries = make_slot_entries_with_transactions(5);
let shreds = entries_to_test_shreds(entries.clone(), slot, slot - 1, true, 0); let shreds = entries_to_test_shreds(entries.clone(), slot, slot - 1, true, 0);
@ -6494,7 +6546,7 @@ pub mod tests {
for transaction in expected_transactions.clone() { for transaction in expected_transactions.clone() {
let signature = transaction.transaction.signatures[0]; let signature = transaction.transaction.signatures[0];
assert_eq!( assert_eq!(
blockstore.get_confirmed_transaction(signature).unwrap(), blockstore.get_rooted_transaction(signature).unwrap(),
Some(ConfirmedTransaction { Some(ConfirmedTransaction {
slot, slot,
transaction: transaction.clone(), transaction: transaction.clone(),
@ -6502,7 +6554,9 @@ pub mod tests {
}) })
); );
assert_eq!( assert_eq!(
blockstore.get_complete_transaction(signature).unwrap(), blockstore
.get_complete_transaction(signature, slot + 1)
.unwrap(),
Some(ConfirmedTransaction { Some(ConfirmedTransaction {
slot, slot,
transaction, transaction,
@ -6515,12 +6569,11 @@ pub mod tests {
*blockstore.lowest_cleanup_slot.write().unwrap() = slot; *blockstore.lowest_cleanup_slot.write().unwrap() = slot;
for TransactionWithStatusMeta { transaction, .. } in expected_transactions { for TransactionWithStatusMeta { transaction, .. } in expected_transactions {
let signature = transaction.signatures[0]; let signature = transaction.signatures[0];
assert_eq!(blockstore.get_rooted_transaction(signature).unwrap(), None,);
assert_eq!( assert_eq!(
blockstore.get_confirmed_transaction(signature).unwrap(), blockstore
None, .get_complete_transaction(signature, slot + 1)
); .unwrap(),
assert_eq!(
blockstore.get_complete_transaction(signature).unwrap(),
None, None,
); );
} }
@ -6534,7 +6587,6 @@ pub mod tests {
let ledger_path = get_tmp_ledger_path!(); let ledger_path = get_tmp_ledger_path!();
let blockstore = Blockstore::open(&ledger_path).unwrap(); let blockstore = Blockstore::open(&ledger_path).unwrap();
blockstore.insert_shreds(shreds, None, false).unwrap(); blockstore.insert_shreds(shreds, None, false).unwrap();
// blockstore.set_roots(&[slot - 1, slot]).unwrap();
let expected_transactions: Vec<TransactionWithStatusMeta> = entries let expected_transactions: Vec<TransactionWithStatusMeta> = entries
.iter() .iter()
@ -6590,17 +6642,16 @@ pub mod tests {
for transaction in expected_transactions.clone() { for transaction in expected_transactions.clone() {
let signature = transaction.transaction.signatures[0]; let signature = transaction.transaction.signatures[0];
assert_eq!( assert_eq!(
blockstore.get_complete_transaction(signature).unwrap(), blockstore
.get_complete_transaction(signature, slot)
.unwrap(),
Some(ConfirmedTransaction { Some(ConfirmedTransaction {
slot, slot,
transaction, transaction,
block_time: None block_time: None
}) })
); );
assert_eq!( assert_eq!(blockstore.get_rooted_transaction(signature).unwrap(), None);
blockstore.get_confirmed_transaction(signature).unwrap(),
None
);
} }
blockstore.run_purge(0, 2, PurgeType::PrimaryIndex).unwrap(); blockstore.run_purge(0, 2, PurgeType::PrimaryIndex).unwrap();
@ -6608,13 +6659,12 @@ pub mod tests {
for TransactionWithStatusMeta { transaction, .. } in expected_transactions { for TransactionWithStatusMeta { transaction, .. } in expected_transactions {
let signature = transaction.signatures[0]; let signature = transaction.signatures[0];
assert_eq!( assert_eq!(
blockstore.get_complete_transaction(signature).unwrap(), blockstore
None, .get_complete_transaction(signature, slot)
); .unwrap(),
assert_eq!(
blockstore.get_confirmed_transaction(signature).unwrap(),
None, None,
); );
assert_eq!(blockstore.get_rooted_transaction(signature).unwrap(), None,);
} }
} }
@ -6625,7 +6675,7 @@ pub mod tests {
blockstore.set_roots(&[0]).unwrap(); blockstore.set_roots(&[0]).unwrap();
assert_eq!( assert_eq!(
blockstore blockstore
.get_confirmed_transaction(Signature::default()) .get_rooted_transaction(Signature::default())
.unwrap(), .unwrap(),
None None
); );