Skip to content
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ resolver = "2"
[workspace.package]
version = "0.16.0-rc.4"
edition = "2021"
rust-version = "1.85"
rust-version = "1.87"
authors = ["init4"]
license = "MIT OR Apache-2.0"
homepage = "https://github.com/init4tech/signet-sdk"
Expand Down
102 changes: 74 additions & 28 deletions crates/bundle/src/send/bundle.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Signet bundle types.
use alloy::{
consensus::TxEnvelope,
eips::Decodable2718,
primitives::{Bytes, B256},
consensus::{transaction::SignerRecoverable, TxEnvelope},
eips::{eip2718::Eip2718Result, Decodable2718},
primitives::{Address, Bytes, TxHash, B256},
rlp::Buf,
rpc::types::mev::EthSendBundle,
};
Expand Down Expand Up @@ -39,10 +39,62 @@ pub struct SignetEthBundle {
}

impl SignetEthBundle {
/// Creates a new [`SignetEthBundle`] from an existing [`EthSendBundle`].
pub const fn new(bundle: EthSendBundle, host_txs: Vec<Bytes>) -> Self {
Self { bundle, host_txs }
}

/// Decomposes the [`SignetEthBundle`] into its parts.
pub fn into_parts(self) -> (EthSendBundle, Vec<Bytes>) {
(self.bundle, self.host_txs)
}

/// Returns the transactions in this bundle.
#[allow(clippy::missing_const_for_fn)] // false positive
pub fn txs(&self) -> &[Bytes] {
&self.bundle.txs
pub const fn txs(&self) -> &[Bytes] {
self.bundle.txs.as_slice()
}

/// Returns the host transactions in this bundle.
pub const fn host_txs(&self) -> &[Bytes] {
self.host_txs.as_slice()
}

/// Get a mutable reference to the host transactions.
pub const fn host_txs_mut(&mut self) -> &mut Vec<Bytes> {
&mut self.host_txs
}

/// Return an iterator over decoded transactions in this bundle.
pub fn decode_txs(&self) -> impl Iterator<Item = Eip2718Result<TxEnvelope>> + '_ {
self.txs().iter().map(|tx| TxEnvelope::decode_2718(&mut tx.chunk()))
}

/// Return an iterator over decoded host transactions in this bundle.
///
/// This may be empty if no host transactions were included.
pub fn decode_host_txs(&self) -> impl Iterator<Item = Eip2718Result<TxEnvelope>> + '_ {
self.host_txs.iter().map(|tx| TxEnvelope::decode_2718(&mut tx.chunk()))
}

/// Return an iterator over the signers of the transactions in this bundle.
/// The iterator yields `Option<(TxHash, Address)>` for each transaction,
/// where `None` indicates that the signer could not be recovered.
///
/// Computing this may be expensive, as it requires decoding and recovering
/// the signer for each transaction. It is recommended to memoize the
/// results
pub fn signers(&self) -> impl Iterator<Item = Option<(TxHash, Address)>> + '_ {
self.txs().iter().map(|tx| {
TxEnvelope::decode_2718(&mut tx.chunk())
.ok()
.and_then(|envelope| envelope.recover_signer().ok().map(|s| (*envelope.hash(), s)))
})
}

/// Return an iterator over the signers of the transactions in this bundle,
/// skipping any transactions where the signer could not be recovered.
pub fn signers_lossy(&self) -> impl Iterator<Item = (TxHash, Address)> + '_ {
self.signers().flatten()
}

/// Returns the block number for this bundle.
Expand All @@ -61,13 +113,15 @@ impl SignetEthBundle {
}

/// Returns the reverting tx hashes for this bundle.
pub fn reverting_tx_hashes(&self) -> &[B256] {
pub const fn reverting_tx_hashes(&self) -> &[B256] {
self.bundle.reverting_tx_hashes.as_slice()
}

/// Returns the replacement uuid for this bundle.
pub fn replacement_uuid(&self) -> Option<&str> {
self.bundle.replacement_uuid.as_deref()
pub const fn replacement_uuid(&self) -> Option<&str> {
let Some(uuid) = &self.bundle.replacement_uuid else { return None };

Some(uuid.as_str())
}

/// Checks if the bundle is valid at a given timestamp.
Expand All @@ -88,9 +142,7 @@ impl SignetEthBundle {
) -> Result<Vec<TxEnvelope>, BundleError<Db>> {
// Decode and validate the transactions in the bundle
let txs = self
.txs()
.iter()
.map(|tx| TxEnvelope::decode_2718(&mut tx.chunk()))
.decode_txs()
.collect::<Result<Vec<_>, _>>()
.map_err(|err| BundleError::TransactionDecodingError(err))?;

Expand All @@ -105,15 +157,9 @@ impl SignetEthBundle {
pub fn decode_and_validate_host_txs<Db: Database>(
&self,
) -> Result<Vec<TxEnvelope>, BundleError<Db>> {
// Decode and validate the host transactions in the bundle
let txs = self
.host_txs
.iter()
.map(|tx| TxEnvelope::decode_2718(&mut tx.chunk()))
self.decode_host_txs()
.collect::<Result<Vec<_>, _>>()
.map_err(|err| BundleError::TransactionDecodingError(err))?;

Ok(txs)
.map_err(|err| BundleError::TransactionDecodingError(err))
}
}

Expand All @@ -123,8 +169,8 @@ mod test {

#[test]
fn send_bundle_ser_roundtrip() {
let bundle = SignetEthBundle {
bundle: EthSendBundle {
let bundle = SignetEthBundle::new(
EthSendBundle {
txs: vec![b"tx1".into(), b"tx2".into()],
block_number: 1,
min_timestamp: Some(2),
Expand All @@ -133,8 +179,8 @@ mod test {
replacement_uuid: Some("uuid".to_owned()),
..Default::default()
},
host_txs: vec![b"host_tx1".into(), b"host_tx2".into()],
};
vec![b"host_tx1".into(), b"host_tx2".into()],
);

let serialized = serde_json::to_string(&bundle).unwrap();
let deserialized: SignetEthBundle = serde_json::from_str(&serialized).unwrap();
Expand All @@ -144,8 +190,8 @@ mod test {

#[test]
fn send_bundle_ser_roundtrip_no_host_no_fills() {
let bundle = SignetEthBundle {
bundle: EthSendBundle {
let bundle = SignetEthBundle::new(
EthSendBundle {
txs: vec![b"tx1".into(), b"tx2".into()],
block_number: 1,
min_timestamp: Some(2),
Expand All @@ -154,8 +200,8 @@ mod test {
replacement_uuid: Some("uuid".to_owned()),
..Default::default()
},
host_txs: vec![],
};
vec![],
);

let serialized = serde_json::to_string(&bundle).unwrap();
let deserialized: SignetEthBundle = serde_json::from_str(&serialized).unwrap();
Expand Down
6 changes: 3 additions & 3 deletions crates/evm/src/orders/framed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ impl<T> Framed<T> {

/// Returns the number of events found, including those that may yet be
/// reverted.
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.events.len()
}

/// Returns `true` if the run has no events.
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.events.is_empty()
}

Expand Down Expand Up @@ -73,7 +73,7 @@ impl<T> Framed<T> {
}

/// True if all frames have been exited.
pub fn is_complete(&self) -> bool {
pub const fn is_complete(&self) -> bool {
self.frame_boundaries.is_empty()
}
}
Expand Down
6 changes: 3 additions & 3 deletions crates/evm/src/outcome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ impl<T> ExecutionOutcome<T> {
}

/// Number of blocks in the execution outcome.
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.receipts.len()
}

/// Check if the execution outcome is empty.
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.receipts.is_empty()
}

Expand All @@ -55,7 +55,7 @@ impl<T> ExecutionOutcome<T> {
}

/// Return last block of the execution outcome
pub fn last_block(&self) -> BlockNumber {
pub const fn last_block(&self) -> BlockNumber {
(self.first_block + self.len() as u64).saturating_sub(1)
}

Expand Down
4 changes: 2 additions & 2 deletions crates/sim/src/built.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ impl BuiltBlock {
}

/// Get the number of transactions in the block.
pub fn tx_count(&self) -> usize {
pub const fn tx_count(&self) -> usize {
self.transactions.len()
}

/// Check if the block is empty.
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.transactions.is_empty()
}

Expand Down
6 changes: 3 additions & 3 deletions crates/tx-cache/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ impl TxCacheBundlesResponse {
}

/// Check if the response is empty (has no bundles).
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.bundles.is_empty()
}
}
Expand Down Expand Up @@ -315,7 +315,7 @@ impl TxCacheTransactionsResponse {
}

/// Check if the response is empty (has no transactions).
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.transactions.is_empty()
}
}
Expand Down Expand Up @@ -438,7 +438,7 @@ impl TxCacheSendOrderResponse {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct TxKey {
/// The transaction hash
/// The transaction hash
pub txn_hash: B256,
/// The transaction score
pub score: u64,
Expand Down
2 changes: 1 addition & 1 deletion crates/zenith/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ mod orders {
}

impl Orders::Filled {
pub fn outputs(&self) -> &[IOrders::Output] {
pub const fn outputs(&self) -> &[IOrders::Output] {
self.outputs.as_slice()
}
}
Expand Down