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
|
/// The first complete block that is available in the Blockstore ledger
|
||||||
pub fn get_first_available_block(&self) -> Result<Slot> {
|
pub fn get_first_available_block(&self) -> Result<Slot> {
|
||||||
let mut root_iterator = self.rooted_slot_iterator(self.lowest_slot())?;
|
let mut root_iterator = self.rooted_slot_iterator(self.lowest_slot_with_genesis())?;
|
||||||
// The block at root-index 0 cannot be complete, because it is missing its parent
|
let first_root = root_iterator.next().unwrap_or_default();
|
||||||
// blockhash. A parent blockhash must be calculated from the entries of the previous block.
|
// If the first root is slot 0, it is genesis. Genesis is always complete, so it is correct
|
||||||
// Therefore, the first available complete block is that at root-index 1.
|
// to return it as first-available.
|
||||||
Ok(root_iterator.nth(1).unwrap_or_default())
|
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(
|
pub fn get_rooted_block(
|
||||||
|
@ -3160,6 +3166,19 @@ impl Blockstore {
|
||||||
self.last_root()
|
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 {
|
pub fn lowest_cleanup_slot(&self) -> Slot {
|
||||||
*self.lowest_cleanup_slot.read().unwrap()
|
*self.lowest_cleanup_slot.read().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -6309,6 +6328,31 @@ pub mod tests {
|
||||||
assert!(blockstore.get_data_shred(1, 0).unwrap().is_some());
|
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]
|
#[test]
|
||||||
fn test_get_rooted_block() {
|
fn test_get_rooted_block() {
|
||||||
let slot = 10;
|
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 start_slot < lowest_blockstore_slot {
|
||||||
// If the starting slot is lower than what's available in blockstore assume the entire
|
// 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
|
// [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 start_slot < lowest_blockstore_slot {
|
||||||
// If the starting slot is lower than what's available in blockstore assume the entire
|
// If the starting slot is lower than what's available in blockstore assume the entire
|
||||||
|
@ -6677,6 +6683,7 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_blocks() {
|
fn test_get_blocks() {
|
||||||
let rpc = RpcHandler::start();
|
let rpc = RpcHandler::start();
|
||||||
|
let _ = rpc.create_test_transactions_and_populate_blockstore();
|
||||||
rpc.add_roots_to_blockstore(vec![0, 1, 3, 4, 8]);
|
rpc.add_roots_to_blockstore(vec![0, 1, 3, 4, 8]);
|
||||||
rpc.block_commitment_cache
|
rpc.block_commitment_cache
|
||||||
.write()
|
.write()
|
||||||
|
@ -6685,7 +6692,7 @@ pub mod tests {
|
||||||
|
|
||||||
let request = create_test_request("getBlocks", Some(json!([0u64])));
|
let request = create_test_request("getBlocks", Some(json!([0u64])));
|
||||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
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 request = create_test_request("getBlocks", Some(json!([2u64])));
|
||||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
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 request = create_test_request("getBlocks", Some(json!([0u64, 4u64])));
|
||||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
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 request = create_test_request("getBlocks", Some(json!([0u64, 7u64])));
|
||||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
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 request = create_test_request("getBlocks", Some(json!([9u64, 11u64])));
|
||||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
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])),
|
Some(json!([0u64, MAX_GET_CONFIRMED_BLOCKS_RANGE])),
|
||||||
);
|
);
|
||||||
let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
|
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(
|
let request = create_test_request(
|
||||||
"getBlocks",
|
"getBlocks",
|
||||||
|
|
Loading…
Reference in New Issue