diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 6c9009fdfc..0a14e8cfe2 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -13,9 +13,7 @@ use jsonrpc_core::{Error, Metadata, Result}; use jsonrpc_derive::rpc; use solana_client::rpc_response::*; use solana_faucet::faucet::request_airdrop_transaction; -use solana_ledger::{ - bank_forks::BankForks, blockstore::Blockstore, rooted_slot_iterator::RootedSlotIterator, -}; +use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore}; use solana_runtime::bank::Bank; use solana_sdk::{ clock::{Slot, UnixTimestamp}, @@ -381,18 +379,12 @@ impl JsonRpcRequestProcessor { if end_slot < start_slot { return Ok(vec![]); } - - let start_slot = (start_slot..end_slot).find(|&slot| self.blockstore.is_root(slot)); - if let Some(start_slot) = start_slot { - let mut slots: Vec = RootedSlotIterator::new(start_slot, &self.blockstore) - .unwrap() - .map(|(slot, _)| slot) - .collect(); - slots.retain(|&x| x <= end_slot); - Ok(slots) - } else { - Ok(vec![]) - } + Ok(self + .blockstore + .rooted_slot_iterator(start_slot) + .map_err(|_| Error::internal_error())? + .filter(|&slot| slot <= end_slot) + .collect()) } pub fn get_block_time(&self, slot: Slot) -> Result> { @@ -543,6 +535,13 @@ impl JsonRpcRequestProcessor { Ok(vec![]) } } + + pub fn get_first_available_block(&self) -> Result { + Ok(self + .blockstore + .get_first_available_block() + .unwrap_or_default()) + } } fn get_tpu_addr(cluster_info: &Arc>) -> Result { @@ -801,6 +800,9 @@ pub trait RpcSol { start_slot: Slot, end_slot: Slot, ) -> Result>; + + #[rpc(meta, name = "getFirstAvailableBlock")] + fn get_first_available_block(&self, meta: Self::Metadata) -> Result; } pub struct RpcSolImpl; @@ -1389,6 +1391,13 @@ impl RpcSol for RpcSolImpl { .collect() }) } + + fn get_first_available_block(&self, meta: Self::Metadata) -> Result { + meta.request_processor + .read() + .unwrap() + .get_first_available_block() + } } #[cfg(test)] diff --git a/docs/src/apps/jsonrpc-api.md b/docs/src/apps/jsonrpc-api.md index c25d9f2f44..b400893940 100644 --- a/docs/src/apps/jsonrpc-api.md +++ b/docs/src/apps/jsonrpc-api.md @@ -27,6 +27,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana- * [getEpochSchedule](jsonrpc-api.md#getepochschedule) * [getFeeCalculatorForBlockhash](jsonrpc-api.md#getfeecalculatorforblockhash) * [getFeeRateGovernor](jsonrpc-api.md#getfeerategovernor) +* [getFirstAvailableBlock](jsonrpc-api.md#getfirstavailableblock) * [getGenesisHash](jsonrpc-api.md#getgenesishash) * [getIdentity](jsonrpc-api.md#getidentity) * [getInflation](jsonrpc-api.md#getinflation) @@ -280,22 +281,24 @@ Returns identity and transaction information about a confirmed block in the ledg The result field will be an object with the following fields: -* `blockhash: ` - the blockhash of this block, as base-58 encoded string -* `previousBlockhash: ` - the blockhash of this block's parent, as base-58 encoded string -* `parentSlot: ` - the slot index of this block's parent -* `transactions: ` - an array of JSON objects containing: - * `transaction: ` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter - * `meta: ` - transaction status metadata object, containing `null` or: - * `err: ` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14) - * `fee: ` - fee this transaction was charged, as u64 integer - * `preBalances: ` - array of u64 account balances from before the transaction was processed - * `postBalances: ` - array of u64 account balances after the transaction was processed - * DEPRECATED: `status: ` - Transaction status - * `"Ok": ` - Transaction was successful - * `"Err": ` - Transaction failed with TransactionError -* `rewards: ` - an array of JSON objects containing: - * `pubkey: ` - The public key, as base-58 encoded string, of the account that received the reward - * `lamports: `- number of reward lamports credited or debited by the account, as a i64 +* `` - if specified block is not confirmed +* `` - if block is confirmed, an object with the following fields: + * `blockhash: ` - the blockhash of this block, as base-58 encoded string + * `previousBlockhash: ` - the blockhash of this block's parent, as base-58 encoded string; if the parent block is not available due to ledger cleanup, this field will return "11111111111111111111111111111111" + * `parentSlot: ` - the slot index of this block's parent + * `transactions: ` - an array of JSON objects containing: + * `transaction: ` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter + * `meta: ` - transaction status metadata object, containing `null` or: + * `err: ` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14) + * `fee: ` - fee this transaction was charged, as u64 integer + * `preBalances: ` - array of u64 account balances from before the transaction was processed + * `postBalances: ` - array of u64 account balances after the transaction was processed + * DEPRECATED: `status: ` - Transaction status + * `"Ok": ` - Transaction was successful + * `"Err": ` - Transaction failed with TransactionError + * `rewards: ` - an array of JSON objects containing: + * `pubkey: ` - The public key, as base-58 encoded string, of the account that received the reward + * `lamports: `- number of reward lamports credited or debited by the account, as a i64 #### Example: @@ -530,6 +533,28 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m {"jsonrpc":"2.0","result":{"context":{"slot":54},"value":{"feeRateGovernor":{"burnPercent":50,"maxLamportsPerSignature":100000,"minLamportsPerSignature":5000,"targetLamportsPerSignature":10000,"targetSignaturesPerSlot":20000}}},"id":1} ``` +### getFirstAvailableBlock + +Returns the slot of the lowest confirmed block that has not been purged from the ledger + +#### Parameters: + +None + +#### Results: + +* `` - Slot + +#### Example: + +```bash +// Request +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getFirstAvailableBlock"}' http://localhost:8899 + +// Result +{"jsonrpc":"2.0","result":250000,"id":1} +``` + ### getGenesisHash Returns the genesis hash diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 6ba6c0cf1f..a87f691804 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -1467,6 +1467,11 @@ impl Blockstore { slots } + pub fn get_first_available_block(&self) -> Result { + let mut root_iterator = self.rooted_slot_iterator(0)?; + Ok(root_iterator.next().unwrap_or_default()) + } + pub fn get_confirmed_block( &self, slot: Slot, @@ -1499,7 +1504,9 @@ impl Blockstore { .iter() .cloned() .flat_map(|entry| entry.transactions); - let parent_slot_entries = self.get_slot_entries(slot_meta.parent_slot, 0, None)?; + let parent_slot_entries = self + .get_slot_entries(slot_meta.parent_slot, 0, None) + .unwrap_or_default(); let previous_blockhash = if !parent_slot_entries.is_empty() { get_last_hash(parent_slot_entries.iter()).unwrap() } else {