remove duplicate child creation (#3100)
* remove duplicate child creation * resurrect test for partial slot * simplify blocktree_processor some more (no tick_height, yay!) * ensure frozen
This commit is contained in:
@ -2449,15 +2449,21 @@ pub mod tests {
|
|||||||
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
|
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entries_to_blobs(entries: &Vec<Entry>, slot_height: u64, parent_slot: u64) -> Vec<Blob> {
|
pub fn entries_to_blobs(
|
||||||
|
entries: &Vec<Entry>,
|
||||||
|
slot_height: u64,
|
||||||
|
parent_slot: u64,
|
||||||
|
is_full_slot: bool,
|
||||||
|
) -> Vec<Blob> {
|
||||||
let mut blobs = entries.clone().to_blobs();
|
let mut blobs = entries.clone().to_blobs();
|
||||||
for (i, b) in blobs.iter_mut().enumerate() {
|
for (i, b) in blobs.iter_mut().enumerate() {
|
||||||
b.set_index(i as u64);
|
b.set_index(i as u64);
|
||||||
b.set_slot(slot_height);
|
b.set_slot(slot_height);
|
||||||
b.set_parent(parent_slot);
|
b.set_parent(parent_slot);
|
||||||
}
|
}
|
||||||
|
if is_full_slot {
|
||||||
blobs.last_mut().unwrap().set_is_last_in_slot();
|
blobs.last_mut().unwrap().set_is_last_in_slot();
|
||||||
|
}
|
||||||
blobs
|
blobs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2467,7 +2473,7 @@ pub mod tests {
|
|||||||
num_entries: u64,
|
num_entries: u64,
|
||||||
) -> (Vec<Blob>, Vec<Entry>) {
|
) -> (Vec<Blob>, Vec<Entry>) {
|
||||||
let entries = make_tiny_test_entries(num_entries as usize);
|
let entries = make_tiny_test_entries(num_entries as usize);
|
||||||
let blobs = entries_to_blobs(&entries, slot_height, parent_slot);
|
let blobs = entries_to_blobs(&entries, slot_height, parent_slot, true);
|
||||||
(blobs, entries)
|
(blobs, entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,30 +116,24 @@ pub fn process_blocktree(
|
|||||||
let bank = Arc::new(Bank::new_with_paths(&genesis_block, account_paths));
|
let bank = Arc::new(Bank::new_with_paths(&genesis_block, account_paths));
|
||||||
let entry_height = 0;
|
let entry_height = 0;
|
||||||
let last_entry_hash = bank.last_blockhash();
|
let last_entry_hash = bank.last_blockhash();
|
||||||
vec![(slot, bank, entry_height, last_entry_hash)]
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut fork_info = vec![];
|
|
||||||
while !pending_slots.is_empty() {
|
|
||||||
let (slot, starting_bank, starting_entry_height, mut last_entry_hash) =
|
|
||||||
pending_slots.pop().unwrap();
|
|
||||||
|
|
||||||
let bank = Arc::new(Bank::new_from_parent(
|
|
||||||
&starting_bank,
|
|
||||||
leader_schedule_utils::slot_leader_at(slot, &starting_bank),
|
|
||||||
starting_bank.slot(),
|
|
||||||
));
|
|
||||||
let mut entry_height = starting_entry_height;
|
|
||||||
|
|
||||||
// Load the metadata for this slot
|
// Load the metadata for this slot
|
||||||
let meta = blocktree
|
let meta = blocktree
|
||||||
.meta(slot)
|
.meta(slot)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
warn!("Failed to load meta for slot {}: {:?}", slot, err);
|
eprintln!("Failed to load meta for slot {}: {:?}", slot, err);
|
||||||
BankError::LedgerVerificationFailed
|
BankError::LedgerVerificationFailed
|
||||||
})?
|
})?
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
vec![(slot, meta, bank, entry_height, last_entry_hash)]
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut fork_info = vec![];
|
||||||
|
while !pending_slots.is_empty() {
|
||||||
|
let (slot, meta, bank, mut entry_height, mut last_entry_hash) =
|
||||||
|
pending_slots.pop().unwrap();
|
||||||
|
|
||||||
// Fetch all entries for this slot
|
// Fetch all entries for this slot
|
||||||
let mut entries = blocktree.get_slot_entries(slot, 0, None).map_err(|err| {
|
let mut entries = blocktree.get_slot_entries(slot, 0, None).map_err(|err| {
|
||||||
warn!("Failed to load entries for slot {}: {:?}", slot, err);
|
warn!("Failed to load entries for slot {}: {:?}", slot, err);
|
||||||
@ -166,7 +160,10 @@ pub fn process_blocktree(
|
|||||||
|
|
||||||
if !entries.is_empty() {
|
if !entries.is_empty() {
|
||||||
if !entries.verify(&last_entry_hash) {
|
if !entries.verify(&last_entry_hash) {
|
||||||
warn!("Ledger proof of history failed at entry: {}", entry_height);
|
warn!(
|
||||||
|
"Ledger proof of history failed at slot: {}, entry: {}",
|
||||||
|
slot, entry_height
|
||||||
|
);
|
||||||
return Err(BankError::LedgerVerificationFailed);
|
return Err(BankError::LedgerVerificationFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,30 +176,11 @@ pub fn process_blocktree(
|
|||||||
entry_height += entries.len() as u64;
|
entry_height += entries.len() as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
let slot_complete =
|
// TODO merge with locktower, voting, bank.vote_accounts()...
|
||||||
leader_schedule_utils::num_ticks_left_in_slot(&bank, bank.tick_height()) == 0;
|
|
||||||
if !slot_complete {
|
|
||||||
// Slot was not complete, clear out any partial entries
|
|
||||||
// TODO: Walk |meta.next_slots| and clear all child slots too?
|
|
||||||
blocktree.reset_slot_consumed(slot).map_err(|err| {
|
|
||||||
warn!("Failed to reset partial slot {}: {:?}", slot, err);
|
|
||||||
BankError::LedgerVerificationFailed
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let bfi = BankForksInfo {
|
|
||||||
bank_slot: slot,
|
|
||||||
entry_height: starting_entry_height,
|
|
||||||
};
|
|
||||||
fork_info.push((starting_bank, bfi));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO merge with locktower, voting
|
|
||||||
bank.squash();
|
bank.squash();
|
||||||
|
|
||||||
if meta.next_slots.is_empty() {
|
if meta.next_slots.is_empty() {
|
||||||
// Reached the end of this fork. Record the final entry height and last entry.hash
|
// Reached the end of this fork. Record the final entry height and last entry.hash
|
||||||
|
|
||||||
let bfi = BankForksInfo {
|
let bfi = BankForksInfo {
|
||||||
bank_slot: slot,
|
bank_slot: slot,
|
||||||
entry_height,
|
entry_height,
|
||||||
@ -212,16 +190,40 @@ pub fn process_blocktree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is a fork point, create a new child bank for each fork
|
// This is a fork point, create a new child bank for each fork
|
||||||
pending_slots.extend(meta.next_slots.iter().map(|next_slot| {
|
for next_slot in meta.next_slots {
|
||||||
let child_bank = Arc::new(Bank::new_from_parent(
|
let next_meta = blocktree
|
||||||
|
.meta(next_slot)
|
||||||
|
.map_err(|err| {
|
||||||
|
eprintln!("Failed to load meta for slot {}: {:?}", slot, err);
|
||||||
|
BankError::LedgerVerificationFailed
|
||||||
|
})?
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// only process full slots in blocktree_processor, replay_stage
|
||||||
|
// handles any partials
|
||||||
|
if next_meta.is_full() {
|
||||||
|
let next_bank = Arc::new(Bank::new_from_parent(
|
||||||
&bank,
|
&bank,
|
||||||
leader_schedule_utils::slot_leader_at(*next_slot, &bank),
|
leader_schedule_utils::slot_leader_at(next_slot, &bank),
|
||||||
*next_slot,
|
next_slot,
|
||||||
));
|
));
|
||||||
trace!("Add child bank for slot={}", next_slot);
|
trace!("Add child bank for slot={}", next_slot);
|
||||||
// bank_forks.insert(*next_slot, child_bank);
|
// bank_forks.insert(*next_slot, child_bank);
|
||||||
(*next_slot, child_bank, entry_height, last_entry_hash)
|
pending_slots.push((
|
||||||
}));
|
next_slot,
|
||||||
|
next_meta,
|
||||||
|
next_bank,
|
||||||
|
entry_height,
|
||||||
|
last_entry_hash,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
let bfi = BankForksInfo {
|
||||||
|
bank_slot: slot,
|
||||||
|
entry_height,
|
||||||
|
};
|
||||||
|
fork_info.push((bank.clone(), bfi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// reverse sort by slot, so the next slot to be processed can be pop()ed
|
// reverse sort by slot, so the next slot to be processed can be pop()ed
|
||||||
// TODO: remove me once leader_scheduler can hang with out-of-order slots?
|
// TODO: remove me once leader_scheduler can hang with out-of-order slots?
|
||||||
@ -260,7 +262,7 @@ mod tests {
|
|||||||
let entries = create_ticks(ticks_per_slot, last_entry_hash);
|
let entries = create_ticks(ticks_per_slot, last_entry_hash);
|
||||||
let last_entry_hash = entries.last().unwrap().hash;
|
let last_entry_hash = entries.last().unwrap().hash;
|
||||||
|
|
||||||
let blobs = entries_to_blobs(&entries, slot, parent_slot);
|
let blobs = entries_to_blobs(&entries, slot, parent_slot, true);
|
||||||
blocktree.insert_data_blobs(blobs.iter()).unwrap();
|
blocktree.insert_data_blobs(blobs.iter()).unwrap();
|
||||||
|
|
||||||
last_entry_hash
|
last_entry_hash
|
||||||
@ -276,11 +278,11 @@ mod tests {
|
|||||||
/*
|
/*
|
||||||
Build a blocktree in the ledger with the following fork structure:
|
Build a blocktree in the ledger with the following fork structure:
|
||||||
|
|
||||||
slot 0
|
slot 0 (all ticks)
|
||||||
|
|
|
|
||||||
slot 1
|
slot 1 (all ticks but one)
|
||||||
|
|
|
|
||||||
slot 2
|
slot 2 (all ticks)
|
||||||
|
|
||||||
where slot 1 is incomplete (missing 1 tick at the end)
|
where slot 1 is incomplete (missing 1 tick at the end)
|
||||||
*/
|
*/
|
||||||
@ -300,9 +302,10 @@ mod tests {
|
|||||||
let mut entries = create_ticks(ticks_per_slot, blockhash);
|
let mut entries = create_ticks(ticks_per_slot, blockhash);
|
||||||
blockhash = entries.last().unwrap().hash;
|
blockhash = entries.last().unwrap().hash;
|
||||||
|
|
||||||
|
// throw away last one
|
||||||
entries.pop();
|
entries.pop();
|
||||||
|
|
||||||
let blobs = entries_to_blobs(&entries, slot, parent_slot);
|
let blobs = entries_to_blobs(&entries, slot, parent_slot, false);
|
||||||
blocktree.insert_data_blobs(blobs.iter()).unwrap();
|
blocktree.insert_data_blobs(blobs.iter()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +319,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank_forks_info[0],
|
bank_forks_info[0],
|
||||||
BankForksInfo {
|
BankForksInfo {
|
||||||
bank_slot: 1, // never finished first slot
|
bank_slot: 0, // slot 1 isn't "full", we stop at slot zero
|
||||||
entry_height: ticks_per_slot,
|
entry_height: ticks_per_slot,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -385,9 +388,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure bank_forks holds the right banks
|
// Ensure bank_forks holds the right banks, and that everything's
|
||||||
|
// frozen
|
||||||
for info in bank_forks_info {
|
for info in bank_forks_info {
|
||||||
assert_eq!(bank_forks[info.bank_slot].slot(), info.bank_slot);
|
assert_eq!(bank_forks[info.bank_slot].slot(), info.bank_slot);
|
||||||
|
assert!(bank_forks[info.bank_slot].is_frozen());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,9 +153,11 @@ impl Bank {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new bank that points to an immutable checkpoint of another bank.
|
/// Create a new bank that points to an immutable checkpoint of another bank.
|
||||||
pub fn new_from_parent(parent: &Arc<Bank>, collector_id: Pubkey, id: u64) -> Self {
|
pub fn new_from_parent(parent: &Arc<Bank>, collector_id: Pubkey, slot: u64) -> Self {
|
||||||
parent.freeze();
|
parent.freeze();
|
||||||
|
|
||||||
|
assert_ne!(slot, parent.slot());
|
||||||
|
|
||||||
let mut bank = Self::default();
|
let mut bank = Self::default();
|
||||||
bank.blockhash_queue = RwLock::new(parent.blockhash_queue.read().unwrap().clone());
|
bank.blockhash_queue = RwLock::new(parent.blockhash_queue.read().unwrap().clone());
|
||||||
bank.tick_height
|
bank.tick_height
|
||||||
@ -164,7 +166,7 @@ impl Bank {
|
|||||||
bank.slots_per_epoch = parent.slots_per_epoch;
|
bank.slots_per_epoch = parent.slots_per_epoch;
|
||||||
bank.stakers_slot_offset = parent.stakers_slot_offset;
|
bank.stakers_slot_offset = parent.stakers_slot_offset;
|
||||||
|
|
||||||
bank.slot = id;
|
bank.slot = slot;
|
||||||
bank.parent = RwLock::new(Some(parent.clone()));
|
bank.parent = RwLock::new(Some(parent.clone()));
|
||||||
bank.parent_hash = parent.hash();
|
bank.parent_hash = parent.hash();
|
||||||
bank.collector_id = collector_id;
|
bank.collector_id = collector_id;
|
||||||
|
Reference in New Issue
Block a user