wip
This commit is contained in:
committed by
Grimes
parent
57f82934f2
commit
3e1a926aa6
@ -1,6 +1,5 @@
|
|||||||
use crate::bank::BankError;
|
use crate::bank::BankError;
|
||||||
use crate::bank::Result;
|
use crate::bank::Result;
|
||||||
use crate::checkpoint::Checkpoint;
|
|
||||||
use crate::counter::Counter;
|
use crate::counter::Counter;
|
||||||
use crate::status_deque::{StatusDeque, StatusDequeError};
|
use crate::status_deque::{StatusDeque, StatusDequeError};
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
@ -11,7 +10,6 @@ use solana_sdk::hash::{hash, Hash};
|
|||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::transaction::Transaction;
|
use solana_sdk::transaction::Transaction;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::{Mutex, RwLock};
|
use std::sync::{Mutex, RwLock};
|
||||||
|
|
||||||
@ -35,9 +33,6 @@ pub struct AccountsDB {
|
|||||||
/// Mapping of known public keys/IDs to accounts
|
/// Mapping of known public keys/IDs to accounts
|
||||||
pub accounts: HashMap<Pubkey, Account>,
|
pub accounts: HashMap<Pubkey, Account>,
|
||||||
|
|
||||||
/// list of prior states
|
|
||||||
checkpoints: VecDeque<(HashMap<Pubkey, Account>, u64)>,
|
|
||||||
|
|
||||||
/// The number of transactions the bank has processed without error since the
|
/// The number of transactions the bank has processed without error since the
|
||||||
/// start of the ledger.
|
/// start of the ledger.
|
||||||
transaction_count: u64,
|
transaction_count: u64,
|
||||||
@ -55,7 +50,6 @@ impl Default for AccountsDB {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
accounts: HashMap::new(),
|
accounts: HashMap::new(),
|
||||||
checkpoints: VecDeque::new(),
|
|
||||||
transaction_count: 0,
|
transaction_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,24 +85,12 @@ impl AccountsDB {
|
|||||||
if let Some(account) = self.accounts.get(pubkey) {
|
if let Some(account) = self.accounts.get(pubkey) {
|
||||||
return Some(account);
|
return Some(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (accounts, _) in &self.checkpoints {
|
|
||||||
if let Some(account) = accounts.get(pubkey) {
|
|
||||||
return Some(account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store(&mut self, pubkey: &Pubkey, account: &Account) {
|
pub fn store(&mut self, pubkey: &Pubkey, account: &Account) {
|
||||||
if account.tokens == 0 {
|
if account.tokens == 0 {
|
||||||
if self.checkpoints.is_empty() {
|
self.accounts.remove(pubkey);
|
||||||
// purge if balance is 0 and no checkpoints
|
|
||||||
self.accounts.remove(pubkey);
|
|
||||||
} else {
|
|
||||||
// store default account if balance is 0 and there's a checkpoint
|
|
||||||
self.accounts.insert(pubkey.clone(), Account::default());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.accounts.insert(pubkey.clone(), account.clone());
|
self.accounts.insert(pubkey.clone(), account.clone());
|
||||||
}
|
}
|
||||||
@ -266,15 +248,6 @@ impl AccountsDB {
|
|||||||
pub fn transaction_count(&self) -> u64 {
|
pub fn transaction_count(&self) -> u64 {
|
||||||
self.transaction_count
|
self.transaction_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checkpoint_and_copy(&mut self) -> AccountsDB {
|
|
||||||
self.checkpoint();
|
|
||||||
let (accounts, tx_count) = self.checkpoints.front().unwrap();
|
|
||||||
let mut copy = AccountsDB::default();
|
|
||||||
copy.accounts = accounts.clone();
|
|
||||||
copy.transaction_count = *tx_count;
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Accounts {
|
impl Accounts {
|
||||||
@ -392,66 +365,6 @@ impl Accounts {
|
|||||||
pub fn transaction_count(&self) -> u64 {
|
pub fn transaction_count(&self) -> u64 {
|
||||||
self.accounts_db.read().unwrap().transaction_count()
|
self.accounts_db.read().unwrap().transaction_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checkpoint(&self) {
|
|
||||||
self.accounts_db.write().unwrap().checkpoint()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rollback(&self) {
|
|
||||||
self.accounts_db.write().unwrap().rollback()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn purge(&self, depth: usize) {
|
|
||||||
self.accounts_db.write().unwrap().purge(depth)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn depth(&self) -> usize {
|
|
||||||
self.accounts_db.read().unwrap().depth()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn checkpoint_and_copy(&self) -> Accounts {
|
|
||||||
let db = self.accounts_db.write().unwrap().checkpoint_and_copy();
|
|
||||||
let mut copy = Accounts::default();
|
|
||||||
copy.accounts_db = RwLock::new(db);
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Checkpoint for AccountsDB {
|
|
||||||
fn checkpoint(&mut self) {
|
|
||||||
let accounts = self.accounts.clone();
|
|
||||||
|
|
||||||
self.checkpoints
|
|
||||||
.push_front((accounts, self.transaction_count()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rollback(&mut self) {
|
|
||||||
let (accounts, transaction_count) = self.checkpoints.pop_front().unwrap();
|
|
||||||
self.accounts = accounts;
|
|
||||||
self.transaction_count = transaction_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn purge(&mut self, depth: usize) {
|
|
||||||
fn merge(into: &mut HashMap<Pubkey, Account>, purge: &mut HashMap<Pubkey, Account>) {
|
|
||||||
purge.retain(|pubkey, _| !into.contains_key(pubkey));
|
|
||||||
into.extend(purge.drain());
|
|
||||||
into.retain(|_, account| account.tokens != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
while self.depth() > depth {
|
|
||||||
let (mut purge, _) = self.checkpoints.pop_back().unwrap();
|
|
||||||
|
|
||||||
if let Some((into, _)) = self.checkpoints.back_mut() {
|
|
||||||
merge(into, &mut purge);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
merge(&mut self.accounts, &mut purge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn depth(&self) -> usize {
|
|
||||||
self.checkpoints.len()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
238
src/bank.rs
238
src/bank.rs
@ -4,7 +4,6 @@
|
|||||||
//! already been signed and verified.
|
//! already been signed and verified.
|
||||||
|
|
||||||
use crate::accounts::{Accounts, ErrorCounters, InstructionAccounts, InstructionLoaders};
|
use crate::accounts::{Accounts, ErrorCounters, InstructionAccounts, InstructionLoaders};
|
||||||
use crate::checkpoint::Checkpoint;
|
|
||||||
use crate::counter::Counter;
|
use crate::counter::Counter;
|
||||||
use crate::entry::Entry;
|
use crate::entry::Entry;
|
||||||
use crate::entry::EntrySlice;
|
use crate::entry::EntrySlice;
|
||||||
@ -138,48 +137,6 @@ impl Bank {
|
|||||||
*sub = subscriptions
|
*sub = subscriptions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checkpoint this bank and return a copy of it
|
|
||||||
pub fn checkpoint_and_copy(&self) -> Bank {
|
|
||||||
let last_ids_cp = self.last_ids.write().unwrap().checkpoint_and_copy();
|
|
||||||
let accounts = self.accounts.checkpoint_and_copy();
|
|
||||||
|
|
||||||
let mut copy = Bank::default();
|
|
||||||
copy.accounts = accounts;
|
|
||||||
copy.last_ids = RwLock::new(last_ids_cp);
|
|
||||||
copy.leader_scheduler =
|
|
||||||
Arc::new(RwLock::new(self.leader_scheduler.read().unwrap().clone()));
|
|
||||||
copy.confirmation_time = AtomicUsize::new(self.confirmation_time.load(Ordering::Relaxed));
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn checkpoint(&self) {
|
|
||||||
self.accounts.checkpoint();
|
|
||||||
self.last_ids.write().unwrap().checkpoint();
|
|
||||||
}
|
|
||||||
pub fn purge(&self, depth: usize) {
|
|
||||||
self.accounts.purge(depth);
|
|
||||||
self.last_ids.write().unwrap().purge(depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rollback(&self) {
|
|
||||||
let rolled_back_pubkeys: Vec<Pubkey> = self.accounts.keys();
|
|
||||||
self.accounts.rollback();
|
|
||||||
|
|
||||||
rolled_back_pubkeys.iter().for_each(|pubkey| {
|
|
||||||
if let Some(account) = self.accounts.load_slow(&pubkey) {
|
|
||||||
self.subscriptions
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.check_account(&pubkey, &account)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.last_ids.write().unwrap().rollback();
|
|
||||||
}
|
|
||||||
pub fn checkpoint_depth(&self) -> usize {
|
|
||||||
self.accounts.depth()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_genesis_block(&self, genesis_block: &GenesisBlock) {
|
fn process_genesis_block(&self, genesis_block: &GenesisBlock) {
|
||||||
assert!(genesis_block.mint_id != Pubkey::default());
|
assert!(genesis_block.mint_id != Pubkey::default());
|
||||||
assert!(genesis_block.tokens >= genesis_block.bootstrap_leader_tokens);
|
assert!(genesis_block.tokens >= genesis_block.bootstrap_leader_tokens);
|
||||||
@ -869,8 +826,6 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::entry::{next_entries, next_entry, Entry};
|
use crate::entry::{next_entries, next_entry, Entry};
|
||||||
use crate::gen_keys::GenKeys;
|
use crate::gen_keys::GenKeys;
|
||||||
use crate::status_deque;
|
|
||||||
use crate::status_deque::StatusDequeError;
|
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use solana_sdk::hash::hash;
|
use solana_sdk::hash::hash;
|
||||||
@ -1577,199 +1532,6 @@ mod tests {
|
|||||||
assert!(ids.into_iter().all(move |id| unique.insert(id)));
|
assert!(ids.into_iter().all(move |id| unique.insert(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bank_purge() {
|
|
||||||
let (genesis_block, alice) = GenesisBlock::new(10_000);
|
|
||||||
let bank = Bank::new(&genesis_block);
|
|
||||||
let bob = Keypair::new();
|
|
||||||
let charlie = Keypair::new();
|
|
||||||
|
|
||||||
// bob should have 500
|
|
||||||
bank.transfer(500, &alice, bob.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 500);
|
|
||||||
|
|
||||||
bank.transfer(500, &alice, charlie.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
|
|
||||||
bank.checkpoint();
|
|
||||||
bank.checkpoint();
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 2);
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 500);
|
|
||||||
assert_eq!(bank.get_balance(&alice.pubkey()), 9_000);
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.transaction_count(), 2);
|
|
||||||
|
|
||||||
// transfer money back, so bob has zero
|
|
||||||
bank.transfer(500, &bob, alice.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
// this has to be stored as zero in the top accounts hashmap ;)
|
|
||||||
assert!(bank.accounts.load_slow(&bob.pubkey()).is_some());
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 0);
|
|
||||||
// double-checks
|
|
||||||
assert_eq!(bank.get_balance(&alice.pubkey()), 9_500);
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.transaction_count(), 3);
|
|
||||||
bank.purge(1);
|
|
||||||
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 0);
|
|
||||||
// double-checks
|
|
||||||
assert_eq!(bank.get_balance(&alice.pubkey()), 9_500);
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.transaction_count(), 3);
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 1);
|
|
||||||
|
|
||||||
bank.purge(0);
|
|
||||||
|
|
||||||
// bob should still have 0, alice should have 10_000
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 0);
|
|
||||||
assert!(bank.accounts.load_slow(&bob.pubkey()).is_none());
|
|
||||||
// double-checks
|
|
||||||
assert_eq!(bank.get_balance(&alice.pubkey()), 9_500);
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.transaction_count(), 3);
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bank_checkpoint_zero_balance() {
|
|
||||||
let (genesis_block, alice) = GenesisBlock::new(1_000);
|
|
||||||
let bank = Bank::new(&genesis_block);
|
|
||||||
let bob = Keypair::new();
|
|
||||||
let charlie = Keypair::new();
|
|
||||||
|
|
||||||
// bob should have 500
|
|
||||||
bank.transfer(500, &alice, bob.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 500);
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 0);
|
|
||||||
|
|
||||||
let account = bank.get_account(&alice.pubkey()).unwrap();
|
|
||||||
let default_account = Account::default();
|
|
||||||
assert_eq!(account.userdata, default_account.userdata);
|
|
||||||
assert_eq!(account.owner, default_account.owner);
|
|
||||||
assert_eq!(account.executable, default_account.executable);
|
|
||||||
assert_eq!(account.loader, default_account.loader);
|
|
||||||
|
|
||||||
bank.checkpoint();
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 1);
|
|
||||||
|
|
||||||
// charlie should have 500, alice should have 0
|
|
||||||
bank.transfer(500, &alice, charlie.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.get_balance(&alice.pubkey()), 0);
|
|
||||||
|
|
||||||
let account = bank.get_account(&alice.pubkey()).unwrap();
|
|
||||||
assert_eq!(account.tokens, default_account.tokens);
|
|
||||||
assert_eq!(account.userdata, default_account.userdata);
|
|
||||||
assert_eq!(account.owner, default_account.owner);
|
|
||||||
assert_eq!(account.executable, default_account.executable);
|
|
||||||
assert_eq!(account.loader, default_account.loader);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reserve_signature_with_last_id_test(
|
|
||||||
bank: &Bank,
|
|
||||||
sig: &Signature,
|
|
||||||
last_id: &Hash,
|
|
||||||
) -> status_deque::Result<()> {
|
|
||||||
let mut last_ids = bank.last_ids.write().unwrap();
|
|
||||||
last_ids.reserve_signature_with_last_id(last_id, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bank_checkpoint_rollback() {
|
|
||||||
let (genesis_block, alice) = GenesisBlock::new(10_000);
|
|
||||||
let bank = Bank::new(&genesis_block);
|
|
||||||
let bob = Keypair::new();
|
|
||||||
let charlie = Keypair::new();
|
|
||||||
|
|
||||||
// bob should have 500
|
|
||||||
bank.transfer(500, &alice, bob.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 500);
|
|
||||||
bank.transfer(500, &alice, charlie.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 0);
|
|
||||||
|
|
||||||
bank.checkpoint();
|
|
||||||
bank.checkpoint();
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 2);
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 500);
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.transaction_count(), 2);
|
|
||||||
|
|
||||||
// transfer money back, so bob has zero
|
|
||||||
bank.transfer(500, &bob, alice.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
// this has to be stored as zero in the top accounts hashmap ;)
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 0);
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.transaction_count(), 3);
|
|
||||||
bank.rollback();
|
|
||||||
|
|
||||||
// bob should have 500 again
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 500);
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.transaction_count(), 2);
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 1);
|
|
||||||
|
|
||||||
let signature = Signature::default();
|
|
||||||
for i in 0..MAX_ENTRY_IDS + 1 {
|
|
||||||
let last_id = hash(&serialize(&i).unwrap()); // Unique hash
|
|
||||||
bank.register_tick(&last_id);
|
|
||||||
}
|
|
||||||
assert_eq!(bank.tick_height(), MAX_ENTRY_IDS as u64 + 2);
|
|
||||||
assert_eq!(
|
|
||||||
reserve_signature_with_last_id_test(&bank, &signature, &genesis_block.last_id()),
|
|
||||||
Err(StatusDequeError::LastIdNotFound)
|
|
||||||
);
|
|
||||||
bank.rollback();
|
|
||||||
assert_eq!(bank.tick_height(), 1);
|
|
||||||
assert_eq!(
|
|
||||||
reserve_signature_with_last_id_test(&bank, &signature, &genesis_block.last_id()),
|
|
||||||
Ok(())
|
|
||||||
);
|
|
||||||
bank.checkpoint();
|
|
||||||
assert_eq!(
|
|
||||||
reserve_signature_with_last_id_test(&bank, &signature, &genesis_block.last_id()),
|
|
||||||
Err(StatusDequeError::DuplicateSignature)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bank_checkpoint_and_copy() {
|
|
||||||
let (genesis_block, alice) = GenesisBlock::new(10_000);
|
|
||||||
let bank = Bank::new(&genesis_block);
|
|
||||||
let bob = Keypair::new();
|
|
||||||
let charlie = Keypair::new();
|
|
||||||
|
|
||||||
// bob should have 500
|
|
||||||
bank.transfer(500, &alice, bob.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(bank.get_balance(&bob.pubkey()), 500);
|
|
||||||
bank.transfer(500, &alice, charlie.pubkey(), genesis_block.last_id())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 0);
|
|
||||||
|
|
||||||
let cp_bank = bank.checkpoint_and_copy();
|
|
||||||
assert_eq!(cp_bank.get_balance(&bob.pubkey()), 500);
|
|
||||||
assert_eq!(cp_bank.get_balance(&charlie.pubkey()), 500);
|
|
||||||
assert_eq!(cp_bank.checkpoint_depth(), 0);
|
|
||||||
assert_eq!(bank.checkpoint_depth(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_bank_rollback_panic() {
|
|
||||||
let (genesis_block, _) = GenesisBlock::new(10_000);
|
|
||||||
let bank = Bank::new(&genesis_block);
|
|
||||||
bank.rollback();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bank_record_transactions() {
|
fn test_bank_record_transactions() {
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new(10_000);
|
let (genesis_block, mint_keypair) = GenesisBlock::new(10_000);
|
||||||
|
@ -213,7 +213,7 @@ impl BroadcastService {
|
|||||||
if let Err(e) = broadcast.run(&broadcast_table, receiver, sock, leader_scheduler) {
|
if let Err(e) = broadcast.run(&broadcast_table, receiver, sock, leader_scheduler) {
|
||||||
match e {
|
match e {
|
||||||
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => {
|
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => {
|
||||||
return BroadcastServiceReturnType::ChannelDisconnected
|
return BroadcastServiceReturnType::ChannelDisconnected;
|
||||||
}
|
}
|
||||||
Error::RecvTimeoutError(RecvTimeoutError::Timeout) => (),
|
Error::RecvTimeoutError(RecvTimeoutError::Timeout) => (),
|
||||||
Error::ClusterInfoError(ClusterInfoError::NoPeers) => (), // TODO: Why are the unit-tests throwing hundreds of these?
|
Error::ClusterInfoError(ClusterInfoError::NoPeers) => (), // TODO: Why are the unit-tests throwing hundreds of these?
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
pub trait Checkpoint {
|
|
||||||
/// add a checkpoint to this data at current state
|
|
||||||
fn checkpoint(&mut self);
|
|
||||||
|
|
||||||
/// rollback to previous state, panics if no prior checkpoint
|
|
||||||
fn rollback(&mut self);
|
|
||||||
|
|
||||||
/// cull checkpoints to depth, that is depth of zero means
|
|
||||||
/// no checkpoints, only current state
|
|
||||||
fn purge(&mut self, depth: usize);
|
|
||||||
|
|
||||||
/// returns the number of checkpoints
|
|
||||||
fn depth(&self) -> usize;
|
|
||||||
}
|
|
@ -278,7 +278,7 @@ impl Fullnode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let tpu = Tpu::new(
|
let tpu = Tpu::new(
|
||||||
&Arc::new(bank.checkpoint_and_copy()),
|
&bank,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
node.sockets
|
node.sockets
|
||||||
.tpu
|
.tpu
|
||||||
@ -360,7 +360,7 @@ impl Fullnode {
|
|||||||
let (to_validator_sender, to_validator_receiver) = channel();
|
let (to_validator_sender, to_validator_receiver) = channel();
|
||||||
self.role_notifiers.1 = to_validator_receiver;
|
self.role_notifiers.1 = to_validator_receiver;
|
||||||
self.node_services.tpu.switch_to_leader(
|
self.node_services.tpu.switch_to_leader(
|
||||||
&Arc::new(self.bank.checkpoint_and_copy()),
|
&self.bank,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
self.tpu_sockets
|
self.tpu_sockets
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -19,7 +19,6 @@ pub mod broadcast_service;
|
|||||||
pub mod chacha;
|
pub mod chacha;
|
||||||
#[cfg(all(feature = "chacha", feature = "cuda"))]
|
#[cfg(all(feature = "chacha", feature = "cuda"))]
|
||||||
pub mod chacha_cuda;
|
pub mod chacha_cuda;
|
||||||
pub mod checkpoint;
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod crds;
|
pub mod crds;
|
||||||
pub mod crds_gossip;
|
pub mod crds_gossip;
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
use crate::checkpoint::Checkpoint;
|
|
||||||
use crate::poh_service::NUM_TICKS_PER_SECOND;
|
use crate::poh_service::NUM_TICKS_PER_SECOND;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use solana_sdk::hash::Hash;
|
use solana_sdk::hash::Hash;
|
||||||
use solana_sdk::signature::Signature;
|
use solana_sdk::signature::Signature;
|
||||||
use solana_sdk::timing::timestamp;
|
use solana_sdk::timing::timestamp;
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
/// The number of most recent `last_id` values that the bank will track the signatures
|
/// The number of most recent `last_id` values that the bank will track the signatures
|
||||||
@ -67,8 +65,6 @@ pub struct StatusDeque<T> {
|
|||||||
/// reject transactions with signatures it's seen before and to reject
|
/// reject transactions with signatures it's seen before and to reject
|
||||||
/// transactions that are too old (nth is too small)
|
/// transactions that are too old (nth is too small)
|
||||||
entries: StatusEntryMap<T>,
|
entries: StatusEntryMap<T>,
|
||||||
|
|
||||||
checkpoints: VecDeque<(u64, Option<Hash>, StatusEntryMap<T>)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Default for StatusDeque<T> {
|
impl<T> Default for StatusDeque<T> {
|
||||||
@ -77,32 +73,10 @@ impl<T> Default for StatusDeque<T> {
|
|||||||
tick_height: 0,
|
tick_height: 0,
|
||||||
last_id: None,
|
last_id: None,
|
||||||
entries: HashMap::new(),
|
entries: HashMap::new(),
|
||||||
checkpoints: VecDeque::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Checkpoint for StatusDeque<T> {
|
|
||||||
fn checkpoint(&mut self) {
|
|
||||||
self.checkpoints
|
|
||||||
.push_front((self.tick_height, self.last_id, self.entries.clone()));
|
|
||||||
}
|
|
||||||
fn rollback(&mut self) {
|
|
||||||
let (tick_height, last_id, entries) = self.checkpoints.pop_front().unwrap();
|
|
||||||
self.tick_height = tick_height;
|
|
||||||
self.last_id = last_id;
|
|
||||||
self.entries = entries;
|
|
||||||
}
|
|
||||||
fn purge(&mut self, depth: usize) {
|
|
||||||
while self.depth() > depth {
|
|
||||||
self.checkpoints.pop_back().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn depth(&self) -> usize {
|
|
||||||
self.checkpoints.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> StatusDeque<T> {
|
impl<T: Clone> StatusDeque<T> {
|
||||||
pub fn update_signature_status_with_last_id(
|
pub fn update_signature_status_with_last_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -116,15 +90,6 @@ impl<T: Clone> StatusDeque<T> {
|
|||||||
.insert(*signature, Status::Complete(result.clone()));
|
.insert(*signature, Status::Complete(result.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn checkpoint_and_copy(&mut self) -> StatusDeque<T> {
|
|
||||||
self.checkpoint();
|
|
||||||
let (tick_height, last_id, entries) = self.checkpoints.front().unwrap().clone();
|
|
||||||
let mut copy = StatusDeque::default();
|
|
||||||
copy.tick_height = tick_height;
|
|
||||||
copy.last_id = last_id;
|
|
||||||
copy.entries = entries;
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
pub fn reserve_signature_with_last_id(
|
pub fn reserve_signature_with_last_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
last_id: &Hash,
|
last_id: &Hash,
|
||||||
@ -264,23 +229,6 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duplicate_transaction_signature_checkpoint() {
|
|
||||||
let sig = Default::default();
|
|
||||||
let last_id = Default::default();
|
|
||||||
let mut status_deque: StatusDeque<()> = StatusDeque::default();
|
|
||||||
status_deque.register_tick(&last_id);
|
|
||||||
assert_eq!(
|
|
||||||
status_deque.reserve_signature_with_last_id(&last_id, &sig),
|
|
||||||
Ok(())
|
|
||||||
);
|
|
||||||
status_deque.checkpoint();
|
|
||||||
assert_eq!(
|
|
||||||
status_deque.reserve_signature_with_last_id(&last_id, &sig),
|
|
||||||
Err(StatusDequeError::DuplicateSignature)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clear_signatures() {
|
fn test_clear_signatures() {
|
||||||
let signature = Signature::default();
|
let signature = Signature::default();
|
||||||
@ -297,23 +245,6 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_clear_signatures_checkpoint() {
|
|
||||||
let signature = Signature::default();
|
|
||||||
let last_id = Default::default();
|
|
||||||
let mut status_deque: StatusDeque<()> = StatusDeque::default();
|
|
||||||
status_deque.register_tick(&last_id);
|
|
||||||
status_deque
|
|
||||||
.reserve_signature_with_last_id(&last_id, &signature)
|
|
||||||
.unwrap();
|
|
||||||
status_deque.checkpoint();
|
|
||||||
status_deque.clear_signatures();
|
|
||||||
assert_eq!(
|
|
||||||
status_deque.reserve_signature_with_last_id(&last_id, &signature),
|
|
||||||
Ok(())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_signature_status() {
|
fn test_get_signature_status() {
|
||||||
let signature = Signature::default();
|
let signature = Signature::default();
|
||||||
|
Reference in New Issue
Block a user