Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rpc: add rollback to getLatestBlockhash (agave#2023)
Browse files Browse the repository at this point in the history
fanatid committed Oct 14, 2024

Verified

This commit was signed with the committer’s verified signature.
fanatid Kirill Fomichev
1 parent 3e2e9c8 commit c4286fa
Showing 4 changed files with 65 additions and 6 deletions.
9 changes: 9 additions & 0 deletions rpc-client-api/src/config.rs
Original file line number Diff line number Diff line change
@@ -360,3 +360,12 @@ pub struct RpcContextConfig {
pub struct RpcRecentPrioritizationFeesConfig {
pub percentile: Option<u16>,
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RpcLatestBlockhashConfig {
#[serde(flatten)]
pub context: RpcContextConfig,
#[serde(default)]
pub rollback: usize,
}
21 changes: 21 additions & 0 deletions rpc-client/src/nonblocking/rpc_client.rs
Original file line number Diff line number Diff line change
@@ -4578,6 +4578,27 @@ impl RpcClient {
Ok(blockhash)
}

pub async fn get_latest_blockhash_with_config(
&self,
config: RpcLatestBlockhashConfig,
) -> ClientResult<(Hash, u64)> {
let RpcBlockhash {
blockhash,
last_valid_block_height,
} = self
.send::<Response<RpcBlockhash>>(RpcRequest::GetLatestBlockhash, json!([config]))
.await?
.value;
let blockhash = blockhash.parse().map_err(|_| {
ClientError::new_with_request(
RpcError::ParseError("Hash".to_string()).into(),
RpcRequest::GetLatestBlockhash,
)
})?;
Ok((blockhash, last_valid_block_height))
}

#[allow(deprecated)]
pub async fn get_latest_blockhash_with_commitment(
&self,
commitment: CommitmentConfig,
28 changes: 24 additions & 4 deletions rpc/src/rpc.rs
Original file line number Diff line number Diff line change
@@ -2190,8 +2190,28 @@ impl JsonRpcRequestProcessor {
}
}

fn get_latest_blockhash(&self, config: RpcContextConfig) -> Result<RpcResponse<RpcBlockhash>> {
let bank = self.get_bank_with_config(config)?;
fn get_latest_blockhash(
&self,
config: RpcLatestBlockhashConfig,
) -> Result<RpcResponse<RpcBlockhash>> {
let mut bank = self.get_bank_with_config(config.context)?;
if config.rollback > MAX_PROCESSING_AGE {
return Err(Error::invalid_params("rollback exceeds 300"));
}
if config.rollback > 0 {
let r_bank_forks = self.bank_forks.read().unwrap();
for _ in 0..config.rollback {
bank = match r_bank_forks.get(bank.parent_slot()).or_else(|| {
r_bank_forks
.banks_frozen
.get(&bank.parent_slot())
.map(Clone::clone)
}) {
Some(bank) => bank,
None => return Err(Error::invalid_params("failed to rollback block")),
};
}
}
let blockhash = bank.last_blockhash();
let last_valid_block_height = bank
.get_blockhash_last_valid_block_height(&blockhash)
@@ -3428,7 +3448,7 @@ pub mod rpc_full {
fn get_latest_blockhash(
&self,
meta: Self::Metadata,
config: Option<RpcContextConfig>,
config: Option<RpcLatestBlockhashConfig>,
) -> Result<RpcResponse<RpcBlockhash>>;

#[rpc(meta, name = "isBlockhashValid")]
@@ -4104,7 +4124,7 @@ pub mod rpc_full {
fn get_latest_blockhash(
&self,
meta: Self::Metadata,
config: Option<RpcContextConfig>,
config: Option<RpcLatestBlockhashConfig>,
) -> Result<RpcResponse<RpcBlockhash>> {
debug!("get_latest_blockhash rpc request received");
meta.get_latest_blockhash(config.unwrap_or_default())
13 changes: 11 additions & 2 deletions runtime/src/bank_forks.rs
Original file line number Diff line number Diff line change
@@ -14,12 +14,12 @@ use {
solana_measure::measure::Measure,
solana_program_runtime::loaded_programs::{BlockRelation, ForkGraph},
solana_sdk::{
clock::{Epoch, Slot},
clock::{Epoch, Slot, MAX_PROCESSING_AGE},
hash::Hash,
timing,
},
std::{
collections::{hash_map::Entry, HashMap, HashSet},
collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
ops::Index,
sync::{
atomic::{AtomicBool, AtomicU64, Ordering},
@@ -72,6 +72,7 @@ struct SetRootTimings {

pub struct BankForks {
banks: HashMap<Slot, BankWithScheduler>,
pub banks_frozen: BTreeMap<Slot, Arc<Bank>>,
descendants: HashMap<Slot, HashSet<Slot>>,
root: Arc<AtomicSlot>,

@@ -125,6 +126,7 @@ impl BankForks {
let bank_forks = Arc::new(RwLock::new(Self {
root: Arc::new(AtomicSlot::new(root_slot)),
banks,
banks_frozen: Default::default(),
descendants,
snapshot_config: None,
accounts_hash_interval_slots: u64::MAX,
@@ -255,6 +257,13 @@ impl BankForks {

pub fn remove(&mut self, slot: Slot) -> Option<BankWithScheduler> {
let bank = self.banks.remove(&slot)?;
if bank.is_frozen() {
self.banks_frozen
.insert(bank.slot(), bank.clone_without_scheduler());
while self.banks_frozen.len() > MAX_PROCESSING_AGE {
self.banks_frozen.pop_first();
}
}
for parent in bank.proper_ancestors() {
let Entry::Occupied(mut entry) = self.descendants.entry(parent) else {
panic!("this should not happen!");

0 comments on commit c4286fa

Please sign in to comment.