Rpc: enable getConfirmedSignaturesForAddress2 to return confirmed (not yet finalized) data (#16281)

* Update blockstore method to allow return of unfinalized signature

* Support confirmed sigs in getConfirmedSignaturesForAddress2

* Add deprecated comments

* Update docs

* Enable confirmed transaction-history in cli

* Return real confirmation_status; fill in not-yet-finalized block time if possible
This commit is contained in:
Tyera Eulberg
2021-03-31 22:35:57 -06:00
committed by GitHub
parent 18bd47dbe1
commit da27acabcc
7 changed files with 411 additions and 48 deletions

View File

@ -24,9 +24,9 @@ use solana_client::{
pubsub_client::PubsubClient, pubsub_client::PubsubClient,
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient}, rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
rpc_config::{ rpc_config::{
RpcAccountInfoConfig, RpcConfirmedBlockConfig, RpcLargestAccountsConfig, RpcAccountInfoConfig, RpcConfirmedBlockConfig, RpcConfirmedTransactionConfig,
RpcLargestAccountsFilter, RpcProgramAccountsConfig, RpcTransactionLogsConfig, RpcLargestAccountsConfig, RpcLargestAccountsFilter, RpcProgramAccountsConfig,
RpcTransactionLogsFilter, RpcTransactionLogsConfig, RpcTransactionLogsFilter,
}, },
rpc_filter, rpc_filter,
rpc_response::SlotInfo, rpc_response::SlotInfo,
@ -1826,6 +1826,7 @@ pub fn process_transaction_history(
before, before,
until, until,
limit: Some(limit), limit: Some(limit),
commitment: Some(CommitmentConfig::confirmed()),
}, },
)?; )?;
@ -1842,9 +1843,13 @@ pub fn process_transaction_history(
Some(block_time) => Some(block_time) =>
format!("timestamp={} ", unix_timestamp_to_string(block_time)), format!("timestamp={} ", unix_timestamp_to_string(block_time)),
}, },
match result.err { if let Some(err) = result.err {
None => "Confirmed".to_string(), format!("Failed: {:?}", err)
Some(err) => format!("Failed: {:?}", err), } else {
match result.confirmation_status {
None => "Finalized".to_string(),
Some(status) => format!("{:?}", status),
}
}, },
result.memo.unwrap_or_else(|| "".to_string()), result.memo.unwrap_or_else(|| "".to_string()),
); );
@ -1854,9 +1859,13 @@ pub fn process_transaction_history(
if show_transactions { if show_transactions {
if let Ok(signature) = result.signature.parse::<Signature>() { if let Ok(signature) = result.signature.parse::<Signature>() {
match rpc_client match rpc_client.get_confirmed_transaction_with_config(
.get_confirmed_transaction(&signature, UiTransactionEncoding::Base64) &signature,
{ RpcConfirmedTransactionConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(CommitmentConfig::confirmed()),
},
) {
Ok(confirmed_transaction) => { Ok(confirmed_transaction) => {
println_transaction( println_transaction(
&confirmed_transaction &confirmed_transaction

View File

@ -652,6 +652,7 @@ impl RpcClient {
before: config.before.map(|signature| signature.to_string()), before: config.before.map(|signature| signature.to_string()),
until: config.until.map(|signature| signature.to_string()), until: config.until.map(|signature| signature.to_string()),
limit: config.limit, limit: config.limit,
commitment: config.commitment,
}; };
let result: Vec<RpcConfirmedTransactionStatusWithSignature> = self.send( let result: Vec<RpcConfirmedTransactionStatusWithSignature> = self.send(
@ -1632,6 +1633,7 @@ pub struct GetConfirmedSignaturesForAddress2Config {
pub before: Option<Signature>, pub before: Option<Signature>,
pub until: Option<Signature>, pub until: Option<Signature>,
pub limit: Option<usize>, pub limit: Option<usize>,
pub commitment: Option<CommitmentConfig>,
} }
fn new_spinner_progress_bar() -> ProgressBar { fn new_spinner_progress_bar() -> ProgressBar {

View File

@ -109,6 +109,8 @@ pub struct RpcGetConfirmedSignaturesForAddress2Config {
pub before: Option<String>, // Signature as base-58 string pub before: Option<String>, // Signature as base-58 string
pub until: Option<String>, // Signature as base-58 string pub until: Option<String>, // Signature as base-58 string
pub limit: Option<usize>, pub limit: Option<usize>,
#[serde(flatten)]
pub commitment: Option<CommitmentConfig>,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]

View File

@ -7,7 +7,9 @@ use {
inflation::Inflation, inflation::Inflation,
transaction::{Result, TransactionError}, transaction::{Result, TransactionError},
}, },
solana_transaction_status::ConfirmedTransactionStatusWithSignature, solana_transaction_status::{
ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus,
},
std::{collections::HashMap, fmt, net::SocketAddr}, std::{collections::HashMap, fmt, net::SocketAddr},
}; };
@ -348,6 +350,7 @@ pub struct RpcConfirmedTransactionStatusWithSignature {
pub err: Option<TransactionError>, pub err: Option<TransactionError>,
pub memo: Option<String>, pub memo: Option<String>,
pub block_time: Option<UnixTimestamp>, pub block_time: Option<UnixTimestamp>,
pub confirmation_status: Option<TransactionConfirmationStatus>,
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -374,6 +377,7 @@ impl From<ConfirmedTransactionStatusWithSignature> for RpcConfirmedTransactionSt
err, err,
memo, memo,
block_time, block_time,
confirmation_status: None,
} }
} }
} }

View File

@ -1163,23 +1163,27 @@ impl JsonRpcRequestProcessor {
mut before: Option<Signature>, mut before: Option<Signature>,
until: Option<Signature>, until: Option<Signature>,
mut limit: usize, mut limit: usize,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>> { ) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>> {
let commitment = commitment.unwrap_or_default();
check_is_at_least_confirmed(commitment)?;
if self.config.enable_rpc_transaction_history { if self.config.enable_rpc_transaction_history {
let highest_confirmed_root = self let highest_confirmed_root = self
.block_commitment_cache .block_commitment_cache
.read() .read()
.unwrap() .unwrap()
.highest_confirmed_root(); .highest_confirmed_root();
let highest_slot = if commitment.is_confirmed() {
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
confirmed_bank.slot()
} else {
highest_confirmed_root
};
let mut results = self let mut results = self
.blockstore .blockstore
.get_confirmed_signatures_for_address2( .get_confirmed_signatures_for_address2(address, highest_slot, before, until, limit)
address,
highest_confirmed_root,
before,
until,
limit,
)
.map_err(|err| Error::invalid_params(format!("{}", err)))?; .map_err(|err| Error::invalid_params(format!("{}", err)))?;
if results.len() < limit { if results.len() < limit {
@ -1208,7 +1212,24 @@ impl JsonRpcRequestProcessor {
} }
} }
Ok(results.into_iter().map(|x| x.into()).collect()) Ok(results
.into_iter()
.map(|x| {
let mut item: RpcConfirmedTransactionStatusWithSignature = x.into();
if item.slot <= highest_confirmed_root {
item.confirmation_status = Some(TransactionConfirmationStatus::Finalized);
} else {
item.confirmation_status = Some(TransactionConfirmationStatus::Confirmed);
if item.block_time.is_none() {
let r_bank_forks = self.bank_forks.read().unwrap();
item.block_time = r_bank_forks
.get(item.slot)
.map(|bank| bank.clock().unix_timestamp);
}
}
item
})
.collect())
} else { } else {
Ok(vec![]) Ok(vec![])
} }
@ -2341,6 +2362,7 @@ pub mod rpc_full {
config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>, config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>,
) -> Result<Option<EncodedConfirmedTransaction>>; ) -> Result<Option<EncodedConfirmedTransaction>>;
// DEPRECATED
#[rpc(meta, name = "getConfirmedSignaturesForAddress")] #[rpc(meta, name = "getConfirmedSignaturesForAddress")]
fn get_confirmed_signatures_for_address( fn get_confirmed_signatures_for_address(
&self, &self,
@ -3087,7 +3109,13 @@ pub mod rpc_full {
))); )));
} }
meta.get_confirmed_signatures_for_address2(address, before, until, limit) meta.get_confirmed_signatures_for_address2(
address,
before,
until,
limit,
config.commitment,
)
} }
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot> { fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot> {

View File

@ -803,6 +803,7 @@ address backwards in time from the provided signature or most recent confirmed b
* `before: <string>` - (optional) start searching backwards from this transaction signature. * `before: <string>` - (optional) start searching backwards from this transaction signature.
If not provided the search starts from the top of the highest max confirmed block. If not provided the search starts from the top of the highest max confirmed block.
* `until: <string>` - (optional) search until this transaction signature, if found before limit reached. * `until: <string>` - (optional) search until this transaction signature, if found before limit reached.
* (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment); "processed" is not supported. If parameter not provided, the default is "finalized".
#### Results: #### Results:
The result field will be an array of transaction signature information, ordered The result field will be an array of transaction signature information, ordered

View File

@ -2112,6 +2112,8 @@ impl Blockstore {
// Returns all rooted signatures for an address, ordered by slot that the transaction was // Returns all rooted signatures for an address, ordered by slot that the transaction was
// processed in. Within each slot the transactions will be ordered by signature, and NOT by // processed in. Within each slot the transactions will be ordered by signature, and NOT by
// the order in which the transactions exist in the block // the order in which the transactions exist in the block
//
// DEPRECATED
fn find_address_signatures( fn find_address_signatures(
&self, &self,
pubkey: Pubkey, pubkey: Pubkey,
@ -2143,6 +2145,40 @@ impl Blockstore {
Ok(signatures) Ok(signatures)
} }
// Returns all signatures for an address in a particular slot, regardless of whether that slot
// has been rooted. The transactions will be ordered by signature, and NOT by the order in
// which the transactions exist in the block
fn find_address_signatures_for_slot(
&self,
pubkey: Pubkey,
slot: Slot,
) -> Result<Vec<(Slot, Signature)>> {
let mut signatures: Vec<(Slot, Signature)> = vec![];
for transaction_status_cf_primary_index in 0..=1 {
let index_iterator = self.address_signatures_cf.iter(IteratorMode::From(
(
transaction_status_cf_primary_index,
pubkey,
slot,
Signature::default(),
),
IteratorDirection::Forward,
))?;
for ((i, address, transaction_slot, signature), _) in index_iterator {
if i != transaction_status_cf_primary_index
|| transaction_slot > slot
|| address != pubkey
{
break;
}
signatures.push((slot, signature));
}
}
signatures.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap().then(a.1.cmp(&b.1)));
Ok(signatures)
}
// DEPRECATED
pub fn get_confirmed_signatures_for_address( pub fn get_confirmed_signatures_for_address(
&self, &self,
pubkey: Pubkey, pubkey: Pubkey,
@ -2164,7 +2200,7 @@ impl Blockstore {
pub fn get_confirmed_signatures_for_address2( pub fn get_confirmed_signatures_for_address2(
&self, &self,
address: Pubkey, address: Pubkey,
highest_confirmed_root: Slot, highest_slot: Slot, // highest_confirmed_root or highest_confirmed_slot
before: Option<Signature>, before: Option<Signature>,
until: Option<Signature>, until: Option<Signature>,
limit: usize, limit: usize,
@ -2177,28 +2213,31 @@ impl Blockstore {
String String
) )
); );
let confirmed_unrooted_slots: Vec<_> = AncestorIterator::new_inclusive(highest_slot, self)
.filter(|&slot| slot > self.last_root())
.collect();
// Figure the `slot` to start listing signatures at, based on the ledger location of the // Figure the `slot` to start listing signatures at, based on the ledger location of the
// `before` signature if present. Also generate a HashSet of signatures that should // `before` signature if present. Also generate a HashSet of signatures that should
// be excluded from the results. // be excluded from the results.
let mut get_before_slot_timer = Measure::start("get_before_slot_timer"); let mut get_before_slot_timer = Measure::start("get_before_slot_timer");
let (slot, mut before_excluded_signatures) = match before { let (slot, mut before_excluded_signatures) = match before {
None => (highest_confirmed_root, None), None => (highest_slot, None),
Some(before) => { Some(before) => {
let transaction_status = self.get_transaction_status(before, &[])?; let transaction_status =
self.get_transaction_status(before, &confirmed_unrooted_slots)?;
match transaction_status { match transaction_status {
None => return Ok(vec![]), None => return Ok(vec![]),
Some((slot, _)) => { Some((slot, _)) => {
let confirmed_block = let block = self.get_complete_block(slot, false).map_err(|err| {
self.get_rooted_block(slot, false).map_err(|err| {
BlockstoreError::Io(IoError::new( BlockstoreError::Io(IoError::new(
ErrorKind::Other, ErrorKind::Other,
format!("Unable to get confirmed block: {}", err), format!("Unable to get block: {}", err),
)) ))
})?; })?;
// Load all signatures for the block // Load all signatures for the block
let mut slot_signatures: Vec<_> = confirmed_block let mut slot_signatures: Vec<_> = block
.transactions .transactions
.into_iter() .into_iter()
.filter_map(|transaction_with_meta| { .filter_map(|transaction_with_meta| {
@ -2236,20 +2275,20 @@ 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, &[])?; let transaction_status =
self.get_transaction_status(until, &confirmed_unrooted_slots)?;
match transaction_status { match transaction_status {
None => (0, HashSet::new()), None => (0, HashSet::new()),
Some((slot, _)) => { Some((slot, _)) => {
let confirmed_block = let block = self.get_complete_block(slot, false).map_err(|err| {
self.get_rooted_block(slot, false).map_err(|err| {
BlockstoreError::Io(IoError::new( BlockstoreError::Io(IoError::new(
ErrorKind::Other, ErrorKind::Other,
format!("Unable to get confirmed block: {}", err), format!("Unable to get block: {}", err),
)) ))
})?; })?;
// Load all signatures for the block // Load all signatures for the block
let mut slot_signatures: Vec<_> = confirmed_block let mut slot_signatures: Vec<_> = block
.transactions .transactions
.into_iter() .into_iter()
.filter_map(|transaction_with_meta| { .filter_map(|transaction_with_meta| {
@ -2284,7 +2323,7 @@ impl Blockstore {
// Get signatures in `slot` // Get signatures in `slot`
let mut get_initial_slot_timer = Measure::start("get_initial_slot_timer"); let mut get_initial_slot_timer = Measure::start("get_initial_slot_timer");
let mut signatures = self.find_address_signatures(address, slot, slot)?; let mut signatures = self.find_address_signatures_for_slot(address, slot)?;
signatures.reverse(); signatures.reverse();
if let Some(excluded_signatures) = before_excluded_signatures.take() { if let Some(excluded_signatures) = before_excluded_signatures.take() {
address_signatures.extend( address_signatures.extend(
@ -2324,7 +2363,7 @@ impl Blockstore {
&& key_address == address && key_address == address
&& slot >= first_available_block && slot >= first_available_block
{ {
if self.is_root(slot) { if self.is_root(slot) || confirmed_unrooted_slots.contains(&slot) {
address_signatures.push((slot, signature)); address_signatures.push((slot, signature));
} }
continue; continue;
@ -2336,7 +2375,7 @@ impl Blockstore {
// Handle slots that cross primary indexes // Handle slots that cross primary indexes
if next_max_slot >= lowest_slot { if next_max_slot >= lowest_slot {
let mut signatures = let mut signatures =
self.find_address_signatures(address, next_max_slot, next_max_slot)?; self.find_address_signatures_for_slot(address, next_max_slot)?;
signatures.reverse(); signatures.reverse();
address_signatures.append(&mut signatures); address_signatures.append(&mut signatures);
} }
@ -2362,7 +2401,7 @@ impl Blockstore {
&& key_address == address && key_address == address
&& slot >= first_available_block && slot >= first_available_block
{ {
if self.is_root(slot) { if self.is_root(slot) || confirmed_unrooted_slots.contains(&slot) {
address_signatures.push((slot, signature)); address_signatures.push((slot, signature));
} }
continue; continue;
@ -2381,7 +2420,8 @@ 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, &[])?; let transaction_status =
self.get_transaction_status(signature, &confirmed_unrooted_slots)?;
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(),
@ -6821,6 +6861,96 @@ pub mod tests {
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction"); Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
} }
#[test]
fn test_find_address_signatures_for_slot() {
let blockstore_path = get_tmp_ledger_path!();
{
let blockstore = Blockstore::open(&blockstore_path).unwrap();
let address0 = solana_sdk::pubkey::new_rand();
let address1 = solana_sdk::pubkey::new_rand();
let slot1 = 1;
for x in 1..5 {
let signature = Signature::new(&[x; 64]);
blockstore
.write_transaction_status(
slot1,
signature,
vec![&address0],
vec![&address1],
TransactionStatusMeta::default(),
)
.unwrap();
}
let slot2 = 2;
for x in 5..7 {
let signature = Signature::new(&[x; 64]);
blockstore
.write_transaction_status(
slot2,
signature,
vec![&address0],
vec![&address1],
TransactionStatusMeta::default(),
)
.unwrap();
}
// Purge to freeze index 0
blockstore.run_purge(0, 1, PurgeType::PrimaryIndex).unwrap();
for x in 7..9 {
let signature = Signature::new(&[x; 64]);
blockstore
.write_transaction_status(
slot2,
signature,
vec![&address0],
vec![&address1],
TransactionStatusMeta::default(),
)
.unwrap();
}
let slot3 = 3;
for x in 9..13 {
let signature = Signature::new(&[x; 64]);
blockstore
.write_transaction_status(
slot3,
signature,
vec![&address0],
vec![&address1],
TransactionStatusMeta::default(),
)
.unwrap();
}
blockstore.set_roots(&[slot1]).unwrap();
let slot1_signatures = blockstore
.find_address_signatures_for_slot(address0, 1)
.unwrap();
for (i, (slot, signature)) in slot1_signatures.iter().enumerate() {
assert_eq!(*slot, slot1);
assert_eq!(*signature, Signature::new(&[i as u8 + 1; 64]));
}
let slot2_signatures = blockstore
.find_address_signatures_for_slot(address0, 2)
.unwrap();
for (i, (slot, signature)) in slot2_signatures.iter().enumerate() {
assert_eq!(*slot, slot2);
assert_eq!(*signature, Signature::new(&[i as u8 + 5; 64]));
}
let slot3_signatures = blockstore
.find_address_signatures_for_slot(address0, 3)
.unwrap();
for (i, (slot, signature)) in slot3_signatures.iter().enumerate() {
assert_eq!(*slot, slot3);
assert_eq!(*signature, Signature::new(&[i as u8 + 9; 64]));
}
}
}
#[test] #[test]
fn test_get_confirmed_signatures_for_address2() { fn test_get_confirmed_signatures_for_address2() {
let blockstore_path = get_tmp_ledger_path!(); let blockstore_path = get_tmp_ledger_path!();
@ -6873,11 +7003,36 @@ pub mod tests {
} }
} }
} }
// Add 2 slots that both descend from slot 8
for slot in 9..=10 {
let entries = make_slot_entries_with_transaction_addresses(&[
address0, address1, address0, address1,
]);
let shreds = entries_to_test_shreds(entries.clone(), slot, 8, true, 0);
blockstore.insert_shreds(shreds, None, false).unwrap();
for entry in entries.iter() {
for transaction in &entry.transactions {
assert_eq!(transaction.signatures.len(), 1);
blockstore
.write_transaction_status(
slot,
transaction.signatures[0],
transaction.message.account_keys.iter().collect(),
vec![],
TransactionStatusMeta::default(),
)
.unwrap();
}
}
}
// Leave one slot unrooted to test only returns confirmed signatures // Leave one slot unrooted to test only returns confirmed signatures
blockstore.set_roots(&[1, 2, 4, 5, 6, 7, 8]).unwrap(); blockstore.set_roots(&[1, 2, 4, 5, 6, 7, 8]).unwrap();
let highest_confirmed_root = 8; let highest_confirmed_root = 8;
// Fetch all signatures for address 0 at once... // Fetch all rooted signatures for address 0 at once...
let all0 = blockstore let all0 = blockstore
.get_confirmed_signatures_for_address2( .get_confirmed_signatures_for_address2(
address0, address0,
@ -6889,7 +7044,7 @@ pub mod tests {
.unwrap(); .unwrap();
assert_eq!(all0.len(), 12); assert_eq!(all0.len(), 12);
// Fetch all signatures for address 1 at once... // Fetch all rooted signatures for address 1 at once...
let all1 = blockstore let all1 = blockstore
.get_confirmed_signatures_for_address2( .get_confirmed_signatures_for_address2(
address1, address1,
@ -6901,8 +7056,6 @@ pub mod tests {
.unwrap(); .unwrap();
assert_eq!(all1.len(), 12); assert_eq!(all1.len(), 12);
assert!(all0 != all1);
// Fetch all signatures for address 0 individually // Fetch all signatures for address 0 individually
for i in 0..all0.len() { for i in 0..all0.len() {
let results = blockstore let results = blockstore
@ -7035,6 +7188,170 @@ pub mod tests {
) )
.unwrap(); .unwrap();
assert!(results2.len() < results.len()); assert!(results2.len() < results.len());
// Duplicate all tests using confirmed signatures
let highest_confirmed_slot = 10;
// Fetch all signatures for address 0 at once...
let all0 = blockstore
.get_confirmed_signatures_for_address2(
address0,
highest_confirmed_slot,
None,
None,
usize::MAX,
)
.unwrap();
assert_eq!(all0.len(), 14);
// Fetch all signatures for address 1 at once...
let all1 = blockstore
.get_confirmed_signatures_for_address2(
address1,
highest_confirmed_slot,
None,
None,
usize::MAX,
)
.unwrap();
assert_eq!(all1.len(), 14);
// Fetch all signatures for address 0 individually
for i in 0..all0.len() {
let results = blockstore
.get_confirmed_signatures_for_address2(
address0,
highest_confirmed_slot,
if i == 0 {
None
} else {
Some(all0[i - 1].signature)
},
None,
1,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], all0[i], "Unexpected result for {}", i);
}
// Fetch all signatures for address 0 individually using `until`
for i in 0..all0.len() {
let results = blockstore
.get_confirmed_signatures_for_address2(
address0,
highest_confirmed_slot,
if i == 0 {
None
} else {
Some(all0[i - 1].signature)
},
if i == all0.len() - 1 || i == all0.len() {
None
} else {
Some(all0[i + 1].signature)
},
10,
)
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], all0[i], "Unexpected result for {}", i);
}
assert!(blockstore
.get_confirmed_signatures_for_address2(
address0,
highest_confirmed_slot,
Some(all0[all0.len() - 1].signature),
None,
1,
)
.unwrap()
.is_empty());
assert!(blockstore
.get_confirmed_signatures_for_address2(
address0,
highest_confirmed_slot,
None,
Some(all0[0].signature),
2,
)
.unwrap()
.is_empty());
// Fetch all signatures for address 0, three at a time
assert!(all0.len() % 3 == 2);
for i in (0..all0.len()).step_by(3) {
let results = blockstore
.get_confirmed_signatures_for_address2(
address0,
highest_confirmed_slot,
if i == 0 {
None
} else {
Some(all0[i - 1].signature)
},
None,
3,
)
.unwrap();
if i < 12 {
assert_eq!(results.len(), 3);
assert_eq!(results[2], all0[i + 2]);
} else {
assert_eq!(results.len(), 2);
}
assert_eq!(results[0], all0[i]);
assert_eq!(results[1], all0[i + 1]);
}
// Ensure that the signatures within a slot are reverse ordered by signature
// (current limitation of the .get_confirmed_signatures_for_address2())
for i in (0..all1.len()).step_by(2) {
let results = blockstore
.get_confirmed_signatures_for_address2(
address1,
highest_confirmed_slot,
if i == 0 {
None
} else {
Some(all1[i - 1].signature)
},
None,
2,
)
.unwrap();
assert_eq!(results.len(), 2);
assert_eq!(results[0].slot, results[1].slot);
assert!(results[0].signature >= results[1].signature);
assert_eq!(results[0], all1[i]);
assert_eq!(results[1], all1[i + 1]);
}
// A search for address 0 with `before` and/or `until` signatures from address1 should also work
let results = blockstore
.get_confirmed_signatures_for_address2(
address0,
highest_confirmed_slot,
Some(all1[0].signature),
None,
usize::MAX,
)
.unwrap();
// The exact number of results returned is variable, based on the sort order of the
// random signatures that are generated
assert!(!results.is_empty());
let results2 = blockstore
.get_confirmed_signatures_for_address2(
address0,
highest_confirmed_slot,
Some(all1[0].signature),
Some(all1[4].signature),
usize::MAX,
)
.unwrap();
assert!(results2.len() < results.len());
} }
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction"); Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
} }