|
|
|
@@ -434,6 +434,7 @@ impl Blocktree {
|
|
|
|
|
&self,
|
|
|
|
|
shreds: Vec<Shred>,
|
|
|
|
|
leader_schedule: Option<&Arc<LeaderScheduleCache>>,
|
|
|
|
|
is_trusted: bool,
|
|
|
|
|
) -> Result<BlocktreeInsertionMetrics> {
|
|
|
|
|
let mut total_start = Measure::start("Total elapsed");
|
|
|
|
|
let mut start = Measure::start("Blocktree lock");
|
|
|
|
@@ -464,6 +465,7 @@ impl Blocktree {
|
|
|
|
|
&mut write_batch,
|
|
|
|
|
&mut just_inserted_data_shreds,
|
|
|
|
|
&mut index_meta_time,
|
|
|
|
|
is_trusted,
|
|
|
|
|
)
|
|
|
|
|
} else if shred.is_code() {
|
|
|
|
|
self.check_insert_coding_shred(
|
|
|
|
@@ -473,6 +475,7 @@ impl Blocktree {
|
|
|
|
|
&mut write_batch,
|
|
|
|
|
&mut just_inserted_coding_shreds,
|
|
|
|
|
&mut index_meta_time,
|
|
|
|
|
is_trusted,
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
panic!("There should be no other case");
|
|
|
|
@@ -507,6 +510,7 @@ impl Blocktree {
|
|
|
|
|
&mut write_batch,
|
|
|
|
|
&mut just_inserted_data_shreds,
|
|
|
|
|
&mut index_meta_time,
|
|
|
|
|
is_trusted,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -584,6 +588,7 @@ impl Blocktree {
|
|
|
|
|
write_batch: &mut WriteBatch,
|
|
|
|
|
just_inserted_coding_shreds: &mut HashMap<(u64, u64), Shred>,
|
|
|
|
|
index_meta_time: &mut u64,
|
|
|
|
|
is_trusted: bool,
|
|
|
|
|
) -> bool {
|
|
|
|
|
let slot = shred.slot();
|
|
|
|
|
let shred_index = u64::from(shred.index());
|
|
|
|
@@ -594,7 +599,9 @@ impl Blocktree {
|
|
|
|
|
let index_meta = &mut index_meta_working_set_entry.index;
|
|
|
|
|
// This gives the index of first coding shred in this FEC block
|
|
|
|
|
// So, all coding shreds in a given FEC block will have the same set index
|
|
|
|
|
if Blocktree::should_insert_coding_shred(&shred, index_meta.coding(), &self.last_root) {
|
|
|
|
|
if is_trusted
|
|
|
|
|
|| Blocktree::should_insert_coding_shred(&shred, index_meta.coding(), &self.last_root)
|
|
|
|
|
{
|
|
|
|
|
self.insert_coding_shred(erasure_metas, index_meta, &shred, write_batch)
|
|
|
|
|
.map(|_| {
|
|
|
|
|
// Insert was a success!
|
|
|
|
@@ -618,6 +625,7 @@ impl Blocktree {
|
|
|
|
|
write_batch: &mut WriteBatch,
|
|
|
|
|
just_inserted_data_shreds: &mut HashMap<(u64, u64), Shred>,
|
|
|
|
|
index_meta_time: &mut u64,
|
|
|
|
|
is_trusted: bool,
|
|
|
|
|
) -> bool {
|
|
|
|
|
let slot = shred.slot();
|
|
|
|
|
let shred_index = u64::from(shred.index());
|
|
|
|
@@ -631,12 +639,14 @@ impl Blocktree {
|
|
|
|
|
|
|
|
|
|
let slot_meta = &mut slot_meta_entry.new_slot_meta.borrow_mut();
|
|
|
|
|
|
|
|
|
|
if Blocktree::should_insert_data_shred(
|
|
|
|
|
&shred,
|
|
|
|
|
slot_meta,
|
|
|
|
|
index_meta.data(),
|
|
|
|
|
&self.last_root,
|
|
|
|
|
) {
|
|
|
|
|
if is_trusted
|
|
|
|
|
|| Blocktree::should_insert_data_shred(
|
|
|
|
|
&shred,
|
|
|
|
|
slot_meta,
|
|
|
|
|
index_meta.data(),
|
|
|
|
|
&self.last_root,
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if let Ok(()) =
|
|
|
|
|
self.insert_data_shred(slot_meta, index_meta.data_mut(), &shred, write_batch)
|
|
|
|
|
{
|
|
|
|
@@ -954,7 +964,7 @@ impl Blocktree {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let num_shreds = all_shreds.len();
|
|
|
|
|
self.insert_shreds(all_shreds, None)?;
|
|
|
|
|
self.insert_shreds(all_shreds, None, false)?;
|
|
|
|
|
Ok(num_shreds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1736,7 +1746,7 @@ pub fn create_new_ledger(ledger_path: &Path, genesis_block: &GenesisBlock) -> Re
|
|
|
|
|
let shreds = shredder.entries_to_shreds(&entries, true, 0).0;
|
|
|
|
|
assert!(shreds.last().unwrap().last_in_slot());
|
|
|
|
|
|
|
|
|
|
blocktree.insert_shreds(shreds, None)?;
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false)?;
|
|
|
|
|
blocktree.set_roots(&[0])?;
|
|
|
|
|
|
|
|
|
|
Ok(last_hash)
|
|
|
|
@@ -1956,7 +1966,7 @@ pub mod tests {
|
|
|
|
|
let last_shred = shreds.pop().unwrap();
|
|
|
|
|
assert!(last_shred.index() > 0);
|
|
|
|
|
ledger
|
|
|
|
|
.insert_shreds(vec![last_shred.clone()], None)
|
|
|
|
|
.insert_shreds(vec![last_shred.clone()], None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let serialized_shred = ledger
|
|
|
|
@@ -2129,7 +2139,7 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
let ledger_path = get_tmp_ledger_path("test_read_shreds_bytes");
|
|
|
|
|
let ledger = Blocktree::open(&ledger_path).unwrap();
|
|
|
|
|
ledger.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
let mut buf = [0; 4096];
|
|
|
|
|
let (_, bytes) = ledger.get_data_shreds(slot, 0, 1, &mut buf).unwrap();
|
|
|
|
@@ -2196,7 +2206,7 @@ pub mod tests {
|
|
|
|
|
// shreds starting from slot 0, index 0 should exist.
|
|
|
|
|
assert!(shreds.len() > 1);
|
|
|
|
|
let last_shred = shreds.pop().unwrap();
|
|
|
|
|
ledger.insert_shreds(vec![last_shred], None).unwrap();
|
|
|
|
|
ledger.insert_shreds(vec![last_shred], None, false).unwrap();
|
|
|
|
|
assert!(ledger.get_slot_entries(0, 0, None).unwrap().is_empty());
|
|
|
|
|
|
|
|
|
|
let meta = ledger
|
|
|
|
@@ -2206,7 +2216,7 @@ pub mod tests {
|
|
|
|
|
assert!(meta.consumed == 0 && meta.received == num_shreds);
|
|
|
|
|
|
|
|
|
|
// Insert the other shreds, check for consecutive returned entries
|
|
|
|
|
ledger.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
let result = ledger.get_slot_entries(0, 0, None).unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(result, entries);
|
|
|
|
@@ -2240,7 +2250,7 @@ pub mod tests {
|
|
|
|
|
// Insert shreds in reverse, check for consecutive returned shreds
|
|
|
|
|
for i in (0..num_shreds).rev() {
|
|
|
|
|
let shred = shreds.pop().unwrap();
|
|
|
|
|
ledger.insert_shreds(vec![shred], None).unwrap();
|
|
|
|
|
ledger.insert_shreds(vec![shred], None, false).unwrap();
|
|
|
|
|
let result = ledger.get_slot_entries(0, 0, None).unwrap();
|
|
|
|
|
|
|
|
|
|
let meta = ledger
|
|
|
|
@@ -2318,7 +2328,7 @@ pub mod tests {
|
|
|
|
|
let entries = create_ticks(8, Hash::default());
|
|
|
|
|
let shreds = entries_to_test_shreds(entries[0..4].to_vec(), 1, 0, false);
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds, None)
|
|
|
|
|
.insert_shreds(shreds, None, false)
|
|
|
|
|
.expect("Expected successful write of shreds");
|
|
|
|
|
|
|
|
|
|
let mut shreds1 = entries_to_test_shreds(entries[4..].to_vec(), 1, 0, false);
|
|
|
|
@@ -2326,7 +2336,7 @@ pub mod tests {
|
|
|
|
|
b.set_index(8 + i as u32);
|
|
|
|
|
}
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds1, None)
|
|
|
|
|
.insert_shreds(shreds1, None, false)
|
|
|
|
|
.expect("Expected successful write of shreds");
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
@@ -2360,7 +2370,7 @@ pub mod tests {
|
|
|
|
|
index += 1;
|
|
|
|
|
}
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds, None)
|
|
|
|
|
.insert_shreds(shreds, None, false)
|
|
|
|
|
.expect("Expected successful write of shreds");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
blocktree
|
|
|
|
@@ -2393,7 +2403,7 @@ pub mod tests {
|
|
|
|
|
entries_to_test_shreds(entries.clone(), slot, slot.saturating_sub(1), false);
|
|
|
|
|
assert!(shreds.len() as u64 >= shreds_per_slot);
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds, None)
|
|
|
|
|
.insert_shreds(shreds, None, false)
|
|
|
|
|
.expect("Expected successful write of shreds");
|
|
|
|
|
assert_eq!(blocktree.get_slot_entries(slot, 0, None).unwrap(), entries);
|
|
|
|
|
}
|
|
|
|
@@ -2428,7 +2438,7 @@ pub mod tests {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blocktree.insert_shreds(odd_shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(odd_shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(blocktree.get_slot_entries(slot, 0, None).unwrap(), vec![]);
|
|
|
|
|
|
|
|
|
@@ -2446,7 +2456,7 @@ pub mod tests {
|
|
|
|
|
assert_eq!(meta.last_index, std::u64::MAX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blocktree.insert_shreds(even_shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(even_shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
blocktree.get_slot_entries(slot, 0, None).unwrap(),
|
|
|
|
@@ -2479,13 +2489,17 @@ pub mod tests {
|
|
|
|
|
// Discard first shred
|
|
|
|
|
original_shreds.remove(0);
|
|
|
|
|
|
|
|
|
|
blocktree.insert_shreds(original_shreds, None).unwrap();
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(original_shreds, None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(blocktree.get_slot_entries(0, 0, None).unwrap(), vec![]);
|
|
|
|
|
|
|
|
|
|
let duplicate_shreds = entries_to_test_shreds(original_entries.clone(), 0, 0, true);
|
|
|
|
|
let num_shreds = duplicate_shreds.len() as u64;
|
|
|
|
|
blocktree.insert_shreds(duplicate_shreds, None).unwrap();
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(duplicate_shreds, None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
blocktree.get_slot_entries(0, 0, None).unwrap(),
|
|
|
|
@@ -2515,16 +2529,20 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
// Insert second shred, but we're missing the first shred, so no consecutive
|
|
|
|
|
// shreds starting from slot 0, index 0 should exist.
|
|
|
|
|
ledger.insert_shreds(vec![shreds.remove(1)], None).unwrap();
|
|
|
|
|
ledger
|
|
|
|
|
.insert_shreds(vec![shreds.remove(1)], None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let timer = Duration::new(1, 0);
|
|
|
|
|
assert!(recvr.recv_timeout(timer).is_err());
|
|
|
|
|
// Insert first shred, now we've made a consecutive block
|
|
|
|
|
ledger.insert_shreds(vec![shreds.remove(0)], None).unwrap();
|
|
|
|
|
ledger
|
|
|
|
|
.insert_shreds(vec![shreds.remove(0)], None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
// Wait to get notified of update, should only be one update
|
|
|
|
|
assert!(recvr.recv_timeout(timer).is_ok());
|
|
|
|
|
assert!(recvr.try_recv().is_err());
|
|
|
|
|
// Insert the rest of the ticks
|
|
|
|
|
ledger.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
// Wait to get notified of update, should only be one update
|
|
|
|
|
assert!(recvr.recv_timeout(timer).is_ok());
|
|
|
|
|
assert!(recvr.try_recv().is_err());
|
|
|
|
@@ -2543,7 +2561,7 @@ pub mod tests {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Should be no updates, since no new chains from block 0 were formed
|
|
|
|
|
ledger.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
assert!(recvr.recv_timeout(timer).is_err());
|
|
|
|
|
|
|
|
|
|
// Insert a shred for each slot that doesn't make a consecutive block, we
|
|
|
|
@@ -2556,7 +2574,7 @@ pub mod tests {
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
ledger.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
assert!(recvr.recv_timeout(timer).is_err());
|
|
|
|
|
|
|
|
|
|
// For slots 1..num_slots/2, fill in the holes in one batch insertion,
|
|
|
|
@@ -2564,13 +2582,13 @@ pub mod tests {
|
|
|
|
|
let missing_shreds2 = missing_shreds
|
|
|
|
|
.drain((num_slots / 2) as usize..)
|
|
|
|
|
.collect_vec();
|
|
|
|
|
ledger.insert_shreds(missing_shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(missing_shreds, None, false).unwrap();
|
|
|
|
|
assert!(recvr.recv_timeout(timer).is_ok());
|
|
|
|
|
assert!(recvr.try_recv().is_err());
|
|
|
|
|
|
|
|
|
|
// Fill in the holes for each of the remaining slots, we should get a single update
|
|
|
|
|
// for each
|
|
|
|
|
ledger.insert_shreds(missing_shreds2, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(missing_shreds2, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
// Destroying database without closing it first is undefined behavior
|
|
|
|
|
drop(ledger);
|
|
|
|
@@ -2591,11 +2609,11 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
let shred0 = shreds.remove(0);
|
|
|
|
|
// Insert all but the first shred in the slot, should not be considered complete
|
|
|
|
|
ledger.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
assert!(recvr.try_recv().is_err());
|
|
|
|
|
|
|
|
|
|
// Insert first shred, slot should now be considered complete
|
|
|
|
|
ledger.insert_shreds(vec![shred0], None).unwrap();
|
|
|
|
|
ledger.insert_shreds(vec![shred0], None, false).unwrap();
|
|
|
|
|
assert_eq!(recvr.try_recv().unwrap(), vec![0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2618,20 +2636,24 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
// Insert all but the first shred in the slot, should not be considered complete
|
|
|
|
|
let orphan_child0 = orphan_child.remove(0);
|
|
|
|
|
ledger.insert_shreds(orphan_child, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(orphan_child, None, false).unwrap();
|
|
|
|
|
assert!(recvr.try_recv().is_err());
|
|
|
|
|
|
|
|
|
|
// Insert first shred, slot should now be considered complete
|
|
|
|
|
ledger.insert_shreds(vec![orphan_child0], None).unwrap();
|
|
|
|
|
ledger
|
|
|
|
|
.insert_shreds(vec![orphan_child0], None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(recvr.try_recv().unwrap(), vec![slots[2]]);
|
|
|
|
|
|
|
|
|
|
// Insert the shreds for the orphan_slot
|
|
|
|
|
let orphan_shred0 = orphan_shreds.remove(0);
|
|
|
|
|
ledger.insert_shreds(orphan_shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(orphan_shreds, None, false).unwrap();
|
|
|
|
|
assert!(recvr.try_recv().is_err());
|
|
|
|
|
|
|
|
|
|
// Insert first shred, slot should now be considered complete
|
|
|
|
|
ledger.insert_shreds(vec![orphan_shred0], None).unwrap();
|
|
|
|
|
ledger
|
|
|
|
|
.insert_shreds(vec![orphan_shred0], None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(recvr.try_recv().unwrap(), vec![slots[1]]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2658,7 +2680,7 @@ pub mod tests {
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
all_shreds.shuffle(&mut thread_rng());
|
|
|
|
|
ledger.insert_shreds(all_shreds, None).unwrap();
|
|
|
|
|
ledger.insert_shreds(all_shreds, None, false).unwrap();
|
|
|
|
|
let mut result = recvr.try_recv().unwrap();
|
|
|
|
|
result.sort();
|
|
|
|
|
slots.push(disconnected_slot);
|
|
|
|
@@ -2682,7 +2704,7 @@ pub mod tests {
|
|
|
|
|
let shreds1 = shreds
|
|
|
|
|
.drain(shreds_per_slot..2 * shreds_per_slot)
|
|
|
|
|
.collect_vec();
|
|
|
|
|
blocktree.insert_shreds(shreds1, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds1, None, false).unwrap();
|
|
|
|
|
let s1 = blocktree.meta(1).unwrap().unwrap();
|
|
|
|
|
assert!(s1.next_slots.is_empty());
|
|
|
|
|
// Slot 1 is not trunk because slot 0 hasn't been inserted yet
|
|
|
|
@@ -2694,7 +2716,7 @@ pub mod tests {
|
|
|
|
|
let shreds2 = shreds
|
|
|
|
|
.drain(shreds_per_slot..2 * shreds_per_slot)
|
|
|
|
|
.collect_vec();
|
|
|
|
|
blocktree.insert_shreds(shreds2, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds2, None, false).unwrap();
|
|
|
|
|
let s2 = blocktree.meta(2).unwrap().unwrap();
|
|
|
|
|
assert!(s2.next_slots.is_empty());
|
|
|
|
|
// Slot 2 is not trunk because slot 0 hasn't been inserted yet
|
|
|
|
@@ -2712,7 +2734,7 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
// 3) Write to the zeroth slot, check that every slot
|
|
|
|
|
// is now part of the trunk
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
for i in 0..3 {
|
|
|
|
|
let s = blocktree.meta(i).unwrap().unwrap();
|
|
|
|
|
// The last slot will not chain to any other slots
|
|
|
|
@@ -2762,7 +2784,7 @@ pub mod tests {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write the shreds for every other slot
|
|
|
|
|
blocktree.insert_shreds(slots, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(slots, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
// Check metadata
|
|
|
|
|
for i in 0..num_slots {
|
|
|
|
@@ -2788,7 +2810,7 @@ pub mod tests {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write the shreds for the other half of the slots that we didn't insert earlier
|
|
|
|
|
blocktree.insert_shreds(missing_slots, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(missing_slots, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
for i in 0..num_slots {
|
|
|
|
|
// Check that all the slots chain correctly once the missing slots
|
|
|
|
@@ -2834,9 +2856,13 @@ pub mod tests {
|
|
|
|
|
if slot % 3 == 0 {
|
|
|
|
|
let shred0 = shreds_for_slot.remove(0);
|
|
|
|
|
missing_shreds.push(shred0);
|
|
|
|
|
blocktree.insert_shreds(shreds_for_slot, None).unwrap();
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds_for_slot, None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
} else {
|
|
|
|
|
blocktree.insert_shreds(shreds_for_slot, None).unwrap();
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds_for_slot, None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2871,7 +2897,7 @@ pub mod tests {
|
|
|
|
|
for slot_index in 0..num_slots {
|
|
|
|
|
if slot_index % 3 == 0 {
|
|
|
|
|
let shred = missing_shreds.remove(0);
|
|
|
|
|
blocktree.insert_shreds(vec![shred], None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(vec![shred], None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
for i in 0..num_slots {
|
|
|
|
|
let s = blocktree.meta(i as u64).unwrap().unwrap();
|
|
|
|
@@ -3052,7 +3078,9 @@ pub mod tests {
|
|
|
|
|
// Write slot 2, which chains to slot 1. We're missing slot 0,
|
|
|
|
|
// so slot 1 is the orphan
|
|
|
|
|
let shreds_for_slot = shreds.drain((shreds_per_slot * 2)..).collect_vec();
|
|
|
|
|
blocktree.insert_shreds(shreds_for_slot, None).unwrap();
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds_for_slot, None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let meta = blocktree
|
|
|
|
|
.meta(1)
|
|
|
|
|
.expect("Expect database get to succeed")
|
|
|
|
@@ -3063,7 +3091,9 @@ pub mod tests {
|
|
|
|
|
// Write slot 1 which chains to slot 0, so now slot 0 is the
|
|
|
|
|
// orphan, and slot 1 is no longer the orphan.
|
|
|
|
|
let shreds_for_slot = shreds.drain(shreds_per_slot..).collect_vec();
|
|
|
|
|
blocktree.insert_shreds(shreds_for_slot, None).unwrap();
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds_for_slot, None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let meta = blocktree
|
|
|
|
|
.meta(1)
|
|
|
|
|
.expect("Expect database get to succeed")
|
|
|
|
@@ -3080,12 +3110,12 @@ pub mod tests {
|
|
|
|
|
// nothing should change
|
|
|
|
|
let (shred4, _) = make_slot_entries(4, 0, 1);
|
|
|
|
|
let (shred5, _) = make_slot_entries(5, 1, 1);
|
|
|
|
|
blocktree.insert_shreds(shred4, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shred5, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shred4, None, false).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shred5, None, false).unwrap();
|
|
|
|
|
assert_eq!(blocktree.get_orphans(None), vec![0]);
|
|
|
|
|
|
|
|
|
|
// Write zeroth slot, no more orphans
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
for i in 0..3 {
|
|
|
|
|
let meta = blocktree
|
|
|
|
|
.meta(i)
|
|
|
|
@@ -3131,11 +3161,11 @@ pub mod tests {
|
|
|
|
|
let num_shreds = shreds.len();
|
|
|
|
|
// Write shreds to the database
|
|
|
|
|
if should_bulk_write {
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
} else {
|
|
|
|
|
for _ in 0..num_shreds {
|
|
|
|
|
let shred = shreds.remove(0);
|
|
|
|
|
blocktree.insert_shreds(vec![shred], None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(vec![shred], None, false).unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -3179,7 +3209,7 @@ pub mod tests {
|
|
|
|
|
s.set_index(i as u32 * gap as u32);
|
|
|
|
|
s.set_slot(slot);
|
|
|
|
|
}
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
// Index of the first shred is 0
|
|
|
|
|
// Index of the second shred is "gap"
|
|
|
|
@@ -3261,7 +3291,7 @@ pub mod tests {
|
|
|
|
|
let shreds: Vec<_> = (0..64)
|
|
|
|
|
.map(|i| Shred::new_from_data(slot, (i * gap) as u32, 0, None, false, false, i as u8))
|
|
|
|
|
.collect();
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
let empty: Vec<u64> = vec![];
|
|
|
|
|
assert_eq!(
|
|
|
|
@@ -3304,7 +3334,7 @@ pub mod tests {
|
|
|
|
|
shreds[1].set_index(OTHER as u32);
|
|
|
|
|
|
|
|
|
|
// Insert one shred at index = first_index
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
const STARTS: u64 = OTHER * 2;
|
|
|
|
|
const END: u64 = OTHER * 3;
|
|
|
|
@@ -3338,7 +3368,7 @@ pub mod tests {
|
|
|
|
|
let shreds = entries_to_test_shreds(entries, slot, 0, true);
|
|
|
|
|
let num_shreds = shreds.len();
|
|
|
|
|
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
let empty: Vec<u64> = vec![];
|
|
|
|
|
for i in 0..num_shreds as u64 {
|
|
|
|
@@ -3365,7 +3395,7 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
// Insert the first 5 shreds, we don't have a "is_last" shred yet
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds[0..5].to_vec(), None)
|
|
|
|
|
.insert_shreds(shreds[0..5].to_vec(), None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// Trying to insert a shred less than `slot_meta.consumed` should fail
|
|
|
|
@@ -3385,7 +3415,7 @@ pub mod tests {
|
|
|
|
|
// Trying to insert the same shred again should fail
|
|
|
|
|
// skip over shred 5 so the `slot_meta.consumed` doesn't increment
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds[6..7].to_vec(), None)
|
|
|
|
|
.insert_shreds(shreds[6..7].to_vec(), None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let slot_meta = blocktree.meta(0).unwrap().unwrap();
|
|
|
|
|
let index = index_cf.get(0).unwrap().unwrap();
|
|
|
|
@@ -3402,7 +3432,7 @@ pub mod tests {
|
|
|
|
|
// Trying to insert another "is_last" shred with index < the received index should fail
|
|
|
|
|
// skip over shred 7
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds[8..9].to_vec(), None)
|
|
|
|
|
.insert_shreds(shreds[8..9].to_vec(), None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let slot_meta = blocktree.meta(0).unwrap().unwrap();
|
|
|
|
|
let index = index_cf.get(0).unwrap().unwrap();
|
|
|
|
@@ -3422,7 +3452,7 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
// Insert all pending shreds
|
|
|
|
|
let mut shred8 = shreds[8].clone();
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
let slot_meta = blocktree.meta(0).unwrap().unwrap();
|
|
|
|
|
let index = index_cf.get(0).unwrap().unwrap();
|
|
|
|
|
|
|
|
|
@@ -3465,7 +3495,7 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
// Insertion should succeed
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(vec![coding_shred.clone()], None)
|
|
|
|
|
.insert_shreds(vec![coding_shred.clone()], None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// Trying to insert the same shred again should fail
|
|
|
|
@@ -3572,7 +3602,9 @@ pub mod tests {
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
// Insertion should succeed
|
|
|
|
|
blocktree.insert_shreds(vec![coding_shred], None).unwrap();
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(vec![coding_shred], None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Trying to insert value into slot <= than last root should fail
|
|
|
|
@@ -3602,7 +3634,7 @@ pub mod tests {
|
|
|
|
|
let blocktree_path = get_tmp_ledger_path!();
|
|
|
|
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
|
|
|
|
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
let slot_meta = blocktree.meta(0).unwrap().unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(slot_meta.consumed, num_shreds);
|
|
|
|
@@ -3611,7 +3643,7 @@ pub mod tests {
|
|
|
|
|
assert!(slot_meta.is_full());
|
|
|
|
|
|
|
|
|
|
let (shreds, _) = make_slot_entries(0, 0, 22);
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
let slot_meta = blocktree.meta(0).unwrap().unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(slot_meta.consumed, num_shreds);
|
|
|
|
@@ -3633,7 +3665,7 @@ pub mod tests {
|
|
|
|
|
let all_shreds = make_chaining_slot_entries(&slots, shreds_per_slot);
|
|
|
|
|
let slot_8_shreds = all_shreds[2].0.clone();
|
|
|
|
|
for (slot_shreds, _) in all_shreds {
|
|
|
|
|
blocktree.insert_shreds(slot_shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(slot_shreds, None, false).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Slot doesnt exist, iterator should be empty
|
|
|
|
@@ -3678,7 +3710,7 @@ pub mod tests {
|
|
|
|
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
|
|
|
|
let (shreds, _) = make_many_slot_entries(0, 50, 6);
|
|
|
|
|
let shreds_per_slot = shreds.len() as u64 / 50;
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
blocktree
|
|
|
|
|
.slot_meta_iterator(0)
|
|
|
|
|
.unwrap()
|
|
|
|
@@ -3713,7 +3745,7 @@ pub mod tests {
|
|
|
|
|
let blocktree_path = get_tmp_ledger_path!();
|
|
|
|
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
|
|
|
|
let (shreds, _) = make_many_slot_entries(0, 50, 5);
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
blocktree.purge_slots(0, Some(5));
|
|
|
|
|
|
|
|
|
@@ -3739,7 +3771,7 @@ pub mod tests {
|
|
|
|
|
let blocktree_path = get_tmp_ledger_path!();
|
|
|
|
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
|
|
|
|
let (shreds, _) = make_many_slot_entries(0, 5000, 10);
|
|
|
|
|
blocktree.insert_shreds(shreds, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
|
|
|
|
|
|
blocktree.purge_slots(0, Some(4999));
|
|
|
|
|
|
|
|
|
@@ -3854,7 +3886,7 @@ pub mod tests {
|
|
|
|
|
let shreds = entries_to_test_shreds(entries, slot, 0, false);
|
|
|
|
|
let next_shred_index = shreds.len();
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds, None)
|
|
|
|
|
.insert_shreds(shreds, None, false)
|
|
|
|
|
.expect("Expected successful write of shreds");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
blocktree.get_slot_entries(slot, 0, None).unwrap().len() as u64,
|
|
|
|
@@ -3875,7 +3907,7 @@ pub mod tests {
|
|
|
|
|
// With the corruption, nothing should be returned, even though an
|
|
|
|
|
// earlier data block was valid
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds, None)
|
|
|
|
|
.insert_shreds(shreds, None, false)
|
|
|
|
|
.expect("Expected successful write of shreds");
|
|
|
|
|
assert!(blocktree.get_slot_entries(slot, 0, None).is_err());
|
|
|
|
|
}
|
|
|
|
@@ -3893,7 +3925,7 @@ pub mod tests {
|
|
|
|
|
|
|
|
|
|
// Insert the first 5 shreds, we don't have a "is_last" shred yet
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds0[0..5].to_vec(), None)
|
|
|
|
|
.insert_shreds(shreds0[0..5].to_vec(), None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// Insert a repetitive shred for slot 's', should get ignored, but also
|
|
|
|
@@ -3903,13 +3935,37 @@ pub mod tests {
|
|
|
|
|
let (mut shreds3, _) = make_slot_entries(3, 0, 200);
|
|
|
|
|
shreds2.push(shreds0[1].clone());
|
|
|
|
|
shreds3.insert(0, shreds0[1].clone());
|
|
|
|
|
blocktree.insert_shreds(shreds2, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds2, None, false).unwrap();
|
|
|
|
|
let slot_meta = blocktree.meta(0).unwrap().unwrap();
|
|
|
|
|
assert_eq!(slot_meta.next_slots, vec![2]);
|
|
|
|
|
blocktree.insert_shreds(shreds3, None).unwrap();
|
|
|
|
|
blocktree.insert_shreds(shreds3, None, false).unwrap();
|
|
|
|
|
let slot_meta = blocktree.meta(0).unwrap().unwrap();
|
|
|
|
|
assert_eq!(slot_meta.next_slots, vec![2, 3]);
|
|
|
|
|
}
|
|
|
|
|
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_trusted_insert_shreds() {
|
|
|
|
|
// Make shred for slot 1
|
|
|
|
|
let (shreds1, _) = make_slot_entries(1, 0, 1);
|
|
|
|
|
let blocktree_path = get_tmp_ledger_path!();
|
|
|
|
|
let last_root = 100;
|
|
|
|
|
{
|
|
|
|
|
let blocktree = Blocktree::open(&blocktree_path).unwrap();
|
|
|
|
|
blocktree.set_roots(&[last_root]).unwrap();
|
|
|
|
|
|
|
|
|
|
// Insert will fail, slot < root
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds1.clone()[..].to_vec(), None, false)
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert!(blocktree.get_data_shred(1, 0).unwrap().is_none());
|
|
|
|
|
|
|
|
|
|
// Insert through trusted path will succeed
|
|
|
|
|
blocktree
|
|
|
|
|
.insert_shreds(shreds1[..].to_vec(), None, true)
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert!(blocktree.get_data_shred(1, 0).unwrap().is_some());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|