From 92e2c4d2aa570c693b1acc6d328efcc0f2d693a9 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 21 Mar 2023 15:23:14 +0100 Subject: [PATCH] feat: add transaction_by_hash_with_meta (#1878) --- crates/primitives/src/lib.rs | 5 +- crates/primitives/src/transaction/meta.rs | 14 ++++++ crates/primitives/src/transaction/mod.rs | 2 + crates/storage/provider/src/providers/mod.rs | 46 ++++++++++++++++++- .../storage/provider/src/test_utils/mock.rs | 11 ++++- .../storage/provider/src/test_utils/noop.rs | 11 ++++- .../provider/src/traits/transactions.rs | 9 +++- 7 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 crates/primitives/src/transaction/meta.rs diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 01eb74867b..a344530c90 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -70,8 +70,9 @@ pub use storage::{StorageEntry, StorageTrieEntry}; pub use transaction::{ util::secp256k1::sign_message, AccessList, AccessListItem, AccessListWithGasUsed, FromRecoveredTransaction, IntoRecoveredTransaction, InvalidTransactionError, Signature, - Transaction, TransactionKind, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, - TxEip2930, TxLegacy, TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, LEGACY_TX_TYPE_ID, + Transaction, TransactionKind, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, + TxEip1559, TxEip2930, TxLegacy, TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, + LEGACY_TX_TYPE_ID, }; pub use withdrawal::Withdrawal; diff --git a/crates/primitives/src/transaction/meta.rs b/crates/primitives/src/transaction/meta.rs new file mode 100644 index 0000000000..d3fcdaa537 --- /dev/null +++ b/crates/primitives/src/transaction/meta.rs @@ -0,0 +1,14 @@ +use crate::H256; + +/// Additional fields in the context of a block that contains this transaction. +#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)] +pub struct TransactionMeta { + /// Hash of the transaction. + pub tx_hash: H256, + /// Index of the transaction in the block + pub index: u64, + /// Hash of the block. + pub block_hash: H256, + /// Number of the block. + pub block_number: u64, +} diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 3ae06b947e..94f42909df 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -3,6 +3,7 @@ pub use access_list::{AccessList, AccessListItem, AccessListWithGasUsed}; use bytes::{Buf, BytesMut}; use derive_more::{AsRef, Deref}; pub use error::InvalidTransactionError; +pub use meta::TransactionMeta; use reth_codecs::{add_arbitrary_tests, main_codec, Compact}; use reth_rlp::{ length_of_length, Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE, @@ -12,6 +13,7 @@ pub use tx_type::{TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, LEGACY_TX_TYPE mod access_list; mod error; +mod meta; mod signature; mod tx_type; pub(crate) mod util; diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index d66433eee2..fdec66c96b 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -11,7 +11,7 @@ use reth_db::{ use reth_interfaces::Result; use reth_primitives::{ Block, BlockHash, BlockId, BlockNumber, ChainInfo, ChainSpec, Hardfork, Head, Header, Receipt, - TransactionSigned, TxHash, TxNumber, Withdrawal, H256, U256, + TransactionMeta, TransactionSigned, TxHash, TxNumber, Withdrawal, H256, U256, }; use reth_revm_primitives::{ config::revm_spec, @@ -181,6 +181,50 @@ impl TransactionsProvider for ShareableDatabase { .map_err(Into::into) } + fn transaction_by_hash_with_meta( + &self, + tx_hash: TxHash, + ) -> Result> { + self.db + .view(|tx| -> Result<_> { + if let Some(transaction_id) = tx.get::(tx_hash)? { + if let Some(transaction) = tx.get::(transaction_id)? { + let mut transaction_cursor = + tx.cursor_read::()?; + if let Some(block_number) = + transaction_cursor.seek(transaction_id).map(|b| b.map(|(_, bn)| bn))? + { + if let Some(block_hash) = + tx.get::(block_number)? + { + if let Some(block_body) = + tx.get::(block_number)? + { + // the index of the tx in the block is the offset: + // len([start..tx_id]) + // SAFETY: `transaction_id` is always `>=` the block's first + // index + let index = transaction_id - block_body.first_tx_index(); + + let meta = TransactionMeta { + tx_hash, + index, + block_hash, + block_number, + }; + + return Ok(Some((transaction, meta))) + } + } + } + } + } + + Ok(None) + })? + .map_err(Into::into) + } + fn transaction_block(&self, id: TxNumber) -> Result> { self.db .view(|tx| { diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index b484ae436e..2c4f74386a 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -6,8 +6,8 @@ use parking_lot::Mutex; use reth_interfaces::Result; use reth_primitives::{ keccak256, Account, Address, Block, BlockHash, BlockId, BlockNumber, BlockNumberOrTag, - Bytecode, Bytes, ChainInfo, Header, Receipt, StorageKey, StorageValue, TransactionSigned, - TxHash, TxNumber, H256, U256, + Bytecode, Bytes, ChainInfo, Header, Receipt, StorageKey, StorageValue, TransactionMeta, + TransactionSigned, TxHash, TxNumber, H256, U256, }; use revm_primitives::{BlockEnv, CfgEnv}; use std::{collections::HashMap, ops::RangeBounds, sync::Arc}; @@ -149,6 +149,13 @@ impl TransactionsProvider for MockEthProvider { .find_map(|(_, block)| block.body.iter().find(|tx| tx.hash == hash).cloned())) } + fn transaction_by_hash_with_meta( + &self, + _hash: TxHash, + ) -> Result> { + Ok(None) + } + fn transaction_block(&self, _id: TxNumber) -> Result> { unimplemented!() } diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 7a921ccbec..9f70f78124 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -5,8 +5,8 @@ use crate::{ use reth_interfaces::Result; use reth_primitives::{ Account, Address, Block, BlockHash, BlockId, BlockNumber, Bytecode, Bytes, ChainInfo, Header, - Receipt, StorageKey, StorageValue, TransactionSigned, TxHash, TxNumber, H256, KECCAK_EMPTY, - U256, + Receipt, StorageKey, StorageValue, TransactionMeta, TransactionSigned, TxHash, TxNumber, H256, + KECCAK_EMPTY, U256, }; use revm_primitives::{BlockEnv, CfgEnv}; use std::ops::RangeBounds; @@ -56,6 +56,13 @@ impl TransactionsProvider for NoopProvider { Ok(None) } + fn transaction_by_hash_with_meta( + &self, + _hash: TxHash, + ) -> Result> { + Ok(None) + } + fn transaction_block(&self, _id: TxNumber) -> Result> { todo!() } diff --git a/crates/storage/provider/src/traits/transactions.rs b/crates/storage/provider/src/traits/transactions.rs index be34b6552a..f52cc65196 100644 --- a/crates/storage/provider/src/traits/transactions.rs +++ b/crates/storage/provider/src/traits/transactions.rs @@ -1,6 +1,6 @@ use crate::BlockIdProvider; use reth_interfaces::Result; -use reth_primitives::{BlockId, BlockNumber, TransactionSigned, TxHash, TxNumber}; +use reth_primitives::{BlockId, BlockNumber, TransactionMeta, TransactionSigned, TxHash, TxNumber}; use std::ops::RangeBounds; /// Client trait for fetching [TransactionSigned] related data. @@ -12,6 +12,13 @@ pub trait TransactionsProvider: BlockIdProvider + Send + Sync { /// Get transaction by transaction hash. fn transaction_by_hash(&self, hash: TxHash) -> Result>; + /// Get transaction by transaction hash and additional metadata of the block the transaction was + /// mined in + fn transaction_by_hash_with_meta( + &self, + hash: TxHash, + ) -> Result>; + /// Get transaction block number fn transaction_block(&self, id: TxNumber) -> Result>;