diff --git a/core/src/commitment_service.rs b/core/src/commitment_service.rs index 9974faafdec90d..9c6998928fcb5c 100644 --- a/core/src/commitment_service.rs +++ b/core/src/commitment_service.rs @@ -1,12 +1,9 @@ -use crate::{ - consensus::Stake, - rpc_subscriptions::{CacheSlotInfo, RpcSubscriptions}, -}; +use crate::{consensus::Stake, rpc_subscriptions::RpcSubscriptions}; use solana_measure::measure::Measure; use solana_metrics::datapoint_info; use solana_runtime::{ bank::Bank, - commitment::{BlockCommitment, BlockCommitmentCache, VOTE_THRESHOLD_SIZE}, + commitment::{BlockCommitment, BlockCommitmentCache, CacheSlotInfo, VOTE_THRESHOLD_SIZE}, }; use solana_sdk::clock::Slot; use solana_vote_program::vote_state::VoteState; @@ -114,14 +111,16 @@ impl AggregateCommitmentService { let mut new_block_commitment = BlockCommitmentCache::new( block_commitment, - highest_confirmed_root, aggregation_data.total_stake, - aggregation_data.bank.slot(), - aggregation_data.root, - aggregation_data.root, + CacheSlotInfo { + slot: aggregation_data.bank.slot(), + root: aggregation_data.root, + highest_confirmed_slot: aggregation_data.root, + highest_confirmed_root, + }, ); - new_block_commitment.highest_confirmed_slot = - new_block_commitment.calculate_highest_confirmed_slot(); + let highest_confirmed_slot = new_block_commitment.calculate_highest_confirmed_slot(); + new_block_commitment.set_highest_confirmed_slot(highest_confirmed_slot); let mut w_block_commitment_cache = block_commitment_cache.write().unwrap(); @@ -136,12 +135,10 @@ impl AggregateCommitmentService { ) ); - subscriptions.notify_subscribers(CacheSlotInfo { - current_slot: w_block_commitment_cache.slot(), - node_root: w_block_commitment_cache.root(), - highest_confirmed_root: w_block_commitment_cache.highest_confirmed_root(), - highest_confirmed_slot: w_block_commitment_cache.highest_confirmed_slot(), - }); + // Triggers rpc_subscription notifications as soon as new commitment data is available, + // sending just the commitment cache slot information that the notifications thread + // needs + subscriptions.notify_subscribers(w_block_commitment_cache.slot_info()); } } diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 861d89e0b42116..7da7182d139deb 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -27,7 +27,7 @@ use solana_runtime::{ accounts::AccountAddressFilter, bank::Bank, bank_forks::BankForks, - commitment::{BlockCommitmentArray, BlockCommitmentCache}, + commitment::{BlockCommitmentArray, BlockCommitmentCache, CacheSlotInfo}, log_collector::LogCollector, send_transaction_service::{SendTransactionService, TransactionInfo}, }; @@ -192,10 +192,12 @@ impl JsonRpcRequestProcessor { block_commitment_cache: Arc::new(RwLock::new(BlockCommitmentCache::new( HashMap::new(), 0, - 0, - bank.slot(), - 0, - 0, + CacheSlotInfo { + slot: bank.slot(), + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, ))), blockstore, validator_exit: create_validator_exit(&exit), @@ -1816,11 +1818,13 @@ pub mod tests { block_commitment.entry(1).or_insert(commitment_slot1); let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new( block_commitment, - 0, 10, - bank.slot(), - 0, - 0, + CacheSlotInfo { + slot: bank.slot(), + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, ))); // Add timestamp vote to blockstore @@ -3329,11 +3333,13 @@ pub mod tests { .or_insert_with(|| commitment_slot1.clone()); let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new( block_commitment, - 0, 42, - bank_forks.read().unwrap().highest_slot(), - 0, - 0, + CacheSlotInfo { + slot: bank_forks.read().unwrap().highest_slot(), + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, ))); let mut config = JsonRpcConfig::default(); @@ -3856,11 +3862,13 @@ pub mod tests { let highest_confirmed_root = 1; let block_commitment_cache = BlockCommitmentCache::new( block_commitment, - highest_confirmed_root, 50, - bank.slot(), - 0, - 0, + CacheSlotInfo { + slot: bank.slot(), + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root, + }, ); assert!(is_confirmed_rooted( diff --git a/core/src/rpc_pubsub.rs b/core/src/rpc_pubsub.rs index 8d3c29e3196309..c00fbf76e38075 100644 --- a/core/src/rpc_pubsub.rs +++ b/core/src/rpc_pubsub.rs @@ -349,7 +349,7 @@ mod tests { use super::*; use crate::{ cluster_info_vote_listener::{ClusterInfoVoteListener, VoteTracker}, - rpc_subscriptions::{tests::robust_poll_or_panic, CacheSlotInfo}, + rpc_subscriptions::tests::robust_poll_or_panic, }; use crossbeam_channel::unbounded; use jsonrpc_core::{futures::sync::mpsc, Response}; @@ -359,7 +359,7 @@ mod tests { use solana_runtime::{ bank::Bank, bank_forks::BankForks, - commitment::BlockCommitmentCache, + commitment::{BlockCommitmentCache, CacheSlotInfo}, genesis_utils::{ create_genesis_config, create_genesis_config_with_vote_accounts, GenesisConfigInfo, ValidatorVoteKeypairs, @@ -393,7 +393,7 @@ mod tests { .unwrap() .process_transaction(tx)?; let mut cache_slot_info = CacheSlotInfo::default(); - cache_slot_info.current_slot = current_slot; + cache_slot_info.slot = current_slot; subscriptions.notify_subscribers(cache_slot_info); Ok(()) } @@ -733,14 +733,14 @@ mod tests { .process_transaction(&tx) .unwrap(); let mut cache_slot_info = CacheSlotInfo::default(); - cache_slot_info.current_slot = 1; + cache_slot_info.slot = 1; rpc.subscriptions.notify_subscribers(cache_slot_info); let cache_slot_info = CacheSlotInfo { - current_slot: 2, - node_root: 1, - highest_confirmed_root: 1, + slot: 2, + root: 1, highest_confirmed_slot: 1, + highest_confirmed_root: 1, }; rpc.subscriptions.notify_subscribers(cache_slot_info); let expected = json!({ diff --git a/core/src/rpc_subscriptions.rs b/core/src/rpc_subscriptions.rs index 88f0c85f16b646..c98ecb84a4332b 100644 --- a/core/src/rpc_subscriptions.rs +++ b/core/src/rpc_subscriptions.rs @@ -11,7 +11,11 @@ use solana_account_decoder::{UiAccount, UiAccountEncoding}; use solana_client::rpc_response::{ Response, RpcKeyedAccount, RpcResponseContext, RpcSignatureResult, }; -use solana_runtime::{bank::Bank, bank_forks::BankForks, commitment::BlockCommitmentCache}; +use solana_runtime::{ + bank::Bank, + bank_forks::BankForks, + commitment::{BlockCommitmentCache, CacheSlotInfo}, +}; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, @@ -43,14 +47,6 @@ pub struct SlotInfo { pub root: Slot, } -#[derive(Default)] -pub struct CacheSlotInfo { - pub current_slot: Slot, - pub node_root: Slot, - pub highest_confirmed_root: Slot, - pub highest_confirmed_slot: Slot, -} - // A more human-friendly version of Vote, with the bank state signature base58 encoded. #[derive(Serialize, Deserialize, Debug)] pub struct RpcVote { @@ -75,11 +71,9 @@ impl std::fmt::Debug for NotificationEntry { NotificationEntry::Frozen(slot) => write!(f, "Frozen({})", slot), NotificationEntry::Vote(vote) => write!(f, "Vote({:?})", vote), NotificationEntry::Slot(slot_info) => write!(f, "Slot({:?})", slot_info), - NotificationEntry::Bank(cache_slot_info) => write!( - f, - "Bank({{current_slot: {:?}}})", - cache_slot_info.current_slot - ), + NotificationEntry::Bank(cache_slot_info) => { + write!(f, "Bank({{slot: {:?}}})", cache_slot_info.slot) + } NotificationEntry::Gossip(slot) => write!(f, "Gossip({:?})", slot), } } @@ -180,8 +174,8 @@ where { let slot = match commitment.commitment { CommitmentLevel::Max => cache_slot_info.highest_confirmed_root, - CommitmentLevel::Recent => cache_slot_info.current_slot, - CommitmentLevel::Root => cache_slot_info.node_root, + CommitmentLevel::Recent => cache_slot_info.slot, + CommitmentLevel::Root => cache_slot_info.root, CommitmentLevel::Single | CommitmentLevel::SingleGossip => { cache_slot_info.highest_confirmed_slot } @@ -995,7 +989,7 @@ pub(crate) mod tests { .process_transaction(&tx) .unwrap(); let mut cache_slot_info = CacheSlotInfo::default(); - cache_slot_info.current_slot = 1; + cache_slot_info.slot = 1; subscriptions.notify_subscribers(cache_slot_info); let (response, _) = robust_poll_or_panic(transport_receiver); let expected = json!({ @@ -1156,8 +1150,16 @@ pub(crate) mod tests { let mut block_commitment = HashMap::new(); block_commitment.entry(0).or_insert(cache0); block_commitment.entry(1).or_insert(cache1); - let block_commitment_cache = - BlockCommitmentCache::new(block_commitment, 0, 10, bank1.slot(), 0, 0); + let block_commitment_cache = BlockCommitmentCache::new( + block_commitment, + 10, + CacheSlotInfo { + slot: bank1.slot(), + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, + ); let exit = Arc::new(AtomicBool::new(false)); let subscriptions = RpcSubscriptions::new( @@ -1209,7 +1211,7 @@ pub(crate) mod tests { assert!(sig_subs.contains_key(&processed_tx.signatures[0])); } let mut cache_slot_info = CacheSlotInfo::default(); - cache_slot_info.current_slot = 1; + cache_slot_info.slot = 1; subscriptions.notify_subscribers(cache_slot_info); let expected_res = RpcSignatureResult { err: None }; diff --git a/runtime/src/commitment.rs b/runtime/src/commitment.rs index eec37e187adb7e..f01701367f8c80 100644 --- a/runtime/src/commitment.rs +++ b/runtime/src/commitment.rs @@ -35,15 +35,17 @@ impl BlockCommitment { } } +/// A node's view of cluster commitment as per a particular bank #[derive(Default)] pub struct BlockCommitmentCache { + /// Map of all commitment levels of current ancestor slots, aggregated from the vote account + /// data in the bank block_commitment: HashMap, - highest_confirmed_root: Slot, + /// Cache slot details. Cluster data is calculated from the block_commitment map, and cached in + /// the struct to avoid the expense of recalculating on every call. + slot_info: CacheSlotInfo, + /// Total stake active during the bank's epoch total_stake: u64, - /// The slot of the bank from which all other slots were calculated. - slot: Slot, - root: Slot, - pub highest_confirmed_slot: Slot, } impl std::fmt::Debug for BlockCommitmentCache { @@ -53,9 +55,9 @@ impl std::fmt::Debug for BlockCommitmentCache { .field("total_stake", &self.total_stake) .field( "bank", - &format_args!("Bank({{current_slot: {:?}}})", self.slot), + &format_args!("Bank({{current_slot: {:?}}})", self.slot_info.slot), ) - .field("root", &self.root) + .field("root", &self.slot_info.root) .finish() } } @@ -63,19 +65,13 @@ impl std::fmt::Debug for BlockCommitmentCache { impl BlockCommitmentCache { pub fn new( block_commitment: HashMap, - highest_confirmed_root: Slot, total_stake: u64, - slot: Slot, - root: Slot, - highest_confirmed_slot: Slot, + slot_info: CacheSlotInfo, ) -> Self { Self { block_commitment, - highest_confirmed_root, total_stake, - slot, - root, - highest_confirmed_slot, + slot_info, } } @@ -83,24 +79,28 @@ impl BlockCommitmentCache { self.block_commitment.get(&slot) } - pub fn highest_confirmed_root(&self) -> Slot { - self.highest_confirmed_root - } - pub fn total_stake(&self) -> u64 { self.total_stake } pub fn slot(&self) -> Slot { - self.slot + self.slot_info.slot } pub fn root(&self) -> Slot { - self.root + self.slot_info.root } pub fn highest_confirmed_slot(&self) -> Slot { - self.highest_confirmed_slot + self.slot_info.highest_confirmed_slot + } + + pub fn highest_confirmed_root(&self) -> Slot { + self.slot_info.highest_confirmed_root + } + + pub fn slot_info(&self) -> CacheSlotInfo { + self.slot_info } fn highest_slot_with_confirmation_count(&self, confirmation_count: usize) -> Slot { @@ -112,7 +112,7 @@ impl BlockCommitmentCache { } } } - self.root + self.slot_info.root } pub fn calculate_highest_confirmed_slot(&self) -> Slot { @@ -155,18 +155,36 @@ impl BlockCommitmentCache { Self { block_commitment, total_stake: 42, - highest_confirmed_root: root, - slot, - root, - highest_confirmed_slot: root, + slot_info: CacheSlotInfo { + slot, + root, + highest_confirmed_slot: root, + highest_confirmed_root: root, + }, } } + pub fn set_highest_confirmed_slot(&mut self, slot: Slot) { + self.slot_info.highest_confirmed_slot = slot; + } + pub fn set_highest_confirmed_root(&mut self, root: Slot) { - self.highest_confirmed_root = root; + self.slot_info.highest_confirmed_root = root; } } +#[derive(Default, Clone, Copy)] +pub struct CacheSlotInfo { + /// The slot of the bank from which all other slots were calculated. + pub slot: Slot, + /// The current node root + pub root: Slot, + /// Highest cluster-confirmed slot + pub highest_confirmed_slot: Slot, + /// Highest cluster-confirmed root + pub highest_confirmed_root: Slot, +} + #[cfg(test)] mod tests { use super::*; @@ -200,7 +218,11 @@ mod tests { block_commitment.entry(0).or_insert(cache0); block_commitment.entry(1).or_insert(cache1); block_commitment.entry(2).or_insert(cache2); - let block_commitment_cache = BlockCommitmentCache::new(block_commitment, 0, 50, 0, 0, 0); + let block_commitment_cache = BlockCommitmentCache { + block_commitment, + total_stake: 50, + ..BlockCommitmentCache::default() + }; assert_eq!(block_commitment_cache.get_confirmation_count(0), Some(2)); assert_eq!(block_commitment_cache.get_confirmation_count(1), Some(1)); @@ -232,8 +254,16 @@ mod tests { block_commitment.entry(1).or_insert_with(|| cache0.clone()); // Slot 1, conf 2 block_commitment.entry(2).or_insert_with(|| cache1.clone()); // Slot 2, conf 1 block_commitment.entry(3).or_insert_with(|| cache2.clone()); // Slot 3, conf 0 - let block_commitment_cache = - BlockCommitmentCache::new(block_commitment, 0, total_stake, bank_slot_5, 0, 0); + let block_commitment_cache = BlockCommitmentCache::new( + block_commitment, + total_stake, + CacheSlotInfo { + slot: bank_slot_5, + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, + ); assert_eq!(block_commitment_cache.calculate_highest_confirmed_slot(), 2); @@ -242,8 +272,16 @@ mod tests { block_commitment.entry(1).or_insert_with(|| cache1.clone()); // Slot 1, conf 1 block_commitment.entry(2).or_insert_with(|| cache1.clone()); // Slot 2, conf 1 block_commitment.entry(3).or_insert_with(|| cache2.clone()); // Slot 3, conf 0 - let block_commitment_cache = - BlockCommitmentCache::new(block_commitment, 0, total_stake, bank_slot_5, 0, 0); + let block_commitment_cache = BlockCommitmentCache::new( + block_commitment, + total_stake, + CacheSlotInfo { + slot: bank_slot_5, + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, + ); assert_eq!(block_commitment_cache.calculate_highest_confirmed_slot(), 2); @@ -252,8 +290,16 @@ mod tests { block_commitment.entry(1).or_insert_with(|| cache1.clone()); // Slot 1, conf 1 block_commitment.entry(3).or_insert(cache1); // Slot 3, conf 1 block_commitment.entry(5).or_insert_with(|| cache2.clone()); // Slot 5, conf 0 - let block_commitment_cache = - BlockCommitmentCache::new(block_commitment, 0, total_stake, bank_slot_5, 0, 0); + let block_commitment_cache = BlockCommitmentCache::new( + block_commitment, + total_stake, + CacheSlotInfo { + slot: bank_slot_5, + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, + ); assert_eq!(block_commitment_cache.calculate_highest_confirmed_slot(), 3); @@ -262,8 +308,16 @@ mod tests { block_commitment.entry(1).or_insert(cache0); // Slot 1, conf 2 block_commitment.entry(2).or_insert_with(|| cache2.clone()); // Slot 2, conf 0 block_commitment.entry(3).or_insert_with(|| cache2.clone()); // Slot 3, conf 0 - let block_commitment_cache = - BlockCommitmentCache::new(block_commitment, 0, total_stake, bank_slot_5, 0, 0); + let block_commitment_cache = BlockCommitmentCache::new( + block_commitment, + total_stake, + CacheSlotInfo { + slot: bank_slot_5, + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, + ); assert_eq!(block_commitment_cache.calculate_highest_confirmed_slot(), 1); @@ -272,8 +326,16 @@ mod tests { block_commitment.entry(1).or_insert_with(|| cache2.clone()); // Slot 1, conf 0 block_commitment.entry(2).or_insert_with(|| cache2.clone()); // Slot 2, conf 0 block_commitment.entry(3).or_insert(cache2); // Slot 3, conf 0 - let block_commitment_cache = - BlockCommitmentCache::new(block_commitment, 0, total_stake, bank_slot_5, 0, 0); + let block_commitment_cache = BlockCommitmentCache::new( + block_commitment, + total_stake, + CacheSlotInfo { + slot: bank_slot_5, + root: 0, + highest_confirmed_slot: 0, + highest_confirmed_root: 0, + }, + ); assert_eq!(block_commitment_cache.calculate_highest_confirmed_slot(), 0); }