From 4a465fd6d8c85e7dd9ff1e0a61c3c042bf7ba174 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 9 Apr 2020 12:36:03 -0600 Subject: [PATCH 1/6] Fix AddressSignatures to enable multiple sigs per slot --- ledger/src/blockstore.rs | 48 +++++++++++++++-------------------- ledger/src/blockstore_db.rs | 14 +++++----- ledger/src/blockstore_meta.rs | 3 +-- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 647a9719084032..80992d84bdb9a8 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -1667,20 +1667,14 @@ impl Blockstore { .put((primary_index, signature, slot), status)?; for address in writable_keys { self.address_signatures_cf.put( - (primary_index, *address, slot), - &AddressSignatureMeta { - signature, - writeable: true, - }, + (primary_index, *address, slot, signature), + &AddressSignatureMeta { writeable: true }, )?; } for address in readonly_keys { self.address_signatures_cf.put( - (primary_index, *address, slot), - &AddressSignatureMeta { - signature, - writeable: false, - }, + (primary_index, *address, slot, signature), + &AddressSignatureMeta { writeable: false }, )?; } Ok(()) @@ -2892,7 +2886,7 @@ pub mod tests { .iter::(IteratorMode::Start) .unwrap() .next() - .map(|((primary_index, _, slot), _)| { + .map(|((primary_index, _, slot, _), _)| { slot >= min_slot || (primary_index == 2 && slot == 0) }) .unwrap_or(true) @@ -5520,7 +5514,7 @@ pub mod tests { let first_status_entry = blockstore .db .iter::(IteratorMode::From( - (0, Signature::default(), 0), + cf::TransactionStatus::as_index(0), IteratorDirection::Forward, )) .unwrap() @@ -5532,7 +5526,7 @@ pub mod tests { let first_address_entry = blockstore .db .iter::(IteratorMode::From( - (0, Pubkey::default(), 0), + cf::AddressSignatures::as_index(0), IteratorDirection::Forward, )) .unwrap() @@ -5590,7 +5584,7 @@ pub mod tests { let first_status_entry = blockstore .db .iter::(IteratorMode::From( - (0, Signature::default(), 0), + cf::TransactionStatus::as_index(0), IteratorDirection::Forward, )) .unwrap() @@ -5602,7 +5596,7 @@ pub mod tests { let first_address_entry = blockstore .db .iter::(IteratorMode::From( - (0, Pubkey::default(), 0), + cf::AddressSignatures::as_index(0), IteratorDirection::Forward, )) .unwrap() @@ -5615,7 +5609,7 @@ pub mod tests { let index1_first_status_entry = blockstore .db .iter::(IteratorMode::From( - (1, Signature::default(), 0), + cf::TransactionStatus::as_index(1), IteratorDirection::Forward, )) .unwrap() @@ -5627,7 +5621,7 @@ pub mod tests { let index1_first_address_entry = blockstore .db .iter::(IteratorMode::From( - (1, Pubkey::default(), 0), + cf::AddressSignatures::as_index(1), IteratorDirection::Forward, )) .unwrap() @@ -5658,7 +5652,7 @@ pub mod tests { let first_status_entry = blockstore .db .iter::(IteratorMode::From( - (0, Signature::default(), 0), + cf::TransactionStatus::as_index(0), IteratorDirection::Forward, )) .unwrap() @@ -5670,7 +5664,7 @@ pub mod tests { let first_address_entry = blockstore .db .iter::(IteratorMode::From( - (0, Pubkey::default(), 0), + cf::AddressSignatures::as_index(0), IteratorDirection::Forward, )) .unwrap() @@ -5707,7 +5701,7 @@ pub mod tests { let mut status_entry_iterator = blockstore .db .iter::(IteratorMode::From( - (0, Signature::default(), 0), + cf::TransactionStatus::as_index(0), IteratorDirection::Forward, )) .unwrap(); @@ -5719,7 +5713,7 @@ pub mod tests { let mut address_transactions_iterator = blockstore .db .iter::(IteratorMode::From( - (0, Pubkey::default(), 0), + (0, Pubkey::default(), 0, Signature::default()), IteratorDirection::Forward, )) .unwrap(); @@ -5741,7 +5735,7 @@ pub mod tests { let mut status_entry_iterator = blockstore .db .iter::(IteratorMode::From( - (0, Signature::default(), 0), + cf::TransactionStatus::as_index(0), IteratorDirection::Forward, )) .unwrap(); @@ -5753,7 +5747,7 @@ pub mod tests { let mut address_transactions_iterator = blockstore .db .iter::(IteratorMode::From( - (0, Pubkey::default(), 0), + cf::AddressSignatures::as_index(0), IteratorDirection::Forward, )) .unwrap(); @@ -5775,7 +5769,7 @@ pub mod tests { let mut status_entry_iterator = blockstore .db .iter::(IteratorMode::From( - (0, Signature::default(), 0), + cf::TransactionStatus::as_index(0), IteratorDirection::Forward, )) .unwrap(); @@ -5787,7 +5781,7 @@ pub mod tests { let mut address_transactions_iterator = blockstore .db .iter::(IteratorMode::From( - (0, Pubkey::default(), 0), + cf::AddressSignatures::as_index(0), IteratorDirection::Forward, )) .unwrap(); @@ -5808,7 +5802,7 @@ pub mod tests { let mut status_entry_iterator = blockstore .db .iter::(IteratorMode::From( - (0, Signature::default(), 0), + cf::TransactionStatus::as_index(0), IteratorDirection::Forward, )) .unwrap(); @@ -5819,7 +5813,7 @@ pub mod tests { let mut address_transactions_iterator = blockstore .db .iter::(IteratorMode::From( - (0, Pubkey::default(), 0), + cf::AddressSignatures::as_index(0), IteratorDirection::Forward, )) .unwrap(); diff --git a/ledger/src/blockstore_db.rs b/ledger/src/blockstore_db.rs index 90bf4e7746a37d..9f6519d4ba1fb7 100644 --- a/ledger/src/blockstore_db.rs +++ b/ledger/src/blockstore_db.rs @@ -356,21 +356,23 @@ impl ColumnName for columns::TransactionStatus { } impl Column for columns::AddressSignatures { - type Index = (u64, Pubkey, Slot); + type Index = (u64, Pubkey, Slot, Signature); - fn key((index, pubkey, slot): (u64, Pubkey, Slot)) -> Vec { - let mut key = vec![0; 8 + 32 + 8]; // size_of u64 + size_of Pubkey + size_of Slot + fn key((index, pubkey, slot, signature): (u64, Pubkey, Slot, Signature)) -> Vec { + let mut key = vec![0; 8 + 32 + 8 + 64]; // size_of u64 + size_of Pubkey + size_of Slot + size_of Signature BigEndian::write_u64(&mut key[0..8], index); key[8..40].clone_from_slice(&pubkey.as_ref()[0..32]); BigEndian::write_u64(&mut key[40..48], slot); + key[48..112].clone_from_slice(&signature.as_ref()[0..64]); key } - fn index(key: &[u8]) -> (u64, Pubkey, Slot) { + fn index(key: &[u8]) -> (u64, Pubkey, Slot, Signature) { let index = BigEndian::read_u64(&key[0..8]); let pubkey = Pubkey::new(&key[8..40]); let slot = BigEndian::read_u64(&key[40..48]); - (index, pubkey, slot) + let signature = Signature::new(&key[48..112]); + (index, pubkey, slot, signature) } fn primary_index(index: Self::Index) -> u64 { @@ -378,7 +380,7 @@ impl Column for columns::AddressSignatures { } fn as_index(index: u64) -> Self::Index { - (index, Pubkey::default(), 0) + (index, Pubkey::default(), 0, Signature::default()) } } diff --git a/ledger/src/blockstore_meta.rs b/ledger/src/blockstore_meta.rs index eb6599dd1198be..0488f24c30b076 100644 --- a/ledger/src/blockstore_meta.rs +++ b/ledger/src/blockstore_meta.rs @@ -1,6 +1,6 @@ use crate::erasure::ErasureConfig; use serde::{Deserialize, Serialize}; -use solana_sdk::{clock::Slot, signature::Signature}; +use solana_sdk::clock::Slot; use std::{collections::BTreeSet, ops::RangeBounds}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)] @@ -230,7 +230,6 @@ pub struct TransactionStatusIndexMeta { #[derive(Debug, Default, Deserialize, Serialize, PartialEq)] pub struct AddressSignatureMeta { - pub signature: Signature, pub writeable: bool, } From d67bc5dc64a0d3c98ae5322ee702bfed56a4a488 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 9 Apr 2020 13:15:00 -0600 Subject: [PATCH 2/6] Add blockstore method to get signatures by address --- ledger/src/blockstore.rs | 159 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 80992d84bdb9a8..dc44f86421c873 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -1751,6 +1751,48 @@ impl Blockstore { .find(|transaction| transaction.signatures[0] == signature)) } + fn find_address_signatures( + &self, + pubkey: Pubkey, + start_slot: Option, + end_slot: Option, + ) -> Result> { + let mut signatures: Vec<(Slot, Signature)> = vec![]; + let start_slot = start_slot.unwrap_or(0); + let end_slot = end_slot.unwrap_or(std::u64::MAX); + 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, + start_slot, + Signature::default(), + ), + IteratorDirection::Forward, + ))?; + for ((i, address, slot, signature), _) in index_iterator { + if i != transaction_status_cf_primary_index || slot > end_slot || address != pubkey + { + break; + } + if self.is_root(slot) { + signatures.push((slot, signature)); + } + } + } + Ok(signatures) + } + + pub fn get_address_confirmed_signatures( + &self, + pubkey: Pubkey, + start_slot: Option, + end_slot: Option, + ) -> Result> { + self.find_address_signatures(pubkey, start_slot, end_slot) + .map(|signatures| signatures.iter().map(|(_, signature)| *signature).collect()) + } + pub fn read_rewards(&self, index: Slot) -> Result> { self.rewards_cf.get(index) } @@ -6043,6 +6085,123 @@ pub mod tests { } } + #[test] + fn test_get_address_confirmed_signatures() { + let blockstore_path = get_tmp_ledger_path!(); + { + let blockstore = Blockstore::open(&blockstore_path).unwrap(); + + let address0 = Pubkey::new_rand(); + let address1 = Pubkey::new_rand(); + + let slot0 = 10; + for x in 1..5 { + let signature = Signature::new(&[x; 64]); + blockstore + .write_transaction_status( + slot0, + signature, + vec![&address0], + vec![&address1], + &TransactionStatusMeta::default(), + ) + .unwrap(); + } + // Purge to freeze index 0 + blockstore.run_purge(0, 1).unwrap(); + let slot1 = 20; + for x in 5..9 { + let signature = Signature::new(&[x; 64]); + blockstore + .write_transaction_status( + slot1, + signature, + vec![&address0], + vec![&address1], + &TransactionStatusMeta::default(), + ) + .unwrap(); + } + blockstore.set_roots(&[slot0, slot1]).unwrap(); + + let all0 = blockstore + .get_address_confirmed_signatures(address0, None, None) + .unwrap(); + assert_eq!(all0.len(), 8); + for x in 1..9 { + let expected_signature = Signature::new(&[x; 64]); + assert_eq!(all0[x as usize - 1], expected_signature); + } + assert_eq!( + blockstore + .get_address_confirmed_signatures(address0, Some(20), None) + .unwrap() + .len(), + 4 + ); + assert_eq!( + blockstore + .get_address_confirmed_signatures(address0, None, Some(10)) + .unwrap() + .len(), + 4 + ); + assert!(blockstore + .get_address_confirmed_signatures(address0, Some(1), Some(5)) + .unwrap() + .is_empty()); + assert_eq!( + blockstore + .get_address_confirmed_signatures(address0, Some(1), Some(15)) + .unwrap() + .len(), + 4 + ); + + let all1 = blockstore + .get_address_confirmed_signatures(address1, None, None) + .unwrap(); + assert_eq!(all1.len(), 8); + for x in 1..9 { + let expected_signature = Signature::new(&[x; 64]); + assert_eq!(all1[x as usize - 1], expected_signature); + } + + // Purge index 0 + blockstore.run_purge(0, 10).unwrap(); + assert_eq!( + blockstore + .get_address_confirmed_signatures(address0, None, None) + .unwrap() + .len(), + 4 + ); + assert_eq!( + blockstore + .get_address_confirmed_signatures(address0, Some(20), None) + .unwrap() + .len(), + 4 + ); + assert!(blockstore + .get_address_confirmed_signatures(address0, None, Some(10)) + .unwrap() + .is_empty()); + assert!(blockstore + .get_address_confirmed_signatures(address0, Some(1), Some(5)) + .unwrap() + .is_empty()); + assert_eq!( + blockstore + .get_address_confirmed_signatures(address0, Some(1), Some(25)) + .unwrap() + .len(), + 4 + ); + } + Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction"); + } + #[test] fn test_get_last_hash() { let mut entries: Vec = vec![]; From 248db23e7e2742e8d7502798b5538592abdf83fd Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 9 Apr 2020 13:24:27 -0600 Subject: [PATCH 3/6] Add getAddressConfirmedSignatures rpc --- core/src/rpc.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 84e7b5ff4cb987..a2c97ac4d6cc51 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -514,6 +514,22 @@ impl JsonRpcRequestProcessor { Ok(None) } } + + pub fn get_address_confirmed_signatures( + &self, + pubkey: Pubkey, + start_slot: Option, + end_slot: Option, + ) -> Result> { + if self.config.enable_rpc_transaction_history { + Ok(self + .blockstore + .get_address_confirmed_signatures(pubkey, start_slot, end_slot) + .unwrap_or_else(|_| vec![])) + } else { + Ok(vec![]) + } + } } fn get_tpu_addr(cluster_info: &Arc>) -> Result { @@ -763,6 +779,15 @@ pub trait RpcSol { signature_str: String, encoding: Option, ) -> Result>; + + #[rpc(meta, name = "getAddressConfirmedSignatures")] + fn get_address_confirmed_signatures( + &self, + meta: Self::Metadata, + pubkey_str: String, + start_slot: Option, + end_slot: Option, + ) -> Result>; } pub struct RpcSolImpl; @@ -1319,6 +1344,26 @@ impl RpcSol for RpcSolImpl { .unwrap() .get_confirmed_transaction(signature, encoding) } + + fn get_address_confirmed_signatures( + &self, + meta: Self::Metadata, + pubkey_str: String, + start_slot: Option, + end_slot: Option, + ) -> Result> { + let pubkey = verify_pubkey(pubkey_str)?; + meta.request_processor + .read() + .unwrap() + .get_address_confirmed_signatures(pubkey, start_slot, end_slot) + .map(|signatures| { + signatures + .iter() + .map(|signature| signature.to_string()) + .collect() + }) + } } #[cfg(test)] From 5a61e0fc0b493d9e12542b270aeb038562fa3acc Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 9 Apr 2020 17:18:10 -0600 Subject: [PATCH 4/6] Add doc --- docs/src/apps/jsonrpc-api.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/src/apps/jsonrpc-api.md b/docs/src/apps/jsonrpc-api.md index 0f22752c4ab7cf..4b421ca4177c75 100644 --- a/docs/src/apps/jsonrpc-api.md +++ b/docs/src/apps/jsonrpc-api.md @@ -21,6 +21,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana- * [getClusterNodes](jsonrpc-api.md#getclusternodes) * [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock) * [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks) +* [getConfirmedSignaturesForAddress](jsonrpc-api.md#getconfirmedsignaturesforaddress) * [getConfirmedTransaction](jsonrpc-api.md#getconfirmedtransaction) * [getEpochInfo](jsonrpc-api.md#getepochinfo) * [getEpochSchedule](jsonrpc-api.md#getepochschedule) @@ -346,6 +347,31 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"m {"jsonrpc":"2.0","result":[5,6,7,8,9,10],"id":1} ``` +### getConfirmedSignaturesForAddress + +Returns a list of all the confirmed signatures for transactions involving an address, within a specified Slot range. Max range allowed is 10_000 Slots. + +#### Parameters: + +* `` - account address as base-58 encoded string +* `` - start slot, inclusive +* `` - end slot, inclusive + +#### Results: + +The result field will be an array of: +* `` - transaction signature as base-58 encoded string + +#### Example: + +```bash +// Request +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedSignaturesForAddress","params":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC", 0, 100]}' localhost:8899 + +// Result +{"jsonrpc":"2.0","result":{["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr","4LQ14a7BYY27578Uj8LPCaVhSdJGLn9DJqnUJHpy95FMqdKf9acAhUhecPQNjNUy6VoNFUbvwYkPociFSf87cWbG"]},"id":1} +``` + ### getConfirmedTransaction Returns transaction details for a confirmed transaction From 4d1ffa2b2afd63c9721d05c0520e9487e7c7ccc9 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 9 Apr 2020 17:21:02 -0600 Subject: [PATCH 5/6] Review comments, notably require slot bounds --- core/src/rpc.rs | 37 +++++++++++++++++++++++++------------ ledger/src/blockstore.rs | 36 +++++++++++++++++------------------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/core/src/rpc.rs b/core/src/rpc.rs index a2c97ac4d6cc51..12907cae05afc1 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -39,6 +39,7 @@ use std::{ }; const MAX_QUERY_ITEMS: usize = 256; +const MAX_SLOT_RANGE: u64 = 10_000; type RpcResponse = Result>; @@ -515,16 +516,16 @@ impl JsonRpcRequestProcessor { } } - pub fn get_address_confirmed_signatures( + pub fn get_confirmed_signatures_for_address( &self, pubkey: Pubkey, - start_slot: Option, - end_slot: Option, + start_slot: Slot, + end_slot: Slot, ) -> Result> { if self.config.enable_rpc_transaction_history { Ok(self .blockstore - .get_address_confirmed_signatures(pubkey, start_slot, end_slot) + .get_confirmed_signatures_for_address(pubkey, start_slot, end_slot) .unwrap_or_else(|_| vec![])) } else { Ok(vec![]) @@ -780,13 +781,13 @@ pub trait RpcSol { encoding: Option, ) -> Result>; - #[rpc(meta, name = "getAddressConfirmedSignatures")] - fn get_address_confirmed_signatures( + #[rpc(meta, name = "getConfirmedSignaturesForAddress")] + fn get_confirmed_signatures_for_address( &self, meta: Self::Metadata, pubkey_str: String, - start_slot: Option, - end_slot: Option, + start_slot: Slot, + end_slot: Slot, ) -> Result>; } @@ -1345,18 +1346,30 @@ impl RpcSol for RpcSolImpl { .get_confirmed_transaction(signature, encoding) } - fn get_address_confirmed_signatures( + fn get_confirmed_signatures_for_address( &self, meta: Self::Metadata, pubkey_str: String, - start_slot: Option, - end_slot: Option, + start_slot: Slot, + end_slot: Slot, ) -> Result> { let pubkey = verify_pubkey(pubkey_str)?; + if end_slot <= start_slot { + return Err(Error::invalid_params(format!( + "start_slot {} must be smaller than end_slot {}", + start_slot, end_slot + ))); + } + if end_slot - start_slot > MAX_SLOT_RANGE { + return Err(Error::invalid_params(format!( + "Slot range too large; max {}", + MAX_SLOT_RANGE + ))); + } meta.request_processor .read() .unwrap() - .get_address_confirmed_signatures(pubkey, start_slot, end_slot) + .get_confirmed_signatures_for_address(pubkey, start_slot, end_slot) .map(|signatures| { signatures .iter() diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index dc44f86421c873..b7965481537cf3 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -1754,12 +1754,10 @@ impl Blockstore { fn find_address_signatures( &self, pubkey: Pubkey, - start_slot: Option, - end_slot: Option, + start_slot: Slot, + end_slot: Slot, ) -> Result> { let mut signatures: Vec<(Slot, Signature)> = vec![]; - let start_slot = start_slot.unwrap_or(0); - let end_slot = end_slot.unwrap_or(std::u64::MAX); for transaction_status_cf_primary_index in 0..=1 { let index_iterator = self.address_signatures_cf.iter(IteratorMode::From( ( @@ -1783,11 +1781,11 @@ impl Blockstore { Ok(signatures) } - pub fn get_address_confirmed_signatures( + pub fn get_confirmed_signatures_for_address( &self, pubkey: Pubkey, - start_slot: Option, - end_slot: Option, + start_slot: Slot, + end_slot: Slot, ) -> Result> { self.find_address_signatures(pubkey, start_slot, end_slot) .map(|signatures| signatures.iter().map(|(_, signature)| *signature).collect()) @@ -6086,7 +6084,7 @@ pub mod tests { } #[test] - fn test_get_address_confirmed_signatures() { + fn test_get_confirmed_signatures_for_address() { let blockstore_path = get_tmp_ledger_path!(); { let blockstore = Blockstore::open(&blockstore_path).unwrap(); @@ -6125,7 +6123,7 @@ pub mod tests { blockstore.set_roots(&[slot0, slot1]).unwrap(); let all0 = blockstore - .get_address_confirmed_signatures(address0, None, None) + .get_confirmed_signatures_for_address(address0, 0, 50) .unwrap(); assert_eq!(all0.len(), 8); for x in 1..9 { @@ -6134,32 +6132,32 @@ pub mod tests { } assert_eq!( blockstore - .get_address_confirmed_signatures(address0, Some(20), None) + .get_confirmed_signatures_for_address(address0, 20, 50) .unwrap() .len(), 4 ); assert_eq!( blockstore - .get_address_confirmed_signatures(address0, None, Some(10)) + .get_confirmed_signatures_for_address(address0, 0, 10) .unwrap() .len(), 4 ); assert!(blockstore - .get_address_confirmed_signatures(address0, Some(1), Some(5)) + .get_confirmed_signatures_for_address(address0, 1, 5) .unwrap() .is_empty()); assert_eq!( blockstore - .get_address_confirmed_signatures(address0, Some(1), Some(15)) + .get_confirmed_signatures_for_address(address0, 1, 15) .unwrap() .len(), 4 ); let all1 = blockstore - .get_address_confirmed_signatures(address1, None, None) + .get_confirmed_signatures_for_address(address1, 0, 50) .unwrap(); assert_eq!(all1.len(), 8); for x in 1..9 { @@ -6171,29 +6169,29 @@ pub mod tests { blockstore.run_purge(0, 10).unwrap(); assert_eq!( blockstore - .get_address_confirmed_signatures(address0, None, None) + .get_confirmed_signatures_for_address(address0, 0, 50) .unwrap() .len(), 4 ); assert_eq!( blockstore - .get_address_confirmed_signatures(address0, Some(20), None) + .get_confirmed_signatures_for_address(address0, 20, 50) .unwrap() .len(), 4 ); assert!(blockstore - .get_address_confirmed_signatures(address0, None, Some(10)) + .get_confirmed_signatures_for_address(address0, 0, 10) .unwrap() .is_empty()); assert!(blockstore - .get_address_confirmed_signatures(address0, Some(1), Some(5)) + .get_confirmed_signatures_for_address(address0, 1, 5) .unwrap() .is_empty()); assert_eq!( blockstore - .get_address_confirmed_signatures(address0, Some(1), Some(25)) + .get_confirmed_signatures_for_address(address0, 1, 25) .unwrap() .len(), 4 From 4147d446373dcf5d60cbe2bf87a747e89e934378 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 9 Apr 2020 20:25:37 -0600 Subject: [PATCH 6/6] Add sort of signature results, test and doc --- docs/src/apps/jsonrpc-api.md | 2 ++ ledger/src/blockstore.rs | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/docs/src/apps/jsonrpc-api.md b/docs/src/apps/jsonrpc-api.md index 4b421ca4177c75..43a0ae8f842a73 100644 --- a/docs/src/apps/jsonrpc-api.md +++ b/docs/src/apps/jsonrpc-api.md @@ -362,6 +362,8 @@ Returns a list of all the confirmed signatures for transactions involving an add The result field will be an array of: * `` - transaction signature as base-58 encoded string +The signatures will be ordered based on the Slot in which they were confirmed in, from lowest to highest Slot + #### Example: ```bash diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index b7965481537cf3..00fb33905a79cd 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -1751,6 +1751,8 @@ impl Blockstore { .find(|transaction| transaction.signatures[0] == signature)) } + // Returns all cached signatures for an address, ordered by slot that the transaction was + // processed in fn find_address_signatures( &self, pubkey: Pubkey, @@ -1778,6 +1780,7 @@ impl Blockstore { } } } + signatures.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); Ok(signatures) } @@ -6196,6 +6199,27 @@ pub mod tests { .len(), 4 ); + + // Test sort, regardless of entry order or signature value + for slot in (21..25).rev() { + let random_bytes: Vec = (0..64).map(|_| rand::random::()).collect(); + let signature = Signature::new(&random_bytes); + blockstore + .write_transaction_status( + slot, + signature, + vec![&address0], + vec![&address1], + &TransactionStatusMeta::default(), + ) + .unwrap(); + } + blockstore.set_roots(&[21, 22, 23, 24]).unwrap(); + let mut past_slot = 0; + for (slot, _) in blockstore.find_address_signatures(address0, 1, 25).unwrap() { + assert!(slot >= past_slot); + past_slot = slot; + } } Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction"); }