Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve block transactions iterator #85

Merged
merged 2 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 166 additions & 33 deletions crates/rpc-types/src/eth/block.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Contains types that represent ethereum types when used in RPC
//! Block RPC types.
use crate::{Transaction, Withdrawal};
use alloy_primitives::{
ruint::ParseError, Address, BlockHash, BlockNumber, Bloom, Bytes, B256, B64, U256, U64,
Expand All @@ -9,13 +10,12 @@ use serde::{
ser::{Error, SerializeStruct},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::{
collections::BTreeMap,
fmt::{self, Formatter},
num::ParseIntError,
ops::Deref,
str::FromStr,
};
use std::{collections::BTreeMap, fmt, num::ParseIntError, ops::Deref, str::FromStr};

#[doc(hidden)]
#[deprecated = "use `BlockTransactionHashes` instead"]
pub type BlockTransactionsHashIterator<'a> = BlockTransactionHashes<'a>;

/// Block Transactions depending on the boolean attribute of `eth_getBlockBy*`,
/// or if used by `eth_getUncle*`
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
Expand All @@ -30,51 +30,184 @@ pub enum BlockTransactions {
}

impl BlockTransactions {
/// Check if the enum variant is
/// used for an uncle response.
pub fn is_uncle(&self) -> bool {
/// Converts `self` into `Hashes`.
pub fn convert_to_hashes(&mut self) {
*self = Self::Hashes(self.hashes().copied().collect());
}

/// Converts `self` into `Hashes`.
pub fn into_hashes(mut self) -> Self {
self.convert_to_hashes();
self
}

/// Check if the enum variant is used for an uncle response.
pub const fn is_uncle(&self) -> bool {
matches!(self, Self::Uncle)
}

/// Returns an iterator over the transaction hashes.
pub fn iter(&self) -> BlockTransactionsHashIterator<'_> {
BlockTransactionsHashIterator::new(self)
#[deprecated = "use `hashes` instead"]
#[inline]
pub fn iter(&self) -> BlockTransactionHashes<'_> {
self.hashes()
}

/// Returns an iterator over references to the transaction hashes.
#[inline]
pub fn hashes(&self) -> BlockTransactionHashes<'_> {
BlockTransactionHashes::new(self)
}

/// Returns an iterator over mutable references to the transaction hashes.
#[inline]
pub fn hashes_mut(&mut self) -> BlockTransactionHashesMut<'_> {
BlockTransactionHashesMut::new(self)
}
}

/// An Iterator over the transaction hashes of a block.
#[derive(Debug, Clone)]
pub struct BlockTransactionsHashIterator<'a> {
txs: &'a BlockTransactions,
idx: usize,
/// An iterator over the transaction hashes of a block.
///
/// See [`BlockTransactions::hashes`].
#[derive(Clone, Debug)]
pub struct BlockTransactionHashes<'a>(BlockTransactionHashesInner<'a>);

#[derive(Clone, Debug)]
enum BlockTransactionHashesInner<'a> {
Hashes(std::slice::Iter<'a, B256>),
Full(std::slice::Iter<'a, Transaction>),
Uncle,
}

impl<'a> BlockTransactionsHashIterator<'a> {
impl<'a> BlockTransactionHashes<'a> {
#[inline]
fn new(txs: &'a BlockTransactions) -> Self {
Self { txs, idx: 0 }
Self(match txs {
BlockTransactions::Hashes(txs) => BlockTransactionHashesInner::Hashes(txs.iter()),
BlockTransactions::Full(txs) => BlockTransactionHashesInner::Full(txs.iter()),
BlockTransactions::Uncle => BlockTransactionHashesInner::Uncle,
})
}
}

impl<'a> Iterator for BlockTransactionsHashIterator<'a> {
type Item = B256;
impl<'a> Iterator for BlockTransactionHashes<'a> {
type Item = &'a B256;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.txs {
BlockTransactions::Full(txs) => {
let tx = txs.get(self.idx);
self.idx += 1;
tx.map(|tx| tx.hash)
}
match &mut self.0 {
BlockTransactionHashesInner::Full(txs) => txs.next().map(|tx| &tx.hash),
BlockTransactionHashesInner::Hashes(txs) => txs.next(),
BlockTransactionHashesInner::Uncle => None,
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.0 {
BlockTransactionHashesInner::Full(txs) => txs.size_hint(),
BlockTransactionHashesInner::Hashes(txs) => txs.size_hint(),
BlockTransactionHashesInner::Uncle => (0, Some(0)),
}
}
}

impl ExactSizeIterator for BlockTransactionHashes<'_> {
#[inline]
fn len(&self) -> usize {
match &self.0 {
BlockTransactionHashesInner::Full(txs) => txs.len(),
BlockTransactionHashesInner::Hashes(txs) => txs.len(),
BlockTransactionHashesInner::Uncle => 0,
}
}
}

impl DoubleEndedIterator for BlockTransactionHashes<'_> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match &mut self.0 {
BlockTransactionHashesInner::Full(txs) => txs.next_back().map(|tx| &tx.hash),
BlockTransactionHashesInner::Hashes(txs) => txs.next_back(),
BlockTransactionHashesInner::Uncle => None,
}
}
}

impl<'a> std::iter::FusedIterator for BlockTransactionHashes<'a> {}

/// An Iterator over the transaction hashes of a block.
///
/// See [`BlockTransactions::hashes_mut`].
#[derive(Debug)]
pub struct BlockTransactionHashesMut<'a>(BlockTransactionHashesInnerMut<'a>);

#[derive(Debug)]
enum BlockTransactionHashesInnerMut<'a> {
Hashes(std::slice::IterMut<'a, B256>),
Full(std::slice::IterMut<'a, Transaction>),
Uncle,
}

impl<'a> BlockTransactionHashesMut<'a> {
#[inline]
fn new(txs: &'a mut BlockTransactions) -> Self {
Self(match txs {
BlockTransactions::Hashes(txs) => {
let tx = txs.get(self.idx).copied();
self.idx += 1;
tx
BlockTransactionHashesInnerMut::Hashes(txs.iter_mut())
}
BlockTransactions::Uncle => None,
BlockTransactions::Full(txs) => BlockTransactionHashesInnerMut::Full(txs.iter_mut()),
BlockTransactions::Uncle => BlockTransactionHashesInnerMut::Uncle,
})
}
}

impl<'a> Iterator for BlockTransactionHashesMut<'a> {
type Item = &'a mut B256;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
BlockTransactionHashesInnerMut::Full(txs) => txs.next().map(|tx| &mut tx.hash),
BlockTransactionHashesInnerMut::Hashes(txs) => txs.next(),
BlockTransactionHashesInnerMut::Uncle => None,
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.0 {
BlockTransactionHashesInnerMut::Full(txs) => txs.size_hint(),
BlockTransactionHashesInnerMut::Hashes(txs) => txs.size_hint(),
BlockTransactionHashesInnerMut::Uncle => (0, Some(0)),
}
}
}

impl ExactSizeIterator for BlockTransactionHashesMut<'_> {
#[inline]
fn len(&self) -> usize {
match &self.0 {
BlockTransactionHashesInnerMut::Full(txs) => txs.len(),
BlockTransactionHashesInnerMut::Hashes(txs) => txs.len(),
BlockTransactionHashesInnerMut::Uncle => 0,
}
}
}

impl DoubleEndedIterator for BlockTransactionHashesMut<'_> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match &mut self.0 {
BlockTransactionHashesInnerMut::Full(txs) => txs.next_back().map(|tx| &mut tx.hash),
BlockTransactionHashesInnerMut::Hashes(txs) => txs.next_back(),
BlockTransactionHashesInnerMut::Uncle => None,
}
}
}

impl<'a> std::iter::FusedIterator for BlockTransactionHashesMut<'a> {}

/// Determines how the `transactions` field of [Block] should be filled.
///
/// This essentially represents the `full:bool` argument in RPC calls that determine whether the
Expand Down Expand Up @@ -485,7 +618,7 @@ impl<'de> Deserialize<'de> for BlockId {
impl<'de> Visitor<'de> for BlockIdVisitor {
type Value = BlockId;

fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("Block identifier following EIP-1898")
}

Expand Down
1 change: 1 addition & 0 deletions crates/signer-aws/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub enum AwsSignerError {
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl Signer for AwsSigner {
#[instrument(err)]
#[allow(clippy::blocks_in_conditions)]
async fn sign_hash(&self, hash: &B256) -> Result<Signature> {
self.sign_digest_with_eip155(hash, self.chain_id).await.map_err(alloy_signer::Error::other)
}
Expand Down