alloy_consensus/transaction/
pooled.rs1use crate::{
5 error::ValueError,
6 transaction::{RlpEcdsaDecodableTx, TxEip1559, TxEip2930, TxEip4844, TxLegacy},
7 SignableTransaction, Signed, Transaction, TxEip4844Variant, TxEip4844WithSidecar, TxEip7702,
8 TxEnvelope, TxType,
9};
10use alloy_eips::{
11 eip2718::{Decodable2718, Eip2718Error, Eip2718Result, Encodable2718},
12 eip2930::AccessList,
13 eip7702::SignedAuthorization,
14 Typed2718,
15};
16use alloy_primitives::{
17 bytes, Bytes, ChainId, PrimitiveSignature as Signature, TxHash, TxKind, B256, U256,
18};
19use alloy_rlp::{Decodable, Encodable, Header};
20use core::hash::{Hash, Hasher};
21
22#[derive(Clone, Debug, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31#[cfg_attr(all(any(test, feature = "arbitrary"), feature = "k256"), derive(arbitrary::Arbitrary))]
32pub enum PooledTransaction {
33 Legacy(Signed<TxLegacy>),
35 Eip2930(Signed<TxEip2930>),
37 Eip1559(Signed<TxEip1559>),
39 Eip4844(Signed<TxEip4844WithSidecar>),
41 Eip7702(Signed<TxEip7702>),
43}
44
45impl PooledTransaction {
46 pub fn signature_hash(&self) -> B256 {
49 match self {
50 Self::Legacy(tx) => tx.signature_hash(),
51 Self::Eip2930(tx) => tx.signature_hash(),
52 Self::Eip1559(tx) => tx.signature_hash(),
53 Self::Eip7702(tx) => tx.signature_hash(),
54 Self::Eip4844(tx) => tx.signature_hash(),
55 }
56 }
57
58 pub fn hash(&self) -> &TxHash {
60 match self {
61 Self::Legacy(tx) => tx.hash(),
62 Self::Eip2930(tx) => tx.hash(),
63 Self::Eip1559(tx) => tx.hash(),
64 Self::Eip7702(tx) => tx.hash(),
65 Self::Eip4844(tx) => tx.hash(),
66 }
67 }
68
69 pub const fn signature(&self) -> &Signature {
71 match self {
72 Self::Legacy(tx) => tx.signature(),
73 Self::Eip2930(tx) => tx.signature(),
74 Self::Eip1559(tx) => tx.signature(),
75 Self::Eip7702(tx) => tx.signature(),
76 Self::Eip4844(tx) => tx.signature(),
77 }
78 }
79
80 fn network_len(&self) -> usize {
83 let mut payload_length = self.encode_2718_len();
84 if !self.is_legacy() {
85 payload_length += Header { list: false, payload_length }.length();
86 }
87
88 payload_length
89 }
90
91 #[cfg(feature = "k256")]
93 pub fn recover_signer(
94 &self,
95 ) -> Result<alloy_primitives::Address, alloy_primitives::SignatureError> {
96 match self {
97 Self::Legacy(tx) => tx.recover_signer(),
98 Self::Eip2930(tx) => tx.recover_signer(),
99 Self::Eip1559(tx) => tx.recover_signer(),
100 Self::Eip4844(tx) => tx.recover_signer(),
101 Self::Eip7702(tx) => tx.recover_signer(),
102 }
103 }
104
105 pub fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
108 match self {
109 Self::Legacy(tx) => tx.tx().encode_for_signing(out),
110 Self::Eip2930(tx) => tx.tx().encode_for_signing(out),
111 Self::Eip1559(tx) => tx.tx().encode_for_signing(out),
112 Self::Eip4844(tx) => tx.tx().encode_for_signing(out),
113 Self::Eip7702(tx) => tx.tx().encode_for_signing(out),
114 }
115 }
116
117 pub fn into_envelope(self) -> TxEnvelope {
119 match self {
120 Self::Legacy(tx) => tx.into(),
121 Self::Eip2930(tx) => tx.into(),
122 Self::Eip1559(tx) => tx.into(),
123 Self::Eip7702(tx) => tx.into(),
124 Self::Eip4844(tx) => tx.into(),
125 }
126 }
127
128 pub const fn as_legacy(&self) -> Option<&TxLegacy> {
130 match self {
131 Self::Legacy(tx) => Some(tx.tx()),
132 _ => None,
133 }
134 }
135
136 pub const fn as_eip2930(&self) -> Option<&TxEip2930> {
138 match self {
139 Self::Eip2930(tx) => Some(tx.tx()),
140 _ => None,
141 }
142 }
143
144 pub const fn as_eip1559(&self) -> Option<&TxEip1559> {
146 match self {
147 Self::Eip1559(tx) => Some(tx.tx()),
148 _ => None,
149 }
150 }
151
152 pub const fn as_eip4844_with_sidecar(&self) -> Option<&TxEip4844WithSidecar> {
154 match self {
155 Self::Eip4844(tx) => Some(tx.tx()),
156 _ => None,
157 }
158 }
159
160 pub const fn as_eip4844(&self) -> Option<&TxEip4844> {
162 match self {
163 Self::Eip4844(tx) => Some(tx.tx().tx()),
164 _ => None,
165 }
166 }
167
168 pub const fn as_eip7702(&self) -> Option<&TxEip7702> {
170 match self {
171 Self::Eip7702(tx) => Some(tx.tx()),
172 _ => None,
173 }
174 }
175
176 pub fn try_into_legacy(self) -> Result<Signed<TxLegacy>, Self> {
179 match self {
180 Self::Legacy(tx) => Ok(tx),
181 tx => Err(tx),
182 }
183 }
184
185 pub fn try_into_eip2930(self) -> Result<Signed<TxEip2930>, Self> {
188 match self {
189 Self::Eip2930(tx) => Ok(tx),
190 tx => Err(tx),
191 }
192 }
193
194 pub fn try_into_eip1559(self) -> Result<Signed<TxEip1559>, Self> {
197 match self {
198 Self::Eip1559(tx) => Ok(tx),
199 tx => Err(tx),
200 }
201 }
202
203 pub fn try_into_eip4844(self) -> Result<Signed<TxEip4844WithSidecar>, Self> {
206 match self {
207 Self::Eip4844(tx) => Ok(tx),
208 tx => Err(tx),
209 }
210 }
211
212 pub fn try_into_eip7702(self) -> Result<Signed<TxEip7702>, Self> {
215 match self {
216 Self::Eip7702(tx) => Ok(tx),
217 tx => Err(tx),
218 }
219 }
220}
221
222impl From<Signed<TxLegacy>> for PooledTransaction {
223 fn from(v: Signed<TxLegacy>) -> Self {
224 Self::Legacy(v)
225 }
226}
227
228impl From<Signed<TxEip2930>> for PooledTransaction {
229 fn from(v: Signed<TxEip2930>) -> Self {
230 Self::Eip2930(v)
231 }
232}
233
234impl From<Signed<TxEip1559>> for PooledTransaction {
235 fn from(v: Signed<TxEip1559>) -> Self {
236 Self::Eip1559(v)
237 }
238}
239
240impl From<Signed<TxEip4844WithSidecar>> for PooledTransaction {
241 fn from(v: Signed<TxEip4844WithSidecar>) -> Self {
242 let (tx, signature, hash) = v.into_parts();
243 Self::Eip4844(Signed::new_unchecked(tx, signature, hash))
244 }
245}
246
247impl TryFrom<Signed<TxEip4844Variant>> for PooledTransaction {
248 type Error = ValueError<Signed<TxEip4844Variant>>;
249
250 fn try_from(value: Signed<TxEip4844Variant>) -> Result<Self, Self::Error> {
251 let (value, signature, hash) = value.into_parts();
252 match value {
253 tx @ TxEip4844Variant::TxEip4844(_) => Err(ValueError::new_static(
254 Signed::new_unchecked(tx, signature, hash),
255 "pooled transaction requires 4844 sidecar",
256 )),
257 TxEip4844Variant::TxEip4844WithSidecar(tx) => {
258 Ok(Signed::new_unchecked(tx, signature, hash).into())
259 }
260 }
261 }
262}
263
264impl TryFrom<TxEnvelope> for PooledTransaction {
265 type Error = ValueError<TxEnvelope>;
266
267 fn try_from(value: TxEnvelope) -> Result<Self, Self::Error> {
268 value.try_into_pooled()
269 }
270}
271
272impl From<Signed<TxEip7702>> for PooledTransaction {
273 fn from(v: Signed<TxEip7702>) -> Self {
274 Self::Eip7702(v)
275 }
276}
277
278impl Hash for PooledTransaction {
279 fn hash<H: Hasher>(&self, state: &mut H) {
280 self.trie_hash().hash(state);
281 }
282}
283
284impl Encodable for PooledTransaction {
285 fn encode(&self, out: &mut dyn bytes::BufMut) {
294 self.network_encode(out);
295 }
296
297 fn length(&self) -> usize {
298 self.network_len()
299 }
300}
301
302impl Decodable for PooledTransaction {
303 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
307 Ok(Self::network_decode(buf)?)
308 }
309}
310
311impl Encodable2718 for PooledTransaction {
312 fn encode_2718_len(&self) -> usize {
313 match self {
314 Self::Legacy(tx) => tx.eip2718_encoded_length(),
315 Self::Eip2930(tx) => tx.eip2718_encoded_length(),
316 Self::Eip1559(tx) => tx.eip2718_encoded_length(),
317 Self::Eip7702(tx) => tx.eip2718_encoded_length(),
318 Self::Eip4844(tx) => tx.eip2718_encoded_length(),
319 }
320 }
321
322 fn encode_2718(&self, out: &mut dyn alloy_rlp::BufMut) {
323 match self {
324 Self::Legacy(tx) => tx.eip2718_encode(out),
325 Self::Eip2930(tx) => tx.eip2718_encode(out),
326 Self::Eip1559(tx) => tx.eip2718_encode(out),
327 Self::Eip7702(tx) => tx.eip2718_encode(out),
328 Self::Eip4844(tx) => tx.eip2718_encode(out),
329 }
330 }
331
332 fn trie_hash(&self) -> B256 {
333 *self.hash()
334 }
335}
336
337impl Decodable2718 for PooledTransaction {
338 fn typed_decode(ty: u8, buf: &mut &[u8]) -> Eip2718Result<Self> {
339 match ty.try_into().map_err(|_| alloy_rlp::Error::Custom("unexpected tx type"))? {
340 TxType::Eip2930 => Ok(TxEip2930::rlp_decode_signed(buf)?.into()),
341 TxType::Eip1559 => Ok(TxEip1559::rlp_decode_signed(buf)?.into()),
342 TxType::Eip4844 => Ok(TxEip4844WithSidecar::rlp_decode_signed(buf)?.into()),
343 TxType::Eip7702 => Ok(TxEip7702::rlp_decode_signed(buf)?.into()),
344 TxType::Legacy => Err(Eip2718Error::UnexpectedType(0)),
345 }
346 }
347
348 fn fallback_decode(buf: &mut &[u8]) -> Eip2718Result<Self> {
349 TxLegacy::rlp_decode_signed(buf).map(Into::into).map_err(Into::into)
350 }
351}
352
353impl Transaction for PooledTransaction {
354 fn chain_id(&self) -> Option<ChainId> {
355 match self {
356 Self::Legacy(tx) => tx.tx().chain_id(),
357 Self::Eip2930(tx) => tx.tx().chain_id(),
358 Self::Eip1559(tx) => tx.tx().chain_id(),
359 Self::Eip7702(tx) => tx.tx().chain_id(),
360 Self::Eip4844(tx) => tx.tx().chain_id(),
361 }
362 }
363
364 fn nonce(&self) -> u64 {
365 match self {
366 Self::Legacy(tx) => tx.tx().nonce(),
367 Self::Eip2930(tx) => tx.tx().nonce(),
368 Self::Eip1559(tx) => tx.tx().nonce(),
369 Self::Eip7702(tx) => tx.tx().nonce(),
370 Self::Eip4844(tx) => tx.tx().nonce(),
371 }
372 }
373
374 fn gas_limit(&self) -> u64 {
375 match self {
376 Self::Legacy(tx) => tx.tx().gas_limit(),
377 Self::Eip2930(tx) => tx.tx().gas_limit(),
378 Self::Eip1559(tx) => tx.tx().gas_limit(),
379 Self::Eip7702(tx) => tx.tx().gas_limit(),
380 Self::Eip4844(tx) => tx.tx().gas_limit(),
381 }
382 }
383
384 fn gas_price(&self) -> Option<u128> {
385 match self {
386 Self::Legacy(tx) => tx.tx().gas_price(),
387 Self::Eip2930(tx) => tx.tx().gas_price(),
388 Self::Eip1559(tx) => tx.tx().gas_price(),
389 Self::Eip7702(tx) => tx.tx().gas_price(),
390 Self::Eip4844(tx) => tx.tx().gas_price(),
391 }
392 }
393
394 fn max_fee_per_gas(&self) -> u128 {
395 match self {
396 Self::Legacy(tx) => tx.tx().max_fee_per_gas(),
397 Self::Eip2930(tx) => tx.tx().max_fee_per_gas(),
398 Self::Eip1559(tx) => tx.tx().max_fee_per_gas(),
399 Self::Eip7702(tx) => tx.tx().max_fee_per_gas(),
400 Self::Eip4844(tx) => tx.tx().max_fee_per_gas(),
401 }
402 }
403
404 fn max_priority_fee_per_gas(&self) -> Option<u128> {
405 match self {
406 Self::Legacy(tx) => tx.tx().max_priority_fee_per_gas(),
407 Self::Eip2930(tx) => tx.tx().max_priority_fee_per_gas(),
408 Self::Eip1559(tx) => tx.tx().max_priority_fee_per_gas(),
409 Self::Eip7702(tx) => tx.tx().max_priority_fee_per_gas(),
410 Self::Eip4844(tx) => tx.tx().max_priority_fee_per_gas(),
411 }
412 }
413
414 fn max_fee_per_blob_gas(&self) -> Option<u128> {
415 match self {
416 Self::Legacy(tx) => tx.tx().max_fee_per_blob_gas(),
417 Self::Eip2930(tx) => tx.tx().max_fee_per_blob_gas(),
418 Self::Eip1559(tx) => tx.tx().max_fee_per_blob_gas(),
419 Self::Eip7702(tx) => tx.tx().max_fee_per_blob_gas(),
420 Self::Eip4844(tx) => tx.tx().max_fee_per_blob_gas(),
421 }
422 }
423
424 fn priority_fee_or_price(&self) -> u128 {
425 match self {
426 Self::Legacy(tx) => tx.tx().priority_fee_or_price(),
427 Self::Eip2930(tx) => tx.tx().priority_fee_or_price(),
428 Self::Eip1559(tx) => tx.tx().priority_fee_or_price(),
429 Self::Eip7702(tx) => tx.tx().priority_fee_or_price(),
430 Self::Eip4844(tx) => tx.tx().priority_fee_or_price(),
431 }
432 }
433
434 fn effective_gas_price(&self, base_fee: Option<u64>) -> u128 {
435 match self {
436 Self::Legacy(tx) => tx.tx().effective_gas_price(base_fee),
437 Self::Eip2930(tx) => tx.tx().effective_gas_price(base_fee),
438 Self::Eip1559(tx) => tx.tx().effective_gas_price(base_fee),
439 Self::Eip7702(tx) => tx.tx().effective_gas_price(base_fee),
440 Self::Eip4844(tx) => tx.tx().effective_gas_price(base_fee),
441 }
442 }
443
444 fn is_dynamic_fee(&self) -> bool {
445 match self {
446 Self::Legacy(tx) => tx.tx().is_dynamic_fee(),
447 Self::Eip2930(tx) => tx.tx().is_dynamic_fee(),
448 Self::Eip1559(tx) => tx.tx().is_dynamic_fee(),
449 Self::Eip7702(tx) => tx.tx().is_dynamic_fee(),
450 Self::Eip4844(tx) => tx.tx().is_dynamic_fee(),
451 }
452 }
453
454 fn kind(&self) -> TxKind {
455 match self {
456 Self::Legacy(tx) => tx.tx().kind(),
457 Self::Eip2930(tx) => tx.tx().kind(),
458 Self::Eip1559(tx) => tx.tx().kind(),
459 Self::Eip7702(tx) => tx.tx().kind(),
460 Self::Eip4844(tx) => tx.tx().kind(),
461 }
462 }
463
464 fn is_create(&self) -> bool {
465 match self {
466 Self::Legacy(tx) => tx.tx().is_create(),
467 Self::Eip2930(tx) => tx.tx().is_create(),
468 Self::Eip1559(tx) => tx.tx().is_create(),
469 Self::Eip7702(tx) => tx.tx().is_create(),
470 Self::Eip4844(tx) => tx.tx().is_create(),
471 }
472 }
473
474 fn value(&self) -> U256 {
475 match self {
476 Self::Legacy(tx) => tx.tx().value(),
477 Self::Eip2930(tx) => tx.tx().value(),
478 Self::Eip1559(tx) => tx.tx().value(),
479 Self::Eip7702(tx) => tx.tx().value(),
480 Self::Eip4844(tx) => tx.tx().value(),
481 }
482 }
483
484 fn input(&self) -> &Bytes {
485 match self {
486 Self::Legacy(tx) => tx.tx().input(),
487 Self::Eip2930(tx) => tx.tx().input(),
488 Self::Eip1559(tx) => tx.tx().input(),
489 Self::Eip7702(tx) => tx.tx().input(),
490 Self::Eip4844(tx) => tx.tx().input(),
491 }
492 }
493
494 fn access_list(&self) -> Option<&AccessList> {
495 match self {
496 Self::Legacy(tx) => tx.tx().access_list(),
497 Self::Eip2930(tx) => tx.tx().access_list(),
498 Self::Eip1559(tx) => tx.tx().access_list(),
499 Self::Eip7702(tx) => tx.tx().access_list(),
500 Self::Eip4844(tx) => tx.tx().access_list(),
501 }
502 }
503
504 fn blob_versioned_hashes(&self) -> Option<&[B256]> {
505 match self {
506 Self::Legacy(tx) => tx.tx().blob_versioned_hashes(),
507 Self::Eip2930(tx) => tx.tx().blob_versioned_hashes(),
508 Self::Eip1559(tx) => tx.tx().blob_versioned_hashes(),
509 Self::Eip7702(tx) => tx.tx().blob_versioned_hashes(),
510 Self::Eip4844(tx) => tx.tx().blob_versioned_hashes(),
511 }
512 }
513
514 fn authorization_list(&self) -> Option<&[SignedAuthorization]> {
515 match self {
516 Self::Legacy(tx) => tx.tx().authorization_list(),
517 Self::Eip2930(tx) => tx.tx().authorization_list(),
518 Self::Eip1559(tx) => tx.tx().authorization_list(),
519 Self::Eip7702(tx) => tx.tx().authorization_list(),
520 Self::Eip4844(tx) => tx.tx().authorization_list(),
521 }
522 }
523}
524
525impl Typed2718 for PooledTransaction {
526 fn ty(&self) -> u8 {
527 match self {
528 Self::Legacy(tx) => tx.tx().ty(),
529 Self::Eip2930(tx) => tx.tx().ty(),
530 Self::Eip1559(tx) => tx.tx().ty(),
531 Self::Eip7702(tx) => tx.tx().ty(),
532 Self::Eip4844(tx) => tx.tx().ty(),
533 }
534 }
535}
536
537impl From<PooledTransaction> for TxEnvelope {
538 fn from(tx: PooledTransaction) -> Self {
539 tx.into_envelope()
540 }
541}
542
543#[cfg(test)]
544mod tests {
545 use super::*;
546 use alloy_primitives::{address, hex};
547 use bytes::Bytes;
548 use std::path::PathBuf;
549
550 #[test]
551 fn invalid_legacy_pooled_decoding_input_too_short() {
552 let input_too_short = [
553 &hex!("d90b0280808bc5cd028083c5cdfd9e407c56565656")[..],
555 &hex!("c10b02808083c5cd028883c5cdfd9e407c56565656"),
561 &hex!("c10b0280808bc5cd028083c5cdfd9e407c56565656"),
562 &hex!("d40b02808083c5cdeb8783c5acfd9e407c5656565656"),
565 &hex!("d30102808083c5cd02887dc5cdfd9e64fd9e407c56"),
566 ];
567
568 for hex_data in &input_too_short {
569 let input_rlp = &mut &hex_data[..];
570 let res = PooledTransaction::decode(input_rlp);
571
572 assert!(
573 res.is_err(),
574 "expected err after decoding rlp input: {:x?}",
575 Bytes::copy_from_slice(hex_data)
576 );
577
578 let input_rlp = &mut &hex_data[..];
580 let res = PooledTransaction::decode_2718(input_rlp);
581
582 assert!(
583 res.is_err(),
584 "expected err after decoding enveloped rlp input: {:x?}",
585 Bytes::copy_from_slice(hex_data)
586 );
587 }
588 }
589
590 #[test]
592 fn decode_eip1559_enveloped() {
593 let data = hex!("02f903d382426882ba09832dc6c0848674742682ed9694714b6a4ea9b94a8a7d9fd362ed72630688c8898c80b90364492d24749189822d8512430d3f3ff7a2ede675ac08265c08e2c56ff6fdaa66dae1cdbe4a5d1d7809f3e99272d067364e597542ac0c369d69e22a6399c3e9bee5da4b07e3f3fdc34c32c3d88aa2268785f3e3f8086df0934b10ef92cfffc2e7f3d90f5e83302e31382e302d64657600000000000000000000000000000000000000000000569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd000000000000000000000000e1e210594771824dad216568b91c9cb4ceed361c00000000000000000000000000000000000000000000000000000000000546e00000000000000000000000000000000000000000000000000000000000e4e1c00000000000000000000000000000000000000000000000000000000065d6750c00000000000000000000000000000000000000000000000000000000000f288000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002cf600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000f1628e56fa6d8c50e5b984a58c0df14de31c7b857ce7ba499945b99252976a93d06dcda6776fc42167fbe71cb59f978f5ef5b12577a90b132d14d9c6efa528076f0161d7bf03643cfc5490ec5084f4a041db7f06c50bd97efa08907ba79ddcac8b890f24d12d8db31abbaaf18985d54f400449ee0559a4452afe53de5853ce090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000c080a01428023fc54a27544abc421d5d017b9a7c5936ad501cbdecd0d9d12d04c1a033a0753104bbf1c87634d6ff3f0ffa0982710612306003eb022363b57994bdef445a"
594);
595
596 let res = PooledTransaction::decode_2718(&mut &data[..]).unwrap();
597 assert_eq!(res.to(), Some(address!("714b6a4ea9b94a8a7d9fd362ed72630688c8898c")));
598 }
599
600 #[test]
601 fn legacy_valid_pooled_decoding() {
602 let data = &hex!("d30b02808083c5cdeb8783c5acfd9e407c565656")[..];
613
614 let input_rlp = &mut &data[..];
615 let res = PooledTransaction::decode(input_rlp);
616 assert!(res.is_ok());
617 assert!(input_rlp.is_empty());
618
619 let res = PooledTransaction::decode_2718(&mut &data[..]);
621 assert!(res.is_ok());
622 }
623
624 #[test]
625 fn decode_encode_raw_4844_rlp() {
626 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata/4844rlp");
627 let dir = std::fs::read_dir(path).expect("Unable to read folder");
628 for entry in dir {
629 let entry = entry.unwrap();
630 let content = std::fs::read_to_string(entry.path()).unwrap();
631 let raw = hex::decode(content.trim()).unwrap();
632 let tx = PooledTransaction::decode_2718(&mut raw.as_ref())
633 .map_err(|err| {
634 panic!("Failed to decode transaction: {:?} {:?}", err, entry.path());
635 })
636 .unwrap();
637 assert!(tx.is_eip4844());
639 let encoded = tx.encoded_2718();
640 assert_eq!(encoded.as_slice(), &raw[..], "{:?}", entry.path());
641 }
642 }
643}