Skip to content

Commit

Permalink
feat(provider): receipt and transaction by id in BlockchainProvider2 (
Browse files Browse the repository at this point in the history
  • Loading branch information
shekhirin authored Aug 15, 2024
1 parent 9f15670 commit 821d3e6
Showing 1 changed file with 116 additions and 5 deletions.
121 changes: 116 additions & 5 deletions crates/storage/provider/src/providers/blockchain_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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>> {
Expand All @@ -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(
Expand Down Expand Up @@ -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)
}
}
}

Expand All @@ -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>> {
Expand Down

0 comments on commit 821d3e6

Please sign in to comment.