Rpc: enable getConfirmedBlocks and getConfirmedBlocksWithLimit to return confirmed (not yet finalized) data (bp #16161) (#16197)

* Rpc: enable getConfirmedBlocks and getConfirmedBlocksWithLimit to return confirmed (not yet finalized) data (#16161)

* Add commitment config capabilities

* Use rpc limit if no end_slot provided

* Limit to actually finalized blocks

* Support confirmed blocks in getConfirmedBlocks and getConfirmedBlocksWithLimit

* Update docs

* Add client plumbing

* Rename config enum

(cherry picked from commit 60ed8e2892)

# Conflicts:
#	client/src/rpc_config.rs
#	core/src/rpc.rs

* Fix conflicts

* Future-aware enum name

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
This commit is contained in:
mergify[bot]
2021-03-29 22:11:46 +00:00
committed by GitHub
parent 72ff8973a2
commit 09843a28d9
4 changed files with 129 additions and 17 deletions

View File

@ -543,6 +543,24 @@ impl RpcClient {
)
}
pub fn get_confirmed_blocks_with_commitment(
&self,
start_slot: Slot,
end_slot: Option<Slot>,
commitment_config: CommitmentConfig,
) -> ClientResult<Vec<Slot>> {
let json = if end_slot.is_some() {
json!([
start_slot,
end_slot,
self.maybe_map_commitment(commitment_config)?
])
} else {
json!([start_slot, self.maybe_map_commitment(commitment_config)?])
};
self.send(RpcRequest::GetConfirmedBlocks, json)
}
pub fn get_confirmed_blocks_with_limit(
&self,
start_slot: Slot,
@ -554,6 +572,22 @@ impl RpcClient {
)
}
pub fn get_confirmed_blocks_with_limit_and_commitment(
&self,
start_slot: Slot,
limit: usize,
commitment_config: CommitmentConfig,
) -> ClientResult<Vec<Slot>> {
self.send(
RpcRequest::GetConfirmedBlocksWithLimit,
json!([
start_slot,
limit,
self.maybe_map_commitment(commitment_config)?
]),
)
}
pub fn get_confirmed_signatures_for_address(
&self,
address: &Pubkey,

View File

@ -1,7 +1,7 @@
use crate::rpc_filter::RpcFilterType;
use solana_account_decoder::{UiAccountEncoding, UiDataSliceConfig};
use solana_sdk::{
clock::Epoch,
clock::{Epoch, Slot},
commitment_config::{CommitmentConfig, CommitmentLevel},
};
use solana_transaction_status::{TransactionDetails, UiTransactionEncoding};
@ -173,3 +173,19 @@ impl EncodingConfig for RpcConfirmedTransactionConfig {
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RpcConfirmedBlocksConfigWrapper {
EndSlotOnly(Option<Slot>),
CommitmentOnly(Option<CommitmentConfig>),
}
impl RpcConfirmedBlocksConfigWrapper {
pub fn unzip(&self) -> (Option<Slot>, Option<CommitmentConfig>) {
match &self {
RpcConfirmedBlocksConfigWrapper::EndSlotOnly(end_slot) => (*end_slot, None),
RpcConfirmedBlocksConfigWrapper::CommitmentOnly(commitment) => (None, *commitment),
}
}
}

View File

@ -811,13 +811,24 @@ impl JsonRpcRequestProcessor {
&self,
start_slot: Slot,
end_slot: Option<Slot>,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Slot>> {
let commitment = commitment.unwrap_or_default();
check_is_at_least_confirmed(commitment)?;
let highest_confirmed_root = self
.block_commitment_cache
.read()
.unwrap()
.highest_confirmed_root();
let end_slot = min(
end_slot.unwrap_or(std::u64::MAX),
self.block_commitment_cache
.read()
.unwrap()
.highest_confirmed_root(),
end_slot.unwrap_or_else(|| start_slot.saturating_add(MAX_GET_CONFIRMED_BLOCKS_RANGE)),
if commitment.is_finalized() {
highest_confirmed_root
} else {
self.bank(Some(CommitmentConfig::confirmed())).slot()
},
);
if end_slot < start_slot {
return Ok(vec![]);
@ -832,7 +843,8 @@ impl JsonRpcRequestProcessor {
let lowest_blockstore_slot = self.blockstore.lowest_slot();
if start_slot < lowest_blockstore_slot {
// If the starting slot is lower than what's available in blockstore assume the entire
// [start_slot..end_slot] can be fetched from BigTable.
// [start_slot..end_slot] can be fetched from BigTable. This range should not ever run
// into unfinalized confirmed blocks due to MAX_GET_CONFIRMED_BLOCKS_RANGE
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
return self
.runtime_handle
@ -853,19 +865,38 @@ impl JsonRpcRequestProcessor {
}
}
Ok(self
// Finalized blocks
let mut blocks: Vec<_> = self
.blockstore
.rooted_slot_iterator(max(start_slot, lowest_blockstore_slot))
.map_err(|_| Error::internal_error())?
.filter(|&slot| slot <= end_slot)
.collect())
.filter(|&slot| slot <= end_slot && slot <= highest_confirmed_root)
.collect();
let last_element = blocks.last().cloned().unwrap_or_default();
// Maybe add confirmed blocks
if commitment.is_confirmed() && last_element < end_slot {
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
let mut confirmed_blocks = confirmed_bank
.status_cache_ancestors()
.into_iter()
.filter(|&slot| slot <= end_slot && slot > last_element)
.collect();
blocks.append(&mut confirmed_blocks);
}
Ok(blocks)
}
pub fn get_confirmed_blocks_with_limit(
&self,
start_slot: Slot,
limit: usize,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Slot>> {
let commitment = commitment.unwrap_or_default();
check_is_at_least_confirmed(commitment)?;
if limit > MAX_GET_CONFIRMED_BLOCKS_RANGE as usize {
return Err(Error::invalid_params(format!(
"Limit too large; max {}",
@ -877,7 +908,8 @@ impl JsonRpcRequestProcessor {
if start_slot < lowest_blockstore_slot {
// If the starting slot is lower than what's available in blockstore assume the entire
// range can be fetched from BigTable.
// range can be fetched from BigTable. This range should not ever run into unfinalized
// confirmed blocks due to MAX_GET_CONFIRMED_BLOCKS_RANGE
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
return Ok(self
.runtime_handle
@ -886,12 +918,35 @@ impl JsonRpcRequestProcessor {
}
}
Ok(self
let highest_confirmed_root = self
.block_commitment_cache
.read()
.unwrap()
.highest_confirmed_root();
// Finalized blocks
let mut blocks: Vec<_> = self
.blockstore
.rooted_slot_iterator(max(start_slot, lowest_blockstore_slot))
.map_err(|_| Error::internal_error())?
.take(limit)
.collect())
.filter(|&slot| slot <= highest_confirmed_root)
.collect();
// Maybe add confirmed blocks
if commitment.is_confirmed() && blocks.len() < limit {
let last_element = blocks.last().cloned().unwrap_or_default();
let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
let mut confirmed_blocks = confirmed_bank
.status_cache_ancestors()
.into_iter()
.filter(|&slot| slot > last_element)
.collect();
blocks.append(&mut confirmed_blocks);
blocks.truncate(limit);
}
Ok(blocks)
}
pub fn get_block_time(&self, slot: Slot) -> Result<Option<UnixTimestamp>> {
@ -2121,7 +2176,8 @@ pub trait RpcSol {
&self,
meta: Self::Metadata,
start_slot: Slot,
end_slot: Option<Slot>,
config: Option<RpcConfirmedBlocksConfigWrapper>,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Slot>>;
#[rpc(meta, name = "getConfirmedBlocksWithLimit")]
@ -2130,6 +2186,7 @@ pub trait RpcSol {
meta: Self::Metadata,
start_slot: Slot,
limit: usize,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Slot>>;
#[rpc(meta, name = "getConfirmedTransaction")]
@ -2920,13 +2977,15 @@ impl RpcSol for RpcSolImpl {
&self,
meta: Self::Metadata,
start_slot: Slot,
end_slot: Option<Slot>,
config: Option<RpcConfirmedBlocksConfigWrapper>,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Slot>> {
let (end_slot, maybe_commitment) = config.map(|config| config.unzip()).unwrap_or_default();
debug!(
"get_confirmed_blocks rpc request received: {}-{:?}",
start_slot, end_slot
);
meta.get_confirmed_blocks(start_slot, end_slot)
meta.get_confirmed_blocks(start_slot, end_slot, commitment.or(maybe_commitment))
}
fn get_confirmed_blocks_with_limit(
@ -2934,12 +2993,13 @@ impl RpcSol for RpcSolImpl {
meta: Self::Metadata,
start_slot: Slot,
limit: usize,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<Slot>> {
debug!(
"get_confirmed_blocks_with_limit rpc request received: {}-{}",
start_slot, limit,
);
meta.get_confirmed_blocks_with_limit(start_slot, limit)
meta.get_confirmed_blocks_with_limit(start_slot, limit, commitment)
}
fn get_block_time(&self, meta: Self::Metadata, slot: Slot) -> Result<Option<UnixTimestamp>> {

View File

@ -688,6 +688,7 @@ Returns a list of confirmed blocks between two slots
- `<u64>` - start_slot, as u64 integer
- `<u64>` - (optional) end_slot, as u64 integer
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment); "processed" is not supported. If parameter not provided, the default is "finalized".
#### Results:
@ -718,6 +719,7 @@ Returns a list of confirmed blocks starting at the given slot
- `<u64>` - start_slot, as u64 integer
- `<u64>` - limit, as u64 integer
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment); "processed" is not supported. If parameter not provided, the default is "finalized".
#### Results: