mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(provider): receipt and transaction by id in BlockchainProvider2 (#10281)
This commit is contained in:
@ -133,6 +133,67 @@ where
|
||||
let latest_historical = self.database.history_by_block_hash(anchor_hash)?;
|
||||
Ok(self.canonical_in_memory_state.state_provider(state.hash(), latest_historical))
|
||||
}
|
||||
|
||||
/// Returns:
|
||||
/// 1. The block state as [`Some`] if the block is in memory, and [`None`] if the block is in
|
||||
/// database.
|
||||
/// 2. The in-block transaction index.
|
||||
fn block_state_by_tx_id(
|
||||
&self,
|
||||
provider: &DatabaseProviderRO<DB>,
|
||||
id: TxNumber,
|
||||
) -> ProviderResult<Option<(Option<Arc<BlockState>>, usize)>> {
|
||||
// Get the last block number stored in the database
|
||||
let last_database_block_number = provider.last_block_number()?;
|
||||
|
||||
// Get the next tx number for the last block stored in the database and consider it the
|
||||
// first tx number of the in-memory state
|
||||
let Some(last_block_body_index) =
|
||||
provider.block_body_indices(last_database_block_number)?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let mut in_memory_tx_num = last_block_body_index.next_tx_num();
|
||||
|
||||
if id < in_memory_tx_num {
|
||||
// If the transaction number is less than the first in-memory transaction number, make a
|
||||
// database lookup
|
||||
let Some(block_number) = provider.transaction_block(id)? else { return Ok(None) };
|
||||
let Some(body_index) = provider.block_body_indices(block_number)? else {
|
||||
return Ok(None)
|
||||
};
|
||||
let tx_index = id - body_index.last_tx_num();
|
||||
Ok(Some((None, tx_index as usize)))
|
||||
} else {
|
||||
// Otherwise, iterate through in-memory blocks and find the transaction with the
|
||||
// matching number
|
||||
|
||||
let first_in_memory_block_number = last_database_block_number.saturating_add(1);
|
||||
let last_in_memory_block_number =
|
||||
self.canonical_in_memory_state.get_canonical_block_number();
|
||||
|
||||
for block_number in first_in_memory_block_number..=last_in_memory_block_number {
|
||||
let Some(block_state) =
|
||||
self.canonical_in_memory_state.state_by_number(block_number)
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let executed_block = block_state.block();
|
||||
let block = executed_block.block();
|
||||
|
||||
for tx_index in 0..block.body.len() {
|
||||
if id == in_memory_tx_num {
|
||||
return Ok(Some((Some(block_state), tx_index)))
|
||||
}
|
||||
|
||||
in_memory_tx_num += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> BlockchainProvider2<DB>
|
||||
@ -692,14 +753,35 @@ where
|
||||
}
|
||||
|
||||
fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<TransactionSigned>> {
|
||||
self.database.transaction_by_id(id)
|
||||
let provider = self.database.provider()?;
|
||||
let Some((block_state, tx_index)) = self.block_state_by_tx_id(&provider, id)? else {
|
||||
return Ok(None)
|
||||
};
|
||||
|
||||
if let Some(block_state) = block_state {
|
||||
let transaction = block_state.block().block().body.get(tx_index).cloned();
|
||||
Ok(transaction)
|
||||
} else {
|
||||
provider.transaction_by_id(id)
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_by_id_no_hash(
|
||||
&self,
|
||||
id: TxNumber,
|
||||
) -> ProviderResult<Option<TransactionSignedNoHash>> {
|
||||
self.database.transaction_by_id_no_hash(id)
|
||||
let provider = self.database.provider()?;
|
||||
let Some((block_state, tx_index)) = self.block_state_by_tx_id(&provider, id)? else {
|
||||
return Ok(None)
|
||||
};
|
||||
|
||||
if let Some(block_state) = block_state {
|
||||
let transaction =
|
||||
block_state.block().block().body.get(tx_index).cloned().map(Into::into);
|
||||
Ok(transaction)
|
||||
} else {
|
||||
provider.transaction_by_id_no_hash(id)
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<TransactionSigned>> {
|
||||
@ -724,7 +806,11 @@ where
|
||||
}
|
||||
|
||||
fn transaction_block(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
|
||||
self.database.transaction_block(id)
|
||||
let provider = self.database.provider()?;
|
||||
Ok(self
|
||||
.block_state_by_tx_id(&provider, id)?
|
||||
.and_then(|(block_state, _)| block_state)
|
||||
.map(|block_state| block_state.block().block().number))
|
||||
}
|
||||
|
||||
fn transactions_by_block(
|
||||
@ -796,7 +882,22 @@ where
|
||||
}
|
||||
|
||||
fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
|
||||
self.database.transaction_sender(id)
|
||||
let provider = self.database.provider()?;
|
||||
let Some((block_state, tx_index)) = self.block_state_by_tx_id(&provider, id)? else {
|
||||
return Ok(None)
|
||||
};
|
||||
|
||||
if let Some(block_state) = block_state {
|
||||
let sender = block_state
|
||||
.block()
|
||||
.block()
|
||||
.body
|
||||
.get(tx_index)
|
||||
.and_then(|transaction| transaction.recover_signer());
|
||||
Ok(sender)
|
||||
} else {
|
||||
provider.transaction_sender(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -805,7 +906,17 @@ where
|
||||
DB: Database,
|
||||
{
|
||||
fn receipt(&self, id: TxNumber) -> ProviderResult<Option<Receipt>> {
|
||||
self.database.receipt(id)
|
||||
let provider = self.database.provider()?;
|
||||
let Some((block_state, tx_index)) = self.block_state_by_tx_id(&provider, id)? else {
|
||||
return Ok(None)
|
||||
};
|
||||
|
||||
if let Some(block_state) = block_state {
|
||||
let receipt = block_state.executed_block_receipts().get(tx_index).cloned();
|
||||
Ok(receipt)
|
||||
} else {
|
||||
provider.receipt(id)
|
||||
}
|
||||
}
|
||||
|
||||
fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Receipt>> {
|
||||
|
||||
Reference in New Issue
Block a user