Skip to content

Commit 72d3aab

Browse files
fanatidleafaar
authored andcommitted
rpc: add rollback to getLatestBlockhash (agave#2023)
1 parent 75ced5e commit 72d3aab

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

rpc-client-api/src/config.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,12 @@ pub struct RpcContextConfig {
358358
pub struct RpcRecentPrioritizationFeesConfig {
359359
pub percentile: Option<u16>,
360360
}
361+
362+
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
363+
#[serde(rename_all = "camelCase")]
364+
pub struct RpcLatestBlockhashConfig {
365+
#[serde(flatten)]
366+
pub context: RpcContextConfig,
367+
#[serde(default)]
368+
pub rollback: usize,
369+
}

rpc-client/src/nonblocking/rpc_client.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4565,6 +4565,27 @@ impl RpcClient {
45654565
Ok(blockhash)
45664566
}
45674567

4568+
pub async fn get_latest_blockhash_with_config(
4569+
&self,
4570+
config: RpcLatestBlockhashConfig,
4571+
) -> ClientResult<(Hash, u64)> {
4572+
let RpcBlockhash {
4573+
blockhash,
4574+
last_valid_block_height,
4575+
} = self
4576+
.send::<Response<RpcBlockhash>>(RpcRequest::GetLatestBlockhash, json!([config]))
4577+
.await?
4578+
.value;
4579+
let blockhash = blockhash.parse().map_err(|_| {
4580+
ClientError::new_with_request(
4581+
RpcError::ParseError("Hash".to_string()).into(),
4582+
RpcRequest::GetLatestBlockhash,
4583+
)
4584+
})?;
4585+
Ok((blockhash, last_valid_block_height))
4586+
}
4587+
4588+
#[allow(deprecated)]
45684589
pub async fn get_latest_blockhash_with_commitment(
45694590
&self,
45704591
commitment: CommitmentConfig,

rpc/src/rpc.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,8 +2359,28 @@ impl JsonRpcRequestProcessor {
23592359
}
23602360
}
23612361

2362-
fn get_latest_blockhash(&self, config: RpcContextConfig) -> Result<RpcResponse<RpcBlockhash>> {
2363-
let bank = self.get_bank_with_config(config)?;
2362+
fn get_latest_blockhash(
2363+
&self,
2364+
config: RpcLatestBlockhashConfig,
2365+
) -> Result<RpcResponse<RpcBlockhash>> {
2366+
let mut bank = self.get_bank_with_config(config.context)?;
2367+
if config.rollback > MAX_PROCESSING_AGE {
2368+
return Err(Error::invalid_params(format!("rollback exceeds ${MAX_PROCESSING_AGE}")));
2369+
}
2370+
if config.rollback > 0 {
2371+
let r_bank_forks = self.bank_forks.read().unwrap();
2372+
for _ in 0..config.rollback {
2373+
bank = match r_bank_forks.get(bank.parent_slot()).or_else(|| {
2374+
r_bank_forks
2375+
.banks_frozen
2376+
.get(&bank.parent_slot())
2377+
.map(Clone::clone)
2378+
}) {
2379+
Some(bank) => bank,
2380+
None => return Err(Error::invalid_params("failed to rollback block")),
2381+
};
2382+
}
2383+
}
23642384
let blockhash = bank.last_blockhash();
23652385
let last_valid_block_height = bank
23662386
.get_blockhash_last_valid_block_height(&blockhash)
@@ -3624,7 +3644,7 @@ pub mod rpc_full {
36243644
fn get_latest_blockhash(
36253645
&self,
36263646
meta: Self::Metadata,
3627-
config: Option<RpcContextConfig>,
3647+
config: Option<RpcLatestBlockhashConfig>,
36283648
) -> Result<RpcResponse<RpcBlockhash>>;
36293649

36303650
#[rpc(meta, name = "isBlockhashValid")]
@@ -4293,7 +4313,7 @@ pub mod rpc_full {
42934313
fn get_latest_blockhash(
42944314
&self,
42954315
meta: Self::Metadata,
4296-
config: Option<RpcContextConfig>,
4316+
config: Option<RpcLatestBlockhashConfig>,
42974317
) -> Result<RpcResponse<RpcBlockhash>> {
42984318
debug!("get_latest_blockhash rpc request received");
42994319
meta.get_latest_blockhash(config.unwrap_or_default())

runtime/src/bank_forks.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ use {
1515
solana_measure::measure::Measure,
1616
solana_program_runtime::loaded_programs::{BlockRelation, ForkGraph},
1717
solana_sdk::{
18-
clock::{BankId, Slot},
18+
clock::{BankId, Slot, MAX_PROCESSING_AGE},
1919
hash::Hash,
2020
},
2121
solana_unified_scheduler_logic::SchedulingMode,
2222
std::{
23-
collections::{hash_map::Entry, HashMap, HashSet},
23+
collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
2424
ops::Index,
2525
sync::{
2626
atomic::{AtomicBool, AtomicU64, Ordering},
@@ -74,6 +74,7 @@ struct SetRootTimings {
7474

7575
pub struct BankForks {
7676
banks: HashMap<Slot, BankWithScheduler>,
77+
pub banks_frozen: BTreeMap<Slot, Arc<Bank>>,
7778
descendants: HashMap<Slot, HashSet<Slot>>,
7879
root: Arc<AtomicSlot>,
7980

@@ -129,6 +130,7 @@ impl BankForks {
129130
let bank_forks = Arc::new(RwLock::new(Self {
130131
root: Arc::new(AtomicSlot::new(root_slot)),
131132
banks,
133+
banks_frozen: Default::default(),
132134
descendants,
133135
snapshot_config: None,
134136
accounts_hash_interval_slots: u64::MAX,
@@ -268,6 +270,13 @@ impl BankForks {
268270

269271
pub fn remove(&mut self, slot: Slot) -> Option<BankWithScheduler> {
270272
let bank = self.banks.remove(&slot)?;
273+
if bank.is_frozen() {
274+
self.banks_frozen
275+
.insert(bank.slot(), bank.clone_without_scheduler());
276+
while self.banks_frozen.len() > MAX_PROCESSING_AGE {
277+
self.banks_frozen.pop_first();
278+
}
279+
}
271280
for parent in bank.proper_ancestors() {
272281
let Entry::Occupied(mut entry) = self.descendants.entry(parent) else {
273282
panic!("this should not happen!");

0 commit comments

Comments
 (0)