diff --git a/Cargo.lock b/Cargo.lock index f3d78ae354..a4057bde56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -376,9 +376,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2dea138d01f0e9739dee905a9e40a0f2347dd217360d813b6b7967ee8c0a8e" +checksum = "ec185bac9d32df79c1132558a450d48f6db0bfb5adef417dbb1a0258153f879b" dependencies = [ "alloy-consensus", "alloy-eips 0.15.11", @@ -673,7 +673,7 @@ dependencies = [ "alloy-serde 0.15.11", "alloy-sol-types", "arbitrary", - "itertools 0.13.0", + "itertools 0.14.0", "jsonrpsee-types", "serde", "serde_json", @@ -5940,9 +5940,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "op-alloy-consensus" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ea96c143b159b53c34f1bc5ff1b196e92d6bef8e6417900a5a02df2baeaf2a" +checksum = "aec9fec6da224c0a86218a21e8e3c28f49a98dbab4bb5ccbd94f80bfbd6a66fb" dependencies = [ "alloy-consensus", "alloy-eips 0.15.11", @@ -5966,9 +5966,9 @@ checksum = "4ef71f23a8caf6f2a2d5cafbdc44956d44e6014dcb9aa58abf7e4e6481c6ec34" [[package]] name = "op-alloy-network" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "603858def0e89940a53907783340e31347154668ae2c5b1fd0e6d232ac2daf8f" +checksum = "37863a5e1b25e2c17195c5e5b73c5b124a7c6ba54187014c566af73159fea45a" dependencies = [ "alloy-consensus", "alloy-network", @@ -5981,9 +5981,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-jsonrpsee" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9007b06c01d440851a66bef626daee227bdc06fbde97bb86eaad961acbdb1edd" +checksum = "c2be914a77a6540efa286059582b95b8d0185144d8c26e3e04f483ec2f178270" dependencies = [ "alloy-primitives", "jsonrpsee", @@ -5991,9 +5991,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0521752d6208545dc6015f8a5038d935d5d5c27971b76e4763c00cde6e216ab" +checksum = "72025d75d797b053cc1bfe6b5951ca8970014cc33d5cccd10029caab4d5c9e77" dependencies = [ "alloy-consensus", "alloy-eips 0.15.11", @@ -6009,9 +6009,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d49b137bebba4ffd4dec9017825aeee83880367dba043f4c65f8a279f82a3991" +checksum = "8e2bbca5c5c85b833810cadde847bad2ebcf5bdd97abbce8ec4cf1565b98c90f" dependencies = [ "alloy-consensus", "alloy-eips 0.15.11", diff --git a/Cargo.toml b/Cargo.toml index 25d5046217..91ee11ac7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -501,11 +501,11 @@ alloy-transport-ws = { version = "0.15.11", default-features = false } # op alloy-op-evm = { version = "0.7.1", default-features = false } alloy-op-hardforks = "0.2.0" -op-alloy-rpc-types = { version = "0.15.4", default-features = false } -op-alloy-rpc-types-engine = { version = "0.15.4", default-features = false } -op-alloy-network = { version = "0.15.4", default-features = false } -op-alloy-consensus = { version = "0.15.4", default-features = false } -op-alloy-rpc-jsonrpsee = { version = "0.15.4", default-features = false } +op-alloy-rpc-types = { version = "0.15.6", default-features = false } +op-alloy-rpc-types-engine = { version = "0.15.6", default-features = false } +op-alloy-network = { version = "0.15.6", default-features = false } +op-alloy-consensus = { version = "0.15.6", default-features = false } +op-alloy-rpc-jsonrpsee = { version = "0.15.6", default-features = false } op-alloy-flz = { version = "0.13.0", default-features = false } # misc diff --git a/crates/ethereum/primitives/src/transaction.rs b/crates/ethereum/primitives/src/transaction.rs index dfd3a0085b..07191142e7 100644 --- a/crates/ethereum/primitives/src/transaction.rs +++ b/crates/ethereum/primitives/src/transaction.rs @@ -3,7 +3,7 @@ use alloc::vec::Vec; use alloy_consensus::{ - transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx}, + transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx, SignerRecoverable}, EthereumTxEnvelope, SignableTransaction, Signed, TxEip1559, TxEip2930, TxEip4844, TxEip7702, TxLegacy, TxType, Typed2718, }; @@ -640,16 +640,23 @@ impl reth_codecs::Compact for TransactionSigned { } } -impl SignedTransaction for TransactionSigned { - fn tx_hash(&self) -> &TxHash { - self.hash.get_or_init(|| self.recalculate_hash()) - } - +impl SignerRecoverable for TransactionSigned { fn recover_signer(&self) -> Result { let signature_hash = self.signature_hash(); recover_signer(&self.signature, signature_hash) } + fn recover_signer_unchecked(&self) -> Result { + let signature_hash = self.signature_hash(); + recover_signer_unchecked(&self.signature, signature_hash) + } +} + +impl SignedTransaction for TransactionSigned { + fn tx_hash(&self) -> &TxHash { + self.hash.get_or_init(|| self.recalculate_hash()) + } + fn recover_signer_unchecked_with_buf( &self, buf: &mut Vec, diff --git a/crates/optimism/primitives/src/transaction/signed.rs b/crates/optimism/primitives/src/transaction/signed.rs index 88db839b03..f98e9f998e 100644 --- a/crates/optimism/primitives/src/transaction/signed.rs +++ b/crates/optimism/primitives/src/transaction/signed.rs @@ -4,7 +4,7 @@ use crate::transaction::OpTransaction; use alloc::vec::Vec; use alloy_consensus::{ - transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx}, + transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx, SignerRecoverable}, Sealed, SignableTransaction, Signed, Transaction, TxEip1559, TxEip2930, TxEip7702, TxLegacy, Typed2718, }; @@ -103,11 +103,7 @@ impl OpTransactionSigned { } } -impl SignedTransaction for OpTransactionSigned { - fn tx_hash(&self) -> &TxHash { - self.hash.get_or_init(|| self.recalculate_hash()) - } - +impl SignerRecoverable for OpTransactionSigned { fn recover_signer(&self) -> Result { // Optimism's Deposit transaction does not have a signature. Directly return the // `from` address. @@ -131,6 +127,12 @@ impl SignedTransaction for OpTransactionSigned { let signature_hash = signature_hash(transaction); recover_signer_unchecked(signature, signature_hash) } +} + +impl SignedTransaction for OpTransactionSigned { + fn tx_hash(&self) -> &TxHash { + self.hash.get_or_init(|| self.recalculate_hash()) + } fn recover_signer_unchecked_with_buf( &self, diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml index f8ee37fb01..f4dcb4dcf3 100644 --- a/crates/primitives-traits/Cargo.toml +++ b/crates/primitives-traits/Cargo.toml @@ -27,7 +27,7 @@ revm-bytecode.workspace = true revm-state.workspace = true # op -op-alloy-consensus = { workspace = true, optional = true } +op-alloy-consensus = { workspace = true, optional = true, features = ["k256"] } # crypto secp256k1 = { workspace = true, features = ["recovery"], optional = true } diff --git a/crates/primitives-traits/src/extended.rs b/crates/primitives-traits/src/extended.rs index ddf339e7f1..a2f25f62d6 100644 --- a/crates/primitives-traits/src/extended.rs +++ b/crates/primitives-traits/src/extended.rs @@ -3,7 +3,7 @@ use crate::{ transaction::signed::{RecoveryError, SignedTransaction}, }; use alloc::vec::Vec; -use alloy_consensus::Transaction; +use alloy_consensus::{transaction::SignerRecoverable, Transaction}; use alloy_eips::{ eip2718::{Eip2718Error, Eip2718Result, IsTyped2718}, eip2930::AccessList, @@ -136,6 +136,20 @@ where } } +impl SignerRecoverable for ExtendedTxEnvelope +where + B: SignedTransaction + IsTyped2718, + T: SignedTransaction, +{ + fn recover_signer(&self) -> Result { + delegate!(self => tx.recover_signer()) + } + + fn recover_signer_unchecked(&self) -> Result { + delegate!(self => tx.recover_signer_unchecked()) + } +} + impl SignedTransaction for ExtendedTxEnvelope where B: SignedTransaction + IsTyped2718, @@ -148,14 +162,6 @@ where } } - fn recover_signer(&self) -> Result { - delegate!(self => tx.recover_signer()) - } - - fn recover_signer_unchecked(&self) -> Result { - delegate!(self => tx.recover_signer_unchecked()) - } - fn recover_signer_unchecked_with_buf( &self, buf: &mut Vec, diff --git a/crates/primitives-traits/src/transaction/signed.rs b/crates/primitives-traits/src/transaction/signed.rs index 79c297edc3..ff1f8f1418 100644 --- a/crates/primitives-traits/src/transaction/signed.rs +++ b/crates/primitives-traits/src/transaction/signed.rs @@ -1,12 +1,12 @@ //! API of a signed transaction. use crate::{ - crypto::secp256k1::{recover_signer, recover_signer_unchecked}, - InMemorySize, MaybeCompact, MaybeSerde, MaybeSerdeBincodeCompat, + crypto::secp256k1::recover_signer_unchecked, InMemorySize, MaybeCompact, MaybeSerde, + MaybeSerdeBincodeCompat, }; use alloc::{fmt, vec::Vec}; use alloy_consensus::{ - transaction::{Recovered, RlpEcdsaEncodableTx}, + transaction::{Recovered, RlpEcdsaEncodableTx, SignerRecoverable}, EthereumTxEnvelope, SignableTransaction, }; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; @@ -38,6 +38,7 @@ pub trait SignedTransaction: + alloy_consensus::Transaction + MaybeSerde + InMemorySize + + SignerRecoverable { /// Returns reference to transaction hash. fn tx_hash(&self) -> &TxHash; @@ -52,17 +53,6 @@ pub trait SignedTransaction: !self.is_eip4844() } - /// Recover signer from signature and hash. - /// - /// Returns `RecoveryError` if the transaction's signature is invalid following [EIP-2](https://eips.ethereum.org/EIPS/eip-2), see also `reth_primitive_traits::crypto::secp256k1::recover_signer`. - /// - /// Note: - /// - /// This can fail for some early ethereum mainnet transactions pre EIP-2, use - /// [`Self::recover_signer_unchecked`] if you want to recover the signer without ensuring that - /// the signature has a low `s` value. - fn recover_signer(&self) -> Result; - /// Recover signer from signature and hash. /// /// Returns an error if the transaction's signature is invalid. @@ -70,15 +60,6 @@ pub trait SignedTransaction: self.recover_signer() } - /// Recover signer from signature and hash _without ensuring that the signature has a low `s` - /// value_. - /// - /// Returns `RecoveryError` if the transaction's signature is invalid, see also - /// `reth_primitive_traits::crypto::secp256k1::recover_signer_unchecked`. - fn recover_signer_unchecked(&self) -> Result { - self.recover_signer_unchecked_with_buf(&mut Vec::new()) - } - /// Recover signer from signature and hash _without ensuring that the signature has a low `s` /// value_. /// @@ -87,8 +68,9 @@ pub trait SignedTransaction: self.recover_signer_unchecked() } - /// Same as [`Self::recover_signer_unchecked`] but receives a buffer to operate on. This is used - /// during batch recovery to avoid allocating a new buffer for each transaction. + /// Same as [`SignerRecoverable::recover_signer_unchecked`] but receives a buffer to operate on. + /// This is used during batch recovery to avoid allocating a new buffer for each + /// transaction. fn recover_signer_unchecked_with_buf( &self, buf: &mut Vec, @@ -109,7 +91,7 @@ pub trait SignedTransaction: /// Tries to recover signer and return [`Recovered`]. /// /// Returns `Err(Self)` if the transaction's signature is invalid, see also - /// [`SignedTransaction::recover_signer`]. + /// [`SignerRecoverable::recover_signer`]. #[auto_impl(keep_default_for(&, Arc))] fn try_into_recovered(self) -> Result, Self> { match self.recover_signer() { @@ -151,11 +133,6 @@ where } } - fn recover_signer(&self) -> Result { - let signature_hash = self.signature_hash(); - recover_signer(self.signature(), signature_hash) - } - fn recover_signer_unchecked_with_buf( &self, buf: &mut Vec, @@ -187,10 +164,6 @@ mod op { } } - fn recover_signer(&self) -> Result { - recover_signer(self.signature(), self.signature_hash()) - } - fn recover_signer_unchecked_with_buf( &self, buf: &mut Vec, @@ -217,46 +190,6 @@ mod op { } } - fn recover_signer(&self) -> Result { - let signature_hash = match self { - Self::Legacy(tx) => tx.signature_hash(), - Self::Eip2930(tx) => tx.signature_hash(), - Self::Eip1559(tx) => tx.signature_hash(), - Self::Eip7702(tx) => tx.signature_hash(), - // Optimism's Deposit transaction does not have a signature. Directly return the - // `from` address. - Self::Deposit(tx) => return Ok(tx.from), - }; - let signature = match self { - Self::Legacy(tx) => tx.signature(), - Self::Eip2930(tx) => tx.signature(), - Self::Eip1559(tx) => tx.signature(), - Self::Eip7702(tx) => tx.signature(), - Self::Deposit(_) => unreachable!("Deposit transactions should not be handled here"), - }; - recover_signer(signature, signature_hash) - } - - fn recover_signer_unchecked(&self) -> Result { - let signature_hash = match self { - Self::Legacy(tx) => tx.signature_hash(), - Self::Eip2930(tx) => tx.signature_hash(), - Self::Eip1559(tx) => tx.signature_hash(), - Self::Eip7702(tx) => tx.signature_hash(), - // Optimism's Deposit transaction does not have a signature. Directly return the - // `from` address. - Self::Deposit(tx) => return Ok(tx.from), - }; - let signature = match self { - Self::Legacy(tx) => tx.signature(), - Self::Eip2930(tx) => tx.signature(), - Self::Eip1559(tx) => tx.signature(), - Self::Eip7702(tx) => tx.signature(), - Self::Deposit(_) => unreachable!("Deposit transactions should not be handled here"), - }; - recover_signer_unchecked(signature, signature_hash) - } - fn recover_signer_unchecked_with_buf( &self, buf: &mut Vec, diff --git a/crates/primitives/benches/recover_ecdsa_crit.rs b/crates/primitives/benches/recover_ecdsa_crit.rs index da6cd8d00f..7521b0fa3b 100644 --- a/crates/primitives/benches/recover_ecdsa_crit.rs +++ b/crates/primitives/benches/recover_ecdsa_crit.rs @@ -1,9 +1,9 @@ #![allow(missing_docs)] +use alloy_consensus::transaction::SignerRecoverable; use alloy_primitives::hex_literal::hex; use alloy_rlp::Decodable; use criterion::{criterion_group, criterion_main, Criterion}; use reth_ethereum_primitives::TransactionSigned; -use reth_primitives_traits::SignedTransaction; /// Benchmarks the recovery of the public key from the ECDSA message using criterion. pub fn criterion_benchmark(c: &mut Criterion) { @@ -12,7 +12,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { let raw =hex!("f88b8212b085028fa6ae00830f424094aad593da0c8116ef7d2d594dd6a63241bccfc26c80a48318b64b000000000000000000000000641c5d790f862a58ec7abcfd644c0442e9c201b32aa0a6ef9e170bca5ffb7ac05433b13b7043de667fbb0b4a5e45d3b54fb2d6efcc63a0037ec2c05c3d60c5f5f78244ce0a3859e3a18a36c61efb061b383507d3ce19d2"); let mut pointer = raw.as_ref(); let tx = TransactionSigned::decode(&mut pointer).unwrap(); - SignedTransaction::recover_signer(&tx).unwrap(); + SignerRecoverable::recover_signer(&tx).unwrap(); } ) }); diff --git a/crates/prune/prune/src/segments/user/sender_recovery.rs b/crates/prune/prune/src/segments/user/sender_recovery.rs index bb0a812aa9..104fbf110f 100644 --- a/crates/prune/prune/src/segments/user/sender_recovery.rs +++ b/crates/prune/prune/src/segments/user/sender_recovery.rs @@ -90,7 +90,6 @@ mod tests { Itertools, }; use reth_db_api::tables; - use reth_primitives_traits::SignedTransaction; use reth_provider::{DatabaseProviderFactory, PruneCheckpointReader}; use reth_prune_types::{PruneCheckpoint, PruneMode, PruneProgress, PruneSegment}; use reth_stages::test_utils::{StorageKind, TestStageDB}; @@ -115,7 +114,7 @@ mod tests { for transaction in &block.body().transactions { transaction_senders.push(( transaction_senders.len() as u64, - SignedTransaction::recover_signer(transaction).expect("recover signer"), + transaction.recover_signer().expect("recover signer"), )); } } diff --git a/crates/rpc/rpc-eth-types/src/gas_oracle.rs b/crates/rpc/rpc-eth-types/src/gas_oracle.rs index 9ce915905e..48c4d1e11a 100644 --- a/crates/rpc/rpc-eth-types/src/gas_oracle.rs +++ b/crates/rpc/rpc-eth-types/src/gas_oracle.rs @@ -2,13 +2,15 @@ //! previous blocks. use super::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError}; -use alloy_consensus::{constants::GWEI_TO_WEI, BlockHeader, Transaction}; +use alloy_consensus::{ + constants::GWEI_TO_WEI, transaction::SignerRecoverable, BlockHeader, Transaction, +}; use alloy_eips::BlockNumberOrTag; use alloy_primitives::{B256, U256}; use alloy_rpc_types_eth::BlockId; use derive_more::{Deref, DerefMut, From, Into}; use itertools::Itertools; -use reth_primitives_traits::{BlockBody, SignedTransaction}; +use reth_primitives_traits::BlockBody; use reth_rpc_server_types::{ constants, constants::gas_oracle::{ diff --git a/crates/rpc/rpc-eth-types/src/utils.rs b/crates/rpc/rpc-eth-types/src/utils.rs index e7873920a9..d3bb655be1 100644 --- a/crates/rpc/rpc-eth-types/src/utils.rs +++ b/crates/rpc/rpc-eth-types/src/utils.rs @@ -18,7 +18,8 @@ pub fn recover_raw_transaction(mut data: &[u8]) -> EthResu let transaction = T::decode_2718(&mut data).map_err(|_| EthApiError::FailedToDecodeSignedTransaction)?; - transaction.try_into_recovered().or(Err(EthApiError::InvalidTransactionSignature)) + SignedTransaction::try_into_recovered(transaction) + .or(Err(EthApiError::InvalidTransactionSignature)) } /// Performs a binary search within a given block range to find the desired block number. diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 85c6e65a44..400182bd2b 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -1,4 +1,4 @@ -use alloy_consensus::BlockHeader; +use alloy_consensus::{transaction::SignerRecoverable, BlockHeader}; use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag}; use alloy_genesis::ChainConfig; use alloy_primitives::{Address, Bytes, B256}; diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index dff8ececc9..fb1cf15ccc 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -19,7 +19,10 @@ use crate::{ TransactionVariant, TransactionsProvider, TransactionsProviderExt, TrieWriter, WithdrawalsProvider, }; -use alloy_consensus::{transaction::TransactionMeta, BlockHeader, Header, TxReceipt}; +use alloy_consensus::{ + transaction::{SignerRecoverable, TransactionMeta}, + BlockHeader, Header, TxReceipt, +}; use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals, BlockHashOrNumber}; use alloy_primitives::{ keccak256, diff --git a/crates/storage/provider/src/providers/static_file/jar.rs b/crates/storage/provider/src/providers/static_file/jar.rs index 64b0d6e284..2c79b1d55c 100644 --- a/crates/storage/provider/src/providers/static_file/jar.rs +++ b/crates/storage/provider/src/providers/static_file/jar.rs @@ -6,7 +6,7 @@ use crate::{ to_range, BlockHashReader, BlockNumReader, HeaderProvider, ReceiptProvider, TransactionsProvider, }; -use alloy_consensus::transaction::TransactionMeta; +use alloy_consensus::transaction::{SignerRecoverable, TransactionMeta}; use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals, BlockHashOrNumber}; use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256}; use reth_chainspec::ChainInfo; diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 9804697db8..72ffa09045 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -7,7 +7,10 @@ use crate::{ ReceiptProvider, StageCheckpointReader, StatsReader, TransactionVariant, TransactionsProvider, TransactionsProviderExt, WithdrawalsProvider, }; -use alloy_consensus::{transaction::TransactionMeta, Header}; +use alloy_consensus::{ + transaction::{SignerRecoverable, TransactionMeta}, + Header, +}; use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals, BlockHashOrNumber}; use alloy_primitives::{ b256, keccak256, Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256, diff --git a/examples/custom-node/src/primitives/tx.rs b/examples/custom-node/src/primitives/tx.rs index d862281bf6..6cbd9b83d6 100644 --- a/examples/custom-node/src/primitives/tx.rs +++ b/examples/custom-node/src/primitives/tx.rs @@ -4,6 +4,7 @@ use alloy_consensus::{ secp256k1::{recover_signer, recover_signer_unchecked}, RecoveryError, }, + transaction::SignerRecoverable, SignableTransaction, Signed, Transaction, }; use alloy_eips::{eip2718::Eip2718Result, Decodable2718, Encodable2718, Typed2718}; @@ -100,16 +101,23 @@ impl Transaction for CustomTransactionEnvelope { } } -impl SignedTransaction for CustomTransactionEnvelope { - fn tx_hash(&self) -> &TxHash { - self.inner.hash() - } - +impl SignerRecoverable for CustomTransactionEnvelope { fn recover_signer(&self) -> Result { let signature_hash = self.inner.signature_hash(); recover_signer(self.inner.signature(), signature_hash) } + fn recover_signer_unchecked(&self) -> Result { + let signature_hash = self.inner.signature_hash(); + recover_signer_unchecked(self.inner.signature(), signature_hash) + } +} + +impl SignedTransaction for CustomTransactionEnvelope { + fn tx_hash(&self) -> &TxHash { + self.inner.hash() + } + fn recover_signer_unchecked_with_buf( &self, buf: &mut Vec,