fix(provider): check list size before calling range.nth (#10460)

This commit is contained in:
joshieDo
2024-08-23 16:27:47 +01:00
committed by GitHub
parent 23f9f4adf2
commit 8ba7821a49

View File

@ -126,6 +126,53 @@ where
(start, end) (start, end)
} }
/// Fetches a range of data from both in-memory state and storage.
///
/// - `fetch_db_range`: Retrieves a range of items from the database.
/// - `map_block_state_item`: Maps a block number to an item in memory. Stops fetching if `None`
/// is returned.
fn fetch_db_mem_range<T, F, G, P>(
&self,
range: impl RangeBounds<BlockNumber>,
fetch_db_range: F,
map_block_state_item: G,
mut predicate: P,
) -> ProviderResult<Vec<T>>
where
F: FnOnce(RangeInclusive<BlockNumber>, &mut P) -> ProviderResult<Vec<T>>,
G: Fn(BlockNumber, &mut P) -> Option<T>,
P: FnMut(&T) -> bool,
{
let (start, end) = self.convert_range_bounds(range, || {
self.canonical_in_memory_state.get_canonical_block_number()
});
let mut range = start..=end;
let mut items = Vec::with_capacity((end - start + 1) as usize);
// First, fetch the items from the database
let mut db_items = fetch_db_range(range.clone(), &mut predicate)?;
if !db_items.is_empty() {
items.append(&mut db_items);
// Advance the range iterator by the number of items fetched from the database
range.nth(items.len() - 1);
}
// Fetch the remaining items from the in-memory state
for num in range {
// TODO: there might be an update between loop iterations, we
// need to handle that situation.
if let Some(item) = map_block_state_item(num, &mut predicate) {
items.push(item);
} else {
break;
}
}
Ok(items)
}
/// This uses a given [`BlockState`] to initialize a state provider for that block. /// This uses a given [`BlockState`] to initialize a state provider for that block.
fn block_state_provider( fn block_state_provider(
&self, &self,
@ -285,32 +332,16 @@ where
} }
fn headers_range(&self, range: impl RangeBounds<BlockNumber>) -> ProviderResult<Vec<Header>> { fn headers_range(&self, range: impl RangeBounds<BlockNumber>) -> ProviderResult<Vec<Header>> {
let (start, end) = self.convert_range_bounds(range, || { self.fetch_db_mem_range(
self.canonical_in_memory_state.get_canonical_block_number() range,
}); |range, _| self.database.headers_range(range),
let mut range = start..=end; |num, _| {
let mut headers = Vec::with_capacity((end - start + 1) as usize); self.canonical_in_memory_state
.state_by_number(num)
// First, fetch the headers from the database .map(|block_state| block_state.block().block().header.header().clone())
let mut db_headers = self.database.headers_range(range.clone())?; },
|_| true,
// Advance the range iterator by the number of headers fetched from the database )
range.nth(db_headers.len() - 1);
headers.append(&mut db_headers);
// Fetch the remaining headers from the in-memory state
for num in range {
if let Some(block_state) = self.canonical_in_memory_state.state_by_number(num) {
// TODO: there might be an update between loop iterations, we
// need to handle that situation.
headers.push(block_state.block().block().header.header().clone());
} else {
break
}
}
Ok(headers)
} }
fn sealed_header(&self, number: BlockNumber) -> ProviderResult<Option<SealedHeader>> { fn sealed_header(&self, number: BlockNumber) -> ProviderResult<Option<SealedHeader>> {
@ -325,69 +356,34 @@ where
&self, &self,
range: impl RangeBounds<BlockNumber>, range: impl RangeBounds<BlockNumber>,
) -> ProviderResult<Vec<SealedHeader>> { ) -> ProviderResult<Vec<SealedHeader>> {
let (start, end) = self.convert_range_bounds(range, || { self.fetch_db_mem_range(
self.canonical_in_memory_state.get_canonical_block_number() range,
}); |range, _| self.database.sealed_headers_range(range),
let mut range = start..=end; |num, _| {
let mut sealed_headers = Vec::with_capacity((end - start + 1) as usize); self.canonical_in_memory_state
.state_by_number(num)
// First, fetch the headers from the database .map(|block_state| block_state.block().block().header.clone())
let mut db_headers = self.database.sealed_headers_range(range.clone())?; },
|_| true,
// Advance the range iterator by the number of headers fetched from the database )
range.nth(db_headers.len() - 1);
sealed_headers.append(&mut db_headers);
// Fetch the remaining headers from the in-memory state
for num in range {
if let Some(block_state) = self.canonical_in_memory_state.state_by_number(num) {
// TODO: there might be an update between loop iterations, we
// need to handle that situation.
sealed_headers.push(block_state.block().block().header.clone());
} else {
break
}
}
Ok(sealed_headers)
} }
fn sealed_headers_while( fn sealed_headers_while(
&self, &self,
range: impl RangeBounds<BlockNumber>, range: impl RangeBounds<BlockNumber>,
mut predicate: impl FnMut(&SealedHeader) -> bool, predicate: impl FnMut(&SealedHeader) -> bool,
) -> ProviderResult<Vec<SealedHeader>> { ) -> ProviderResult<Vec<SealedHeader>> {
let (start, end) = self.convert_range_bounds(range, || { self.fetch_db_mem_range(
self.canonical_in_memory_state.get_canonical_block_number() range,
}); |range, predicate| self.database.sealed_headers_while(range, predicate),
let mut range = start..=end; |num, predicate| {
let mut sealed_headers = Vec::with_capacity((end - start + 1) as usize); self.canonical_in_memory_state
.state_by_number(num)
// First, fetch the headers from the database .map(|block_state| block_state.block().block().header.clone())
let mut db_headers = self.database.sealed_headers_while(range.clone(), &mut predicate)?; .filter(|header| predicate(header))
},
// Advance the range iterator by the number of headers fetched from the database predicate,
range.nth(db_headers.len() - 1); )
sealed_headers.append(&mut db_headers);
// Fetch the remaining headers from the in-memory state
for num in range {
if let Some(block_state) = self.canonical_in_memory_state.state_by_number(num) {
let header = block_state.block().block().header.clone();
if !predicate(&header) {
break
}
// TODO: there might be an update between loop iterations, we
// need to handle that situation.
sealed_headers.push(header);
} else {
break
}
}
Ok(sealed_headers)
} }
} }
@ -408,30 +404,16 @@ where
start: BlockNumber, start: BlockNumber,
end: BlockNumber, end: BlockNumber,
) -> ProviderResult<Vec<B256>> { ) -> ProviderResult<Vec<B256>> {
let mut range = start..=end; self.fetch_db_mem_range(
start..=end,
let mut hashes = Vec::with_capacity((end - start + 1) as usize); |range, _| self.database.canonical_hashes_range(*range.start(), *range.end()),
|num, _| {
// First, fetch the hashes from the database self.canonical_in_memory_state
let mut db_hashes = self.database.canonical_hashes_range(start, end)?; .state_by_number(num)
.map(|block_state| block_state.hash())
// Advance the range iterator by the number of blocks fetched from the database },
range.nth(db_hashes.len() - 1); |_| true,
)
hashes.append(&mut db_hashes);
// Fetch the remaining blocks from the in-memory state
for num in range {
if let Some(block_state) = self.canonical_in_memory_state.state_by_number(num) {
// TODO: there might be an update between loop iterations, we
// need to handle that situation.
hashes.push(block_state.hash());
} else {
break
}
}
Ok(hashes)
} }
} }
@ -629,89 +611,53 @@ where
self.database.sealed_block_with_senders(id, transaction_kind) self.database.sealed_block_with_senders(id, transaction_kind)
} }
fn block_range(&self, mut range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>> { fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>> {
let capacity = (range.end() - range.start() + 1) as usize; self.fetch_db_mem_range(
let mut blocks = Vec::with_capacity(capacity); range,
|range, _| self.database.block_range(range),
// First, fetch the blocks from the database |num, _| {
let mut database_blocks = self.database.block_range(range.clone())?; self.canonical_in_memory_state
blocks.append(&mut database_blocks); .state_by_number(num)
.map(|block_state| block_state.block().block().clone().unseal())
// Advance the range iterator by the number of blocks fetched from the database },
range.nth(blocks.len() - 1); |_| true,
)
// Fetch the remaining blocks from the in-memory state
for num in range {
if let Some(block_state) = self.canonical_in_memory_state.state_by_number(num) {
// TODO: there might be an update between loop iterations, we
// need to handle that situation.
blocks.push(block_state.block().block().clone().unseal());
} else {
break
}
}
Ok(blocks)
} }
fn block_with_senders_range( fn block_with_senders_range(
&self, &self,
mut range: RangeInclusive<BlockNumber>, range: RangeInclusive<BlockNumber>,
) -> ProviderResult<Vec<BlockWithSenders>> { ) -> ProviderResult<Vec<BlockWithSenders>> {
let capacity = (range.end() - range.start() + 1) as usize; self.fetch_db_mem_range(
let mut blocks = Vec::with_capacity(capacity); range,
|range, _| self.database.block_with_senders_range(range),
// First, fetch the blocks from the database |num, _| {
let mut database_blocks = self.database.block_with_senders_range(range.clone())?; self.canonical_in_memory_state.state_by_number(num).map(|block_state| {
blocks.append(&mut database_blocks); let block = block_state.block().block().clone();
let senders = block_state.block().senders().clone();
// Advance the range iterator by the number of blocks fetched from the database BlockWithSenders { block: block.unseal(), senders }
range.nth(blocks.len() - 1); })
},
// Fetch the remaining blocks from the in-memory state |_| true,
for num in range { )
if let Some(block_state) = self.canonical_in_memory_state.state_by_number(num) {
let block = block_state.block().block().clone();
let senders = block_state.block().senders().clone();
// TODO: there might be an update between loop iterations, we
// need to handle that situation.
blocks.push(BlockWithSenders { block: block.unseal(), senders });
} else {
break
}
}
Ok(blocks)
} }
fn sealed_block_with_senders_range( fn sealed_block_with_senders_range(
&self, &self,
mut range: RangeInclusive<BlockNumber>, range: RangeInclusive<BlockNumber>,
) -> ProviderResult<Vec<SealedBlockWithSenders>> { ) -> ProviderResult<Vec<SealedBlockWithSenders>> {
let capacity = (range.end() - range.start() + 1) as usize; self.fetch_db_mem_range(
let mut blocks = Vec::with_capacity(capacity); range,
|range, _| self.database.sealed_block_with_senders_range(range),
// First, fetch the blocks from the database |num, _| {
let mut database_blocks = self.database.sealed_block_with_senders_range(range.clone())?; self.canonical_in_memory_state.state_by_number(num).map(|block_state| {
blocks.append(&mut database_blocks); let block = block_state.block().block().clone();
let senders = block_state.block().senders().clone();
// Advance the range iterator by the number of blocks fetched from the database SealedBlockWithSenders { block, senders }
range.nth(blocks.len() - 1); })
},
// Fetch the remaining blocks from the in-memory state |_| true,
for num in range { )
if let Some(block_state) = self.canonical_in_memory_state.state_by_number(num) {
let block = block_state.block().block().clone();
let senders = block_state.block().senders().clone();
// TODO: there might be an update between loop iterations, we
// need to handle that situation.
blocks.push(SealedBlockWithSenders { block, senders });
} else {
break
}
}
Ok(blocks)
} }
} }