Fix get_first_available_block for genesis; also make get_blocks(_with_limit) consistent (#24760)
* Handle genesis more appropriately in get_first_available_block * Add unit test * Make get_blocks starting-slots consistent with other methods
This commit is contained in:
parent
8be726aa67
commit
b6a18e0e87
|
@ -1930,11 +1930,17 @@ impl Blockstore {
|
|||
|
||||
/// The first complete block that is available in the Blockstore ledger
|
||||
pub fn get_first_available_block(&self) -> Result<Slot> {
|
||||
let mut root_iterator = self.rooted_slot_iterator(self.lowest_slot())?;
|
||||
// The block at root-index 0 cannot be complete, because it is missing its parent
|
||||
// blockhash. A parent blockhash must be calculated from the entries of the previous block.
|
||||
// Therefore, the first available complete block is that at root-index 1.
|
||||
Ok(root_iterator.nth(1).unwrap_or_default())
|
||||
let mut root_iterator = self.rooted_slot_iterator(self.lowest_slot_with_genesis())?;
|
||||
let first_root = root_iterator.next().unwrap_or_default();
|
||||
// If the first root is slot 0, it is genesis. Genesis is always complete, so it is correct
|
||||
// to return it as first-available.
|
||||
if first_root == 0 {
|
||||
return Ok(first_root);
|
||||
}
|
||||
// Otherwise, the block at root-index 0 cannot ever be complete, because it is missing its
|
||||
// parent blockhash. A parent blockhash must be calculated from the entries of the previous
|
||||
// block. Therefore, the first available complete block is that at root-index 1.
|
||||
Ok(root_iterator.next().unwrap_or_default())
|
||||
}
|
||||
|
||||
pub fn get_rooted_block(
|
||||
|
@ -3160,6 +3166,19 @@ impl Blockstore {
|
|||
self.last_root()
|
||||
}
|
||||
|
||||
fn lowest_slot_with_genesis(&self) -> Slot {
|
||||
for (slot, meta) in self
|
||||
.slot_meta_iterator(0)
|
||||
.expect("unable to iterate over meta")
|
||||
{
|
||||
if meta.received > 0 {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
// This means blockstore is empty, should never get here aside from right at boot.
|
||||
self.last_root()
|
||||
}
|
||||
|
||||
pub fn lowest_cleanup_slot(&self) -> Slot {
|
||||
*self.lowest_cleanup_slot.read().unwrap()
|
||||
}
|
||||
|
@ -6309,6 +6328,31 @@ pub mod tests {
|
|||
assert!(blockstore.get_data_shred(1, 0).unwrap().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_first_available_block() {
|
||||
let mint_total = 1_000_000_000_000;
|
||||
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(mint_total);
|
||||
let (ledger_path, _blockhash) = create_new_tmp_ledger_auto_delete!(&genesis_config);
|
||||
let blockstore = Blockstore::open(ledger_path.path()).unwrap();
|
||||
assert_eq!(blockstore.get_first_available_block().unwrap(), 0);
|
||||
assert_eq!(blockstore.lowest_slot_with_genesis(), 0);
|
||||
assert_eq!(blockstore.lowest_slot(), 0);
|
||||
for slot in 1..4 {
|
||||
let entries = make_slot_entries_with_transactions(100);
|
||||
let shreds = entries_to_test_shreds(&entries, slot, slot - 1, true, 0);
|
||||
blockstore.insert_shreds(shreds, None, false).unwrap();
|
||||
blockstore.set_roots(vec![slot].iter()).unwrap();
|
||||
}
|
||||
assert_eq!(blockstore.get_first_available_block().unwrap(), 0);
|
||||
assert_eq!(blockstore.lowest_slot_with_genesis(), 0);
|
||||
assert_eq!(blockstore.lowest_slot(), 1);
|
||||
|
||||
blockstore.purge_slots(0, 1, PurgeType::CompactionFilter);
|
||||
assert_eq!(blockstore.get_first_available_block().unwrap(), 3);
|
||||
assert_eq!(blockstore.lowest_slot_with_genesis(), 2);
|
||||
assert_eq!(blockstore.lowest_slot(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_rooted_block() {
|
||||
let slot = 10;
|
||||
|
|
|
@ -1124,7 +1124,10 @@ impl JsonRpcRequestProcessor {
|
|||
)));
|
||||
}
|
||||
|
||||
let lowest_blockstore_slot = self.blockstore.lowest_slot();
|
||||
let lowest_blockstore_slot = self
|
||||
.blockstore
|
||||
.get_first_available_block()
|
||||
.unwrap_or_default();
|
||||
if start_slot < lowest_blockstore_slot {
|
||||
// If the starting slot is lower than what's available in blockstore assume the entire
|
||||
// [start_slot..end_slot] can be fetched from BigTable. This range should not ever run
|
||||
|
@ -1188,7 +1191,10 @@ impl JsonRpcRequestProcessor {
|
|||
)));
|
||||
}
|
||||
|
||||
let lowest_blockstore_slot = self.blockstore.lowest_slot();
|
||||
let lowest_blockstore_slot = self
|
||||
.blockstore
|
||||
.get_first_available_block()
|
||||
.unwrap_or_default();
|
||||
|
||||
if start_slot < lowest_blockstore_slot {
|
||||
// If the starting slot is lower than what's available in blockstore assume the entire
|
||||
|
@ -6677,6 +6683,7 @@ pub mod tests {
|
|||
#[test]
|
||||
fn test_get_blocks() {
|
||||
let rpc = RpcHandler::start();
|
||||
let _ = rpc.create_test_transactions_and_populate_blockstore();
|
||||
rpc.add_roots_to_blockstore(vec![0, 1, 3, 4, 8]);
|
||||
rpc.block_commitment_cache
|
||||
.write()
|
||||
|
@ -6685,7 +6692,7 @@ pub mod tests {
|
|||
|
||||
let request = create_test_request("getBlocks", Some(json!([0u64])));
|
||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
||||
assert_eq!(result, vec![1, 3, 4, 8]);
|
||||
assert_eq!(result, vec![0, 1, 3, 4, 8]);
|
||||
|
||||
let request = create_test_request("getBlocks", Some(json!([2u64])));
|
||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
||||
|
@ -6693,11 +6700,11 @@ pub mod tests {
|
|||
|
||||
let request = create_test_request("getBlocks", Some(json!([0u64, 4u64])));
|
||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
||||
assert_eq!(result, vec![1, 3, 4]);
|
||||
assert_eq!(result, vec![0, 1, 3, 4]);
|
||||
|
||||
let request = create_test_request("getBlocks", Some(json!([0u64, 7u64])));
|
||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
||||
assert_eq!(result, vec![1, 3, 4]);
|
||||
assert_eq!(result, vec![0, 1, 3, 4]);
|
||||
|
||||
let request = create_test_request("getBlocks", Some(json!([9u64, 11u64])));
|
||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
||||
|
@ -6713,7 +6720,7 @@ pub mod tests {
|
|||
Some(json!([0u64, MAX_GET_CONFIRMED_BLOCKS_RANGE])),
|
||||
);
|
||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
||||
assert_eq!(result, vec![1, 3, 4, 8]);
|
||||
assert_eq!(result, vec![0, 1, 3, 4, 8]);
|
||||
|
||||
let request = create_test_request(
|
||||
"getBlocks",
|
||||
|
|
Loading…
Reference in New Issue