Skip to content

Commit e0c220e

Browse files
authored
fix: actually use envelope encoding for pooled tx (#6832)
1 parent 7bee4a0 commit e0c220e

File tree

2 files changed

+67
-10
lines changed

2 files changed

+67
-10
lines changed

crates/primitives/src/transaction/pooled.rs

+63-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
EIP4844_TX_TYPE_ID,
1111
};
1212
use alloy_rlp::{Decodable, Encodable, Error as RlpError, Header, EMPTY_LIST_CODE};
13-
use bytes::Buf;
13+
use bytes::{Buf, BytesMut};
1414
use derive_more::{AsRef, Deref};
1515
use reth_codecs::add_arbitrary_tests;
1616
use serde::{Deserialize, Serialize};
@@ -317,14 +317,61 @@ impl PooledTransactionsElement {
317317
Self::Deposit { transaction, .. } => transaction.payload_len_without_header(),
318318
}
319319
}
320+
321+
/// Returns the enveloped encoded transactions.
322+
///
323+
/// See also [TransactionSigned::encode_enveloped]
324+
pub fn envelope_encoded(&self) -> Bytes {
325+
let mut buf = BytesMut::new();
326+
self.encode_enveloped(&mut buf);
327+
buf.freeze().into()
328+
}
329+
330+
/// Encodes the transaction into the "raw" format (e.g. `eth_sendRawTransaction`).
331+
/// This format is also referred to as "binary" encoding.
332+
///
333+
/// For legacy transactions, it encodes the RLP of the transaction into the buffer:
334+
/// `rlp(tx-data)`
335+
/// For EIP-2718 typed it encodes the type of the transaction followed by the rlp of the
336+
/// transaction: `tx-type || rlp(tx-data)`
337+
pub fn encode_enveloped(&self, out: &mut dyn bytes::BufMut) {
338+
// The encoding of `tx-data` depends on the transaction type. Refer to these docs for more
339+
// information on the exact format:
340+
// - Legacy: TxLegacy::encode_with_signature
341+
// - EIP-2930: TxEip2930::encode_with_signature
342+
// - EIP-1559: TxEip1559::encode_with_signature
343+
// - EIP-4844: BlobTransaction::encode_with_type_inner
344+
match self {
345+
Self::Legacy { transaction, signature, .. } => {
346+
transaction.encode_with_signature(signature, out)
347+
}
348+
Self::Eip2930 { transaction, signature, .. } => {
349+
transaction.encode_with_signature(signature, out, false)
350+
}
351+
Self::Eip1559 { transaction, signature, .. } => {
352+
transaction.encode_with_signature(signature, out, false)
353+
}
354+
Self::BlobTransaction(blob_tx) => {
355+
// The inner encoding is used with `with_header` set to true, making the final
356+
// encoding:
357+
// `tx_type || rlp([transaction_payload_body, blobs, commitments, proofs]))`
358+
blob_tx.encode_with_type_inner(out, false);
359+
}
360+
#[cfg(feature = "optimism")]
361+
Self::Deposit { transaction, .. } => {
362+
transaction.encode(out, false);
363+
}
364+
}
365+
}
320366
}
321367

322368
impl Encodable for PooledTransactionsElement {
323369
/// Encodes an enveloped post EIP-4844 [PooledTransactionsElement].
324370
///
325371
/// For legacy transactions, this encodes the transaction as `rlp(tx-data)`.
326372
///
327-
/// For EIP-2718 transactions, this encodes the transaction as `rlp(tx_type || rlp(tx-data)))`.
373+
/// For EIP-2718 transactions, this encodes the transaction as `rlp(tx_type || rlp(tx-data)))`,
374+
/// ___including__ the RLP-header for the entire transaction.
328375
fn encode(&self, out: &mut dyn bytes::BufMut) {
329376
// The encoding of `tx-data` depends on the transaction type. Refer to these docs for more
330377
// information on the exact format:
@@ -646,7 +693,7 @@ impl From<TransactionSignedEcRecovered> for PooledTransactionsElementEcRecovered
646693
#[cfg(test)]
647694
mod tests {
648695
use super::*;
649-
use alloy_primitives::hex;
696+
use alloy_primitives::{address, hex};
650697
use assert_matches::assert_matches;
651698

652699
#[test]
@@ -690,6 +737,19 @@ mod tests {
690737
}
691738
}
692739

740+
// <https://holesky.etherscan.io/tx/0x7f60faf8a410a80d95f7ffda301d5ab983545913d3d789615df3346579f6c849>
741+
#[test]
742+
fn decode_eip1559_enveloped() {
743+
let data = hex!("02f903d382426882ba09832dc6c0848674742682ed9694714b6a4ea9b94a8a7d9fd362ed72630688c8898c80b90364492d24749189822d8512430d3f3ff7a2ede675ac08265c08e2c56ff6fdaa66dae1cdbe4a5d1d7809f3e99272d067364e597542ac0c369d69e22a6399c3e9bee5da4b07e3f3fdc34c32c3d88aa2268785f3e3f8086df0934b10ef92cfffc2e7f3d90f5e83302e31382e302d64657600000000000000000000000000000000000000000000569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd000000000000000000000000e1e210594771824dad216568b91c9cb4ceed361c00000000000000000000000000000000000000000000000000000000000546e00000000000000000000000000000000000000000000000000000000000e4e1c00000000000000000000000000000000000000000000000000000000065d6750c00000000000000000000000000000000000000000000000000000000000f288000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002cf600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000f1628e56fa6d8c50e5b984a58c0df14de31c7b857ce7ba499945b99252976a93d06dcda6776fc42167fbe71cb59f978f5ef5b12577a90b132d14d9c6efa528076f0161d7bf03643cfc5490ec5084f4a041db7f06c50bd97efa08907ba79ddcac8b890f24d12d8db31abbaaf18985d54f400449ee0559a4452afe53de5853ce090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000c080a01428023fc54a27544abc421d5d017b9a7c5936ad501cbdecd0d9d12d04c1a033a0753104bbf1c87634d6ff3f0ffa0982710612306003eb022363b57994bdef445a"
744+
);
745+
746+
let res = PooledTransactionsElement::decode_enveloped(data.into()).unwrap();
747+
assert_eq!(
748+
res.into_transaction().to(),
749+
Some(address!("714b6a4ea9b94a8a7d9fd362ed72630688c8898c"))
750+
);
751+
}
752+
693753
#[test]
694754
fn legacy_valid_pooled_decoding() {
695755
// d3 <- payload length, d3 - c0 = 0x13 = 19

crates/rpc/rpc/src/eth/api/transactions.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::{
1111
},
1212
EthApi, EthApiSpec,
1313
};
14-
use alloy_rlp::Encodable;
1514
use async_trait::async_trait;
1615
use reth_network_api::NetworkInfo;
1716
use reth_node_api::ConfigureEvmEnv;
@@ -440,12 +439,10 @@ where
440439

441440
async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult<Option<Bytes>> {
442441
// Note: this is mostly used to fetch pooled transactions so we check the pool first
443-
if let Some(tx) = self.pool().get_pooled_transaction_element(hash).map(|tx| {
444-
let mut buf = Vec::new();
445-
tx.encode(&mut buf);
446-
buf
447-
}) {
448-
return Ok(Some(tx.into()));
442+
if let Some(tx) =
443+
self.pool().get_pooled_transaction_element(hash).map(|tx| tx.envelope_encoded())
444+
{
445+
return Ok(Some(tx));
449446
}
450447

451448
self.on_blocking_task(|this| async move {

0 commit comments

Comments
 (0)