@ -38,6 +38,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MAX_QUERY_ITEMS: usize = 256;
|
const MAX_QUERY_ITEMS: usize = 256;
|
||||||
|
const MAX_SLOT_RANGE: u64 = 10_000;
|
||||||
|
|
||||||
type RpcResponse<T> = Result<Response<T>>;
|
type RpcResponse<T> = Result<Response<T>>;
|
||||||
|
|
||||||
@ -520,6 +521,22 @@ impl JsonRpcRequestProcessor {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_signatures_for_address(
|
||||||
|
&self,
|
||||||
|
pubkey: Pubkey,
|
||||||
|
start_slot: Slot,
|
||||||
|
end_slot: Slot,
|
||||||
|
) -> Result<Vec<Signature>> {
|
||||||
|
if self.config.enable_rpc_transaction_history {
|
||||||
|
Ok(self
|
||||||
|
.blockstore
|
||||||
|
.get_confirmed_signatures_for_address(pubkey, start_slot, end_slot)
|
||||||
|
.unwrap_or_else(|_| vec![]))
|
||||||
|
} else {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tpu_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
fn get_tpu_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
||||||
@ -769,6 +786,15 @@ pub trait RpcSol {
|
|||||||
signature_str: String,
|
signature_str: String,
|
||||||
encoding: Option<TransactionEncoding>,
|
encoding: Option<TransactionEncoding>,
|
||||||
) -> Result<Option<ConfirmedTransaction>>;
|
) -> Result<Option<ConfirmedTransaction>>;
|
||||||
|
|
||||||
|
#[rpc(meta, name = "getConfirmedSignaturesForAddress")]
|
||||||
|
fn get_confirmed_signatures_for_address(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
pubkey_str: String,
|
||||||
|
start_slot: Slot,
|
||||||
|
end_slot: Slot,
|
||||||
|
) -> Result<Vec<String>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RpcSolImpl;
|
pub struct RpcSolImpl;
|
||||||
@ -1325,6 +1351,38 @@ impl RpcSol for RpcSolImpl {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.get_confirmed_transaction(signature, encoding)
|
.get_confirmed_transaction(signature, encoding)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_confirmed_signatures_for_address(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
pubkey_str: String,
|
||||||
|
start_slot: Slot,
|
||||||
|
end_slot: Slot,
|
||||||
|
) -> Result<Vec<String>> {
|
||||||
|
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_confirmed_signatures_for_address(pubkey, start_slot, end_slot)
|
||||||
|
.map(|signatures| {
|
||||||
|
signatures
|
||||||
|
.iter()
|
||||||
|
.map(|signature| signature.to_string())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -21,6 +21,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
* [getClusterNodes](jsonrpc-api.md#getclusternodes)
|
* [getClusterNodes](jsonrpc-api.md#getclusternodes)
|
||||||
* [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock)
|
* [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock)
|
||||||
* [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
|
* [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
|
||||||
|
* [getConfirmedSignaturesForAddress](jsonrpc-api.md#getconfirmedsignaturesforaddress)
|
||||||
* [getConfirmedTransaction](jsonrpc-api.md#getconfirmedtransaction)
|
* [getConfirmedTransaction](jsonrpc-api.md#getconfirmedtransaction)
|
||||||
* [getEpochInfo](jsonrpc-api.md#getepochinfo)
|
* [getEpochInfo](jsonrpc-api.md#getepochinfo)
|
||||||
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
|
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
|
||||||
@ -346,6 +347,33 @@ 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}
|
{"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:
|
||||||
|
|
||||||
|
* `<string>` - account address as base-58 encoded string
|
||||||
|
* `<u64>` - start slot, inclusive
|
||||||
|
* `<u64>` - end slot, inclusive
|
||||||
|
|
||||||
|
#### Results:
|
||||||
|
|
||||||
|
The result field will be an array of:
|
||||||
|
* `<string>` - 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
|
||||||
|
// 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
|
### getConfirmedTransaction
|
||||||
|
|
||||||
Returns transaction details for a confirmed transaction
|
Returns transaction details for a confirmed transaction
|
||||||
|
@ -1633,20 +1633,14 @@ impl Blockstore {
|
|||||||
.put((primary_index, signature, slot), status)?;
|
.put((primary_index, signature, slot), status)?;
|
||||||
for address in writable_keys {
|
for address in writable_keys {
|
||||||
self.address_signatures_cf.put(
|
self.address_signatures_cf.put(
|
||||||
(primary_index, *address, slot),
|
(primary_index, *address, slot, signature),
|
||||||
&AddressSignatureMeta {
|
&AddressSignatureMeta { writeable: true },
|
||||||
signature,
|
|
||||||
writeable: true,
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
for address in readonly_keys {
|
for address in readonly_keys {
|
||||||
self.address_signatures_cf.put(
|
self.address_signatures_cf.put(
|
||||||
(primary_index, *address, slot),
|
(primary_index, *address, slot, signature),
|
||||||
&AddressSignatureMeta {
|
&AddressSignatureMeta { writeable: false },
|
||||||
signature,
|
|
||||||
writeable: false,
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1723,6 +1717,49 @@ impl Blockstore {
|
|||||||
.find(|transaction| transaction.signatures[0] == signature))
|
.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,
|
||||||
|
start_slot: Slot,
|
||||||
|
end_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,
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signatures.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
|
||||||
|
Ok(signatures)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_signatures_for_address(
|
||||||
|
&self,
|
||||||
|
pubkey: Pubkey,
|
||||||
|
start_slot: Slot,
|
||||||
|
end_slot: Slot,
|
||||||
|
) -> Result<Vec<Signature>> {
|
||||||
|
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<Option<Rewards>> {
|
pub fn read_rewards(&self, index: Slot) -> Result<Option<Rewards>> {
|
||||||
self.rewards_cf.get(index)
|
self.rewards_cf.get(index)
|
||||||
}
|
}
|
||||||
@ -2858,7 +2895,7 @@ pub mod tests {
|
|||||||
.iter::<cf::AddressSignatures>(IteratorMode::Start)
|
.iter::<cf::AddressSignatures>(IteratorMode::Start)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.next()
|
.next()
|
||||||
.map(|((primary_index, _, slot), _)| {
|
.map(|((primary_index, _, slot, _), _)| {
|
||||||
slot >= min_slot || (primary_index == 2 && slot == 0)
|
slot >= min_slot || (primary_index == 2 && slot == 0)
|
||||||
})
|
})
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
@ -5466,7 +5503,7 @@ pub mod tests {
|
|||||||
let first_status_entry = blockstore
|
let first_status_entry = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
||||||
(0, Signature::default(), 0),
|
cf::TransactionStatus::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -5478,7 +5515,7 @@ pub mod tests {
|
|||||||
let first_address_entry = blockstore
|
let first_address_entry = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
||||||
(0, Pubkey::default(), 0),
|
cf::AddressSignatures::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -5536,7 +5573,7 @@ pub mod tests {
|
|||||||
let first_status_entry = blockstore
|
let first_status_entry = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
||||||
(0, Signature::default(), 0),
|
cf::TransactionStatus::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -5548,7 +5585,7 @@ pub mod tests {
|
|||||||
let first_address_entry = blockstore
|
let first_address_entry = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
||||||
(0, Pubkey::default(), 0),
|
cf::AddressSignatures::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -5561,7 +5598,7 @@ pub mod tests {
|
|||||||
let index1_first_status_entry = blockstore
|
let index1_first_status_entry = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
||||||
(1, Signature::default(), 0),
|
cf::TransactionStatus::as_index(1),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -5573,7 +5610,7 @@ pub mod tests {
|
|||||||
let index1_first_address_entry = blockstore
|
let index1_first_address_entry = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
||||||
(1, Pubkey::default(), 0),
|
cf::AddressSignatures::as_index(1),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -5604,7 +5641,7 @@ pub mod tests {
|
|||||||
let first_status_entry = blockstore
|
let first_status_entry = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
||||||
(0, Signature::default(), 0),
|
cf::TransactionStatus::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -5616,7 +5653,7 @@ pub mod tests {
|
|||||||
let first_address_entry = blockstore
|
let first_address_entry = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
||||||
(0, Pubkey::default(), 0),
|
cf::AddressSignatures::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -5653,7 +5690,7 @@ pub mod tests {
|
|||||||
let mut status_entry_iterator = blockstore
|
let mut status_entry_iterator = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
||||||
(0, Signature::default(), 0),
|
cf::TransactionStatus::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -5665,7 +5702,7 @@ pub mod tests {
|
|||||||
let mut address_transactions_iterator = blockstore
|
let mut address_transactions_iterator = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
||||||
(0, Pubkey::default(), 0),
|
(0, Pubkey::default(), 0, Signature::default()),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -5687,7 +5724,7 @@ pub mod tests {
|
|||||||
let mut status_entry_iterator = blockstore
|
let mut status_entry_iterator = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
||||||
(0, Signature::default(), 0),
|
cf::TransactionStatus::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -5699,7 +5736,7 @@ pub mod tests {
|
|||||||
let mut address_transactions_iterator = blockstore
|
let mut address_transactions_iterator = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
||||||
(0, Pubkey::default(), 0),
|
cf::AddressSignatures::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -5721,7 +5758,7 @@ pub mod tests {
|
|||||||
let mut status_entry_iterator = blockstore
|
let mut status_entry_iterator = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
||||||
(0, Signature::default(), 0),
|
cf::TransactionStatus::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -5733,7 +5770,7 @@ pub mod tests {
|
|||||||
let mut address_transactions_iterator = blockstore
|
let mut address_transactions_iterator = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
||||||
(0, Pubkey::default(), 0),
|
cf::AddressSignatures::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -5754,7 +5791,7 @@ pub mod tests {
|
|||||||
let mut status_entry_iterator = blockstore
|
let mut status_entry_iterator = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
.iter::<cf::TransactionStatus>(IteratorMode::From(
|
||||||
(0, Signature::default(), 0),
|
cf::TransactionStatus::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -5765,7 +5802,7 @@ pub mod tests {
|
|||||||
let mut address_transactions_iterator = blockstore
|
let mut address_transactions_iterator = blockstore
|
||||||
.db
|
.db
|
||||||
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
.iter::<cf::AddressSignatures>(IteratorMode::From(
|
||||||
(0, Pubkey::default(), 0),
|
cf::AddressSignatures::as_index(0),
|
||||||
IteratorDirection::Forward,
|
IteratorDirection::Forward,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -5995,6 +6032,144 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_confirmed_signatures_for_address() {
|
||||||
|
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_confirmed_signatures_for_address(address0, 0, 50)
|
||||||
|
.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_confirmed_signatures_for_address(address0, 20, 50)
|
||||||
|
.unwrap()
|
||||||
|
.len(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
blockstore
|
||||||
|
.get_confirmed_signatures_for_address(address0, 0, 10)
|
||||||
|
.unwrap()
|
||||||
|
.len(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
assert!(blockstore
|
||||||
|
.get_confirmed_signatures_for_address(address0, 1, 5)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
|
assert_eq!(
|
||||||
|
blockstore
|
||||||
|
.get_confirmed_signatures_for_address(address0, 1, 15)
|
||||||
|
.unwrap()
|
||||||
|
.len(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
|
let all1 = blockstore
|
||||||
|
.get_confirmed_signatures_for_address(address1, 0, 50)
|
||||||
|
.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_confirmed_signatures_for_address(address0, 0, 50)
|
||||||
|
.unwrap()
|
||||||
|
.len(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
blockstore
|
||||||
|
.get_confirmed_signatures_for_address(address0, 20, 50)
|
||||||
|
.unwrap()
|
||||||
|
.len(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
assert!(blockstore
|
||||||
|
.get_confirmed_signatures_for_address(address0, 0, 10)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
|
assert!(blockstore
|
||||||
|
.get_confirmed_signatures_for_address(address0, 1, 5)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
|
assert_eq!(
|
||||||
|
blockstore
|
||||||
|
.get_confirmed_signatures_for_address(address0, 1, 25)
|
||||||
|
.unwrap()
|
||||||
|
.len(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test sort, regardless of entry order or signature value
|
||||||
|
for slot in (21..25).rev() {
|
||||||
|
let random_bytes: Vec<u8> = (0..64).map(|_| rand::random::<u8>()).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");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_last_hash() {
|
fn test_get_last_hash() {
|
||||||
let mut entries: Vec<Entry> = vec![];
|
let mut entries: Vec<Entry> = vec![];
|
||||||
|
@ -356,21 +356,23 @@ impl ColumnName for columns::TransactionStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Column for columns::AddressSignatures {
|
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<u8> {
|
fn key((index, pubkey, slot, signature): (u64, Pubkey, Slot, Signature)) -> Vec<u8> {
|
||||||
let mut key = vec![0; 8 + 32 + 8]; // size_of u64 + size_of Pubkey + size_of Slot
|
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);
|
BigEndian::write_u64(&mut key[0..8], index);
|
||||||
key[8..40].clone_from_slice(&pubkey.as_ref()[0..32]);
|
key[8..40].clone_from_slice(&pubkey.as_ref()[0..32]);
|
||||||
BigEndian::write_u64(&mut key[40..48], slot);
|
BigEndian::write_u64(&mut key[40..48], slot);
|
||||||
|
key[48..112].clone_from_slice(&signature.as_ref()[0..64]);
|
||||||
key
|
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 index = BigEndian::read_u64(&key[0..8]);
|
||||||
let pubkey = Pubkey::new(&key[8..40]);
|
let pubkey = Pubkey::new(&key[8..40]);
|
||||||
let slot = BigEndian::read_u64(&key[40..48]);
|
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 {
|
fn primary_index(index: Self::Index) -> u64 {
|
||||||
@ -378,7 +380,7 @@ impl Column for columns::AddressSignatures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn as_index(index: u64) -> Self::Index {
|
fn as_index(index: u64) -> Self::Index {
|
||||||
(index, Pubkey::default(), 0)
|
(index, Pubkey::default(), 0, Signature::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::erasure::ErasureConfig;
|
use crate::erasure::ErasureConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use solana_sdk::{clock::Slot, signature::Signature};
|
use solana_sdk::clock::Slot;
|
||||||
use std::{collections::BTreeSet, ops::RangeBounds};
|
use std::{collections::BTreeSet, ops::RangeBounds};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
|
||||||
@ -230,7 +230,6 @@ pub struct TransactionStatusIndexMeta {
|
|||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
|
#[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
|
||||||
pub struct AddressSignatureMeta {
|
pub struct AddressSignatureMeta {
|
||||||
pub signature: Signature,
|
|
||||||
pub writeable: bool,
|
pub writeable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user