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:
parent
18bd47dbe1
commit
da27acabcc
|
@ -24,9 +24,9 @@ use solana_client::{
|
|||
pubsub_client::PubsubClient,
|
||||
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
|
||||
rpc_config::{
|
||||
RpcAccountInfoConfig, RpcConfirmedBlockConfig, RpcLargestAccountsConfig,
|
||||
RpcLargestAccountsFilter, RpcProgramAccountsConfig, RpcTransactionLogsConfig,
|
||||
RpcTransactionLogsFilter,
|
||||
RpcAccountInfoConfig, RpcConfirmedBlockConfig, RpcConfirmedTransactionConfig,
|
||||
RpcLargestAccountsConfig, RpcLargestAccountsFilter, RpcProgramAccountsConfig,
|
||||
RpcTransactionLogsConfig, RpcTransactionLogsFilter,
|
||||
},
|
||||
rpc_filter,
|
||||
rpc_response::SlotInfo,
|
||||
|
@ -1826,6 +1826,7 @@ pub fn process_transaction_history(
|
|||
before,
|
||||
until,
|
||||
limit: Some(limit),
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
},
|
||||
)?;
|
||||
|
||||
|
@ -1842,9 +1843,13 @@ pub fn process_transaction_history(
|
|||
Some(block_time) =>
|
||||
format!("timestamp={} ", unix_timestamp_to_string(block_time)),
|
||||
},
|
||||
match result.err {
|
||||
None => "Confirmed".to_string(),
|
||||
Some(err) => format!("Failed: {:?}", err),
|
||||
if let Some(err) = result.err {
|
||||
format!("Failed: {:?}", err)
|
||||
} else {
|
||||
match result.confirmation_status {
|
||||
None => "Finalized".to_string(),
|
||||
Some(status) => format!("{:?}", status),
|
||||
}
|
||||
},
|
||||
result.memo.unwrap_or_else(|| "".to_string()),
|
||||
);
|
||||
|
@ -1854,9 +1859,13 @@ pub fn process_transaction_history(
|
|||
|
||||
if show_transactions {
|
||||
if let Ok(signature) = result.signature.parse::<Signature>() {
|
||||
match rpc_client
|
||||
.get_confirmed_transaction(&signature, UiTransactionEncoding::Base64)
|
||||
{
|
||||
match rpc_client.get_confirmed_transaction_with_config(
|
||||
&signature,
|
||||
RpcConfirmedTransactionConfig {
|
||||
encoding: Some(UiTransactionEncoding::Base64),
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
},
|
||||
) {
|
||||
Ok(confirmed_transaction) => {
|
||||
println_transaction(
|
||||
&confirmed_transaction
|
||||
|
|
|
@ -652,6 +652,7 @@ impl RpcClient {
|
|||
before: config.before.map(|signature| signature.to_string()),
|
||||
until: config.until.map(|signature| signature.to_string()),
|
||||
limit: config.limit,
|
||||
commitment: config.commitment,
|
||||
};
|
||||
|
||||
let result: Vec<RpcConfirmedTransactionStatusWithSignature> = self.send(
|
||||
|
@ -1632,6 +1633,7 @@ pub struct GetConfirmedSignaturesForAddress2Config {
|
|||
pub before: Option<Signature>,
|
||||
pub until: Option<Signature>,
|
||||
pub limit: Option<usize>,
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
fn new_spinner_progress_bar() -> ProgressBar {
|
||||
|
|
|
@ -109,6 +109,8 @@ pub struct RpcGetConfirmedSignaturesForAddress2Config {
|
|||
pub before: Option<String>, // Signature as base-58 string
|
||||
pub until: Option<String>, // Signature as base-58 string
|
||||
pub limit: Option<usize>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
|
|
|
@ -7,7 +7,9 @@ use {
|
|||
inflation::Inflation,
|
||||
transaction::{Result, TransactionError},
|
||||
},
|
||||
solana_transaction_status::ConfirmedTransactionStatusWithSignature,
|
||||
solana_transaction_status::{
|
||||
ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus,
|
||||
},
|
||||
std::{collections::HashMap, fmt, net::SocketAddr},
|
||||
};
|
||||
|
||||
|
@ -348,6 +350,7 @@ pub struct RpcConfirmedTransactionStatusWithSignature {
|
|||
pub err: Option<TransactionError>,
|
||||
pub memo: Option<String>,
|
||||
pub block_time: Option<UnixTimestamp>,
|
||||
pub confirmation_status: Option<TransactionConfirmationStatus>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -374,6 +377,7 @@ impl From<ConfirmedTransactionStatusWithSignature> for RpcConfirmedTransactionSt
|
|||
err,
|
||||
memo,
|
||||
block_time,
|
||||
confirmation_status: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1163,23 +1163,27 @@ impl JsonRpcRequestProcessor {
|
|||
mut before: Option<Signature>,
|
||||
until: Option<Signature>,
|
||||
mut limit: usize,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>> {
|
||||
let commitment = commitment.unwrap_or_default();
|
||||
check_is_at_least_confirmed(commitment)?;
|
||||
|
||||
if self.config.enable_rpc_transaction_history {
|
||||
let highest_confirmed_root = self
|
||||
.block_commitment_cache
|
||||
.read()
|
||||
.unwrap()
|
||||
.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
|
||||
.blockstore
|
||||
.get_confirmed_signatures_for_address2(
|
||||
address,
|
||||
highest_confirmed_root,
|
||||
before,
|
||||
until,
|
||||
limit,
|
||||
)
|
||||
.get_confirmed_signatures_for_address2(address, highest_slot, before, until, limit)
|
||||
.map_err(|err| Error::invalid_params(format!("{}", err)))?;
|
||||
|
||||
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 {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
@ -2341,6 +2362,7 @@ pub mod rpc_full {
|
|||
config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>,
|
||||
) -> Result<Option<EncodedConfirmedTransaction>>;
|
||||
|
||||
// DEPRECATED
|
||||
#[rpc(meta, name = "getConfirmedSignaturesForAddress")]
|
||||
fn get_confirmed_signatures_for_address(
|
||||
&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> {
|
||||
|
|
|
@ -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.
|
||||
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.
|
||||
* (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment); "processed" is not supported. If parameter not provided, the default is "finalized".
|
||||
|
||||
#### Results:
|
||||
The result field will be an array of transaction signature information, ordered
|
||||
|
|
|
@ -2112,6 +2112,8 @@ impl Blockstore {
|
|||
// 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
|
||||
// the order in which the transactions exist in the block
|
||||
//
|
||||
// DEPRECATED
|
||||
fn find_address_signatures(
|
||||
&self,
|
||||
pubkey: Pubkey,
|
||||
|
@ -2143,6 +2145,40 @@ impl Blockstore {
|
|||
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(
|
||||
&self,
|
||||
pubkey: Pubkey,
|
||||
|
@ -2164,7 +2200,7 @@ impl Blockstore {
|
|||
pub fn get_confirmed_signatures_for_address2(
|
||||
&self,
|
||||
address: Pubkey,
|
||||
highest_confirmed_root: Slot,
|
||||
highest_slot: Slot, // highest_confirmed_root or highest_confirmed_slot
|
||||
before: Option<Signature>,
|
||||
until: Option<Signature>,
|
||||
limit: usize,
|
||||
|
@ -2177,28 +2213,31 @@ impl Blockstore {
|
|||
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
|
||||
// `before` signature if present. Also generate a HashSet of signatures that should
|
||||
// be excluded from the results.
|
||||
let mut get_before_slot_timer = Measure::start("get_before_slot_timer");
|
||||
let (slot, mut before_excluded_signatures) = match before {
|
||||
None => (highest_confirmed_root, None),
|
||||
None => (highest_slot, None),
|
||||
Some(before) => {
|
||||
let transaction_status = self.get_transaction_status(before, &[])?;
|
||||
let transaction_status =
|
||||
self.get_transaction_status(before, &confirmed_unrooted_slots)?;
|
||||
match transaction_status {
|
||||
None => return Ok(vec![]),
|
||||
Some((slot, _)) => {
|
||||
let confirmed_block =
|
||||
self.get_rooted_block(slot, false).map_err(|err| {
|
||||
BlockstoreError::Io(IoError::new(
|
||||
ErrorKind::Other,
|
||||
format!("Unable to get confirmed block: {}", err),
|
||||
))
|
||||
})?;
|
||||
let block = self.get_complete_block(slot, false).map_err(|err| {
|
||||
BlockstoreError::Io(IoError::new(
|
||||
ErrorKind::Other,
|
||||
format!("Unable to get block: {}", err),
|
||||
))
|
||||
})?;
|
||||
|
||||
// Load all signatures for the block
|
||||
let mut slot_signatures: Vec<_> = confirmed_block
|
||||
let mut slot_signatures: Vec<_> = block
|
||||
.transactions
|
||||
.into_iter()
|
||||
.filter_map(|transaction_with_meta| {
|
||||
|
@ -2236,20 +2275,20 @@ impl Blockstore {
|
|||
let (lowest_slot, until_excluded_signatures) = match until {
|
||||
None => (0, HashSet::new()),
|
||||
Some(until) => {
|
||||
let transaction_status = self.get_transaction_status(until, &[])?;
|
||||
let transaction_status =
|
||||
self.get_transaction_status(until, &confirmed_unrooted_slots)?;
|
||||
match transaction_status {
|
||||
None => (0, HashSet::new()),
|
||||
Some((slot, _)) => {
|
||||
let confirmed_block =
|
||||
self.get_rooted_block(slot, false).map_err(|err| {
|
||||
BlockstoreError::Io(IoError::new(
|
||||
ErrorKind::Other,
|
||||
format!("Unable to get confirmed block: {}", err),
|
||||
))
|
||||
})?;
|
||||
let block = self.get_complete_block(slot, false).map_err(|err| {
|
||||
BlockstoreError::Io(IoError::new(
|
||||
ErrorKind::Other,
|
||||
format!("Unable to get block: {}", err),
|
||||
))
|
||||
})?;
|
||||
|
||||
// Load all signatures for the block
|
||||
let mut slot_signatures: Vec<_> = confirmed_block
|
||||
let mut slot_signatures: Vec<_> = block
|
||||
.transactions
|
||||
.into_iter()
|
||||
.filter_map(|transaction_with_meta| {
|
||||
|
@ -2284,7 +2323,7 @@ impl Blockstore {
|
|||
|
||||
// Get signatures in `slot`
|
||||
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();
|
||||
if let Some(excluded_signatures) = before_excluded_signatures.take() {
|
||||
address_signatures.extend(
|
||||
|
@ -2324,7 +2363,7 @@ impl Blockstore {
|
|||
&& key_address == address
|
||||
&& slot >= first_available_block
|
||||
{
|
||||
if self.is_root(slot) {
|
||||
if self.is_root(slot) || confirmed_unrooted_slots.contains(&slot) {
|
||||
address_signatures.push((slot, signature));
|
||||
}
|
||||
continue;
|
||||
|
@ -2336,7 +2375,7 @@ impl Blockstore {
|
|||
// Handle slots that cross primary indexes
|
||||
if next_max_slot >= lowest_slot {
|
||||
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();
|
||||
address_signatures.append(&mut signatures);
|
||||
}
|
||||
|
@ -2362,7 +2401,7 @@ impl Blockstore {
|
|||
&& key_address == address
|
||||
&& slot >= first_available_block
|
||||
{
|
||||
if self.is_root(slot) {
|
||||
if self.is_root(slot) || confirmed_unrooted_slots.contains(&slot) {
|
||||
address_signatures.push((slot, signature));
|
||||
}
|
||||
continue;
|
||||
|
@ -2381,7 +2420,8 @@ impl Blockstore {
|
|||
let mut get_status_info_timer = Measure::start("get_status_info_timer");
|
||||
let mut infos = vec![];
|
||||
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 {
|
||||
None => None,
|
||||
Some((_slot, status)) => status.status.err(),
|
||||
|
@ -6821,6 +6861,96 @@ pub mod tests {
|
|||
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]
|
||||
fn test_get_confirmed_signatures_for_address2() {
|
||||
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
|
||||
blockstore.set_roots(&[1, 2, 4, 5, 6, 7, 8]).unwrap();
|
||||
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
|
||||
.get_confirmed_signatures_for_address2(
|
||||
address0,
|
||||
|
@ -6889,7 +7044,7 @@ pub mod tests {
|
|||
.unwrap();
|
||||
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
|
||||
.get_confirmed_signatures_for_address2(
|
||||
address1,
|
||||
|
@ -6901,8 +7056,6 @@ pub mod tests {
|
|||
.unwrap();
|
||||
assert_eq!(all1.len(), 12);
|
||||
|
||||
assert!(all0 != all1);
|
||||
|
||||
// Fetch all signatures for address 0 individually
|
||||
for i in 0..all0.len() {
|
||||
let results = blockstore
|
||||
|
@ -7035,6 +7188,170 @@ pub mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue