1
1
use crate :: { SignableTransaction , Signed , Transaction , TxType } ;
2
-
3
2
use alloc:: vec:: Vec ;
4
3
use alloy_eips:: {
5
4
eip2718:: IsTyped2718 , eip2930:: AccessList , eip4844:: DATA_GAS_PER_BLOB ,
6
- eip7702:: SignedAuthorization , Typed2718 ,
5
+ eip7594 :: BlobTransactionSidecarVariant , eip7702:: SignedAuthorization , Typed2718 ,
7
6
} ;
8
7
use alloy_primitives:: { Address , Bytes , ChainId , Signature , TxKind , B256 , U256 } ;
9
8
use alloy_rlp:: { BufMut , Decodable , Encodable , Header } ;
@@ -54,7 +53,11 @@ impl<'de> serde::Deserialize<'de> for TxEip4844Variant {
54
53
let tx = TxEip4844SerdeHelper :: deserialize ( deserializer) ?;
55
54
56
55
if let Some ( sidecar) = tx. sidecar {
57
- Ok ( TxEip4844WithSidecar :: from_tx_and_sidecar ( tx. tx , sidecar) . into ( ) )
56
+ Ok ( TxEip4844WithSidecar :: from_tx_and_sidecar (
57
+ tx. tx ,
58
+ BlobTransactionSidecarVariant :: Eip4844 ( sidecar) ,
59
+ )
60
+ . into ( ) )
58
61
} else {
59
62
Ok ( tx. tx . into ( ) )
60
63
}
@@ -87,8 +90,8 @@ impl From<TxEip4844> for TxEip4844Variant {
87
90
}
88
91
}
89
92
90
- impl From < ( TxEip4844 , BlobTransactionSidecar ) > for TxEip4844Variant {
91
- fn from ( ( tx, sidecar) : ( TxEip4844 , BlobTransactionSidecar ) ) -> Self {
93
+ impl From < ( TxEip4844 , BlobTransactionSidecarVariant ) > for TxEip4844Variant {
94
+ fn from ( ( tx, sidecar) : ( TxEip4844 , BlobTransactionSidecarVariant ) ) -> Self {
92
95
TxEip4844WithSidecar :: from_tx_and_sidecar ( tx, sidecar) . into ( )
93
96
}
94
97
}
@@ -537,17 +540,16 @@ impl TxEip4844 {
537
540
/// Takes as input the [KzgSettings](c_kzg::KzgSettings), which should contain the parameters
538
541
/// derived from the KZG trusted setup.
539
542
///
540
- /// This ensures that the blob transaction payload has the same number of blob data elements,
541
- /// commitments, and proofs. Each blob data element is verified against its commitment and
542
- /// proof.
543
+ /// This ensures that the blob transaction payload is consistent with the spec for a given
544
+ /// variant
543
545
///
544
546
/// Returns [BlobTransactionValidationError::InvalidProof] if any blob KZG proof in the response
545
547
/// fails to verify, or if the versioned hashes in the transaction do not match the actual
546
548
/// commitment versioned hashes.
547
549
#[ cfg( feature = "kzg" ) ]
548
550
pub fn validate_blob (
549
551
& self ,
550
- sidecar : & BlobTransactionSidecar ,
552
+ sidecar : & BlobTransactionSidecarVariant ,
551
553
proof_settings : & c_kzg:: KzgSettings ,
552
554
) -> Result < ( ) , BlobTransactionValidationError > {
553
555
sidecar. validate ( & self . blob_versioned_hashes , proof_settings)
@@ -560,7 +562,7 @@ impl TxEip4844 {
560
562
}
561
563
562
564
/// Attaches the blob sidecar to the transaction
563
- pub fn with_sidecar ( self , sidecar : BlobTransactionSidecar ) -> TxEip4844WithSidecar {
565
+ pub fn with_sidecar ( self , sidecar : BlobTransactionSidecarVariant ) -> TxEip4844WithSidecar {
564
566
TxEip4844WithSidecar :: from_tx_and_sidecar ( self , sidecar)
565
567
}
566
568
@@ -774,7 +776,7 @@ impl From<TxEip4844WithSidecar> for TxEip4844 {
774
776
/// This is defined in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#networking) as an element
775
777
/// of a `PooledTransactions` response, and is also used as the format for sending raw transactions
776
778
/// through the network (eth_sendRawTransaction/eth_sendTransaction).
777
- #[ derive( Clone , Debug , Default , PartialEq , Eq , Hash ) ]
779
+ #[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
778
780
#[ cfg_attr( any( test, feature = "arbitrary" ) , derive( arbitrary:: Arbitrary ) ) ]
779
781
#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
780
782
#[ cfg_attr( feature = "serde" , serde( rename_all = "camelCase" ) ) ]
@@ -786,13 +788,17 @@ pub struct TxEip4844WithSidecar {
786
788
pub tx : TxEip4844 ,
787
789
/// The sidecar.
788
790
#[ cfg_attr( feature = "serde" , serde( flatten) ) ]
789
- pub sidecar : BlobTransactionSidecar ,
791
+ pub sidecar : BlobTransactionSidecarVariant ,
790
792
}
791
793
792
794
impl TxEip4844WithSidecar {
793
- /// Constructs a new [TxEip4844WithSidecar] from a [TxEip4844] and a [BlobTransactionSidecar].
795
+ /// Constructs a new [TxEip4844WithSidecar] from a [TxEip4844] and a
796
+ /// [BlobTransactionSidecarVariant].
794
797
#[ doc( alias = "from_transaction_and_sidecar" ) ]
795
- pub const fn from_tx_and_sidecar ( tx : TxEip4844 , sidecar : BlobTransactionSidecar ) -> Self {
798
+ pub const fn from_tx_and_sidecar (
799
+ tx : TxEip4844 ,
800
+ sidecar : BlobTransactionSidecarVariant ,
801
+ ) -> Self {
796
802
Self { tx, sidecar }
797
803
}
798
804
@@ -819,19 +825,20 @@ impl TxEip4844WithSidecar {
819
825
& self . tx
820
826
}
821
827
822
- /// Get access to the inner sidecar [BlobTransactionSidecar ].
823
- pub const fn sidecar ( & self ) -> & BlobTransactionSidecar {
828
+ /// Get access to the inner sidecar [BlobTransactionSidecarVariant ].
829
+ pub const fn sidecar ( & self ) -> & BlobTransactionSidecarVariant {
824
830
& self . sidecar
825
831
}
826
832
827
- /// Consumes the [TxEip4844WithSidecar] and returns the inner sidecar [BlobTransactionSidecar].
828
- pub fn into_sidecar ( self ) -> BlobTransactionSidecar {
833
+ /// Consumes the [TxEip4844WithSidecar] and returns the inner sidecar
834
+ /// [BlobTransactionSidecarVariant].
835
+ pub fn into_sidecar ( self ) -> BlobTransactionSidecarVariant {
829
836
self . sidecar
830
837
}
831
838
832
839
/// Consumes the [TxEip4844WithSidecar] and returns the inner [TxEip4844] and
833
- /// [BlobTransactionSidecar ].
834
- pub fn into_parts ( self ) -> ( TxEip4844 , BlobTransactionSidecar ) {
840
+ /// [BlobTransactionSidecarVariant ].
841
+ pub fn into_parts ( self ) -> ( TxEip4844 , BlobTransactionSidecarVariant ) {
835
842
( self . tx , self . sidecar )
836
843
}
837
844
@@ -988,7 +995,7 @@ impl RlpEcdsaDecodableTx for TxEip4844WithSidecar {
988
995
989
996
fn rlp_decode_fields ( buf : & mut & [ u8 ] ) -> alloy_rlp:: Result < Self > {
990
997
let tx = TxEip4844 :: rlp_decode ( buf) ?;
991
- let sidecar = BlobTransactionSidecar :: rlp_decode_fields ( buf) ?;
998
+ let sidecar = BlobTransactionSidecarVariant :: rlp_decode_fields ( buf) ?;
992
999
Ok ( Self { tx, sidecar } )
993
1000
}
994
1001
@@ -1000,7 +1007,7 @@ impl RlpEcdsaDecodableTx for TxEip4844WithSidecar {
1000
1007
let remaining = buf. len ( ) ;
1001
1008
1002
1009
let ( tx, signature) = TxEip4844 :: rlp_decode_with_signature ( buf) ?;
1003
- let sidecar = BlobTransactionSidecar :: rlp_decode_fields ( buf) ?;
1010
+ let sidecar = BlobTransactionSidecarVariant :: rlp_decode_fields ( buf) ?;
1004
1011
1005
1012
if buf. len ( ) + header. payload_length != remaining {
1006
1013
return Err ( alloy_rlp:: Error :: UnexpectedLength ) ;
@@ -1012,11 +1019,16 @@ impl RlpEcdsaDecodableTx for TxEip4844WithSidecar {
1012
1019
1013
1020
#[ cfg( test) ]
1014
1021
mod tests {
1015
- use super :: { BlobTransactionSidecar , TxEip4844 , TxEip4844WithSidecar } ;
1022
+ use super :: { BlobTransactionSidecar , TxEip4844 , TxEip4844WithSidecar , * } ;
1016
1023
use crate :: { transaction:: eip4844:: TxEip4844Variant , SignableTransaction , TxEnvelope } ;
1017
- use alloy_eips:: eip2930:: AccessList ;
1018
- use alloy_primitives:: { address, b256, bytes, Signature , U256 } ;
1024
+ use alloy_eips:: {
1025
+ eip2930:: AccessList , eip4844:: env_settings:: EnvKzgSettings ,
1026
+ eip7594:: BlobTransactionSidecarVariant , Encodable2718 ,
1027
+ } ;
1028
+ use alloy_primitives:: { address, b256, bytes, hex, Signature , U256 } ;
1019
1029
use alloy_rlp:: { Decodable , Encodable } ;
1030
+ use assert_matches:: assert_matches;
1031
+ use std:: path:: PathBuf ;
1020
1032
1021
1033
#[ test]
1022
1034
fn different_sidecar_same_hash ( ) {
@@ -1035,23 +1047,23 @@ mod tests {
1035
1047
max_fee_per_blob_gas : 1 ,
1036
1048
input : Default :: default ( ) ,
1037
1049
} ;
1038
- let sidecar = BlobTransactionSidecar {
1050
+ let sidecar = BlobTransactionSidecarVariant :: Eip4844 ( BlobTransactionSidecar {
1039
1051
blobs : vec ! [ [ 2 ; 131072 ] . into( ) ] ,
1040
1052
commitments : vec ! [ [ 3 ; 48 ] . into( ) ] ,
1041
1053
proofs : vec ! [ [ 4 ; 48 ] . into( ) ] ,
1042
- } ;
1054
+ } ) ;
1043
1055
let mut tx = TxEip4844WithSidecar { tx, sidecar } ;
1044
1056
let signature = Signature :: test_signature ( ) ;
1045
1057
1046
1058
// turn this transaction into_signed
1047
1059
let expected_signed = tx. clone ( ) . into_signed ( signature) ;
1048
1060
1049
1061
// change the sidecar, adding a single (blob, commitment, proof) pair
1050
- tx. sidecar = BlobTransactionSidecar {
1062
+ tx. sidecar = BlobTransactionSidecarVariant :: Eip4844 ( BlobTransactionSidecar {
1051
1063
blobs : vec ! [ [ 1 ; 131072 ] . into( ) ] ,
1052
1064
commitments : vec ! [ [ 1 ; 48 ] . into( ) ] ,
1053
1065
proofs : vec ! [ [ 1 ; 48 ] . into( ) ] ,
1054
- } ;
1066
+ } ) ;
1055
1067
1056
1068
// turn this transaction into_signed
1057
1069
let actual_signed = tx. into_signed ( signature) ;
@@ -1111,4 +1123,64 @@ mod tests {
1111
1123
b256!( "93fc9daaa0726c3292a2e939df60f7e773c6a6a726a61ce43f4a217c64d85e87" )
1112
1124
) ;
1113
1125
}
1126
+
1127
+ #[ test]
1128
+ fn decode_raw_7594_rlp ( ) {
1129
+ let kzg_settings = EnvKzgSettings :: default ( ) ;
1130
+ let path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "testdata/7594rlp" ) ;
1131
+ let dir = std:: fs:: read_dir ( path) . expect ( "Unable to read folder" ) ;
1132
+ for entry in dir {
1133
+ let entry = entry. unwrap ( ) ;
1134
+ let content = std:: fs:: read_to_string ( entry. path ( ) ) . unwrap ( ) ;
1135
+ let raw = hex:: decode ( content. trim ( ) ) . unwrap ( ) ;
1136
+ let tx = TxEip4844WithSidecar :: eip2718_decode ( & mut raw. as_ref ( ) )
1137
+ . map_err ( |err| {
1138
+ panic ! ( "Failed to decode transaction: {:?} {:?}" , err, entry. path( ) ) ;
1139
+ } )
1140
+ . unwrap ( ) ;
1141
+
1142
+ // Test roundtrip
1143
+ let encoded = tx. encoded_2718 ( ) ;
1144
+ assert_eq ! ( encoded. as_slice( ) , & raw[ ..] , "{:?}" , entry. path( ) ) ;
1145
+
1146
+ let TxEip4844WithSidecar { tx, sidecar } = tx. tx ( ) ;
1147
+ assert_matches ! ( sidecar, BlobTransactionSidecarVariant :: Eip7594 ( _) ) ;
1148
+
1149
+ let result = sidecar. validate ( & tx. blob_versioned_hashes , kzg_settings. get ( ) ) ;
1150
+ assert_matches ! ( result, Ok ( ( ) ) ) ;
1151
+ }
1152
+ }
1153
+
1154
+ #[ test]
1155
+ fn decode_raw_7594_rlp_invalid ( ) {
1156
+ let kzg_settings = EnvKzgSettings :: default ( ) ;
1157
+ let path = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "testdata/7594rlp-invalid" ) ;
1158
+ let dir = std:: fs:: read_dir ( path) . expect ( "Unable to read folder" ) ;
1159
+ for entry in dir {
1160
+ let entry = entry. unwrap ( ) ;
1161
+
1162
+ // TODO: fix emptiness check
1163
+ if entry. path ( ) . file_name ( ) . and_then ( |f| f. to_str ( ) ) == Some ( "0.rlp" ) {
1164
+ continue ;
1165
+ }
1166
+
1167
+ let content = std:: fs:: read_to_string ( entry. path ( ) ) . unwrap ( ) ;
1168
+ let raw = hex:: decode ( content. trim ( ) ) . unwrap ( ) ;
1169
+ let tx = TxEip4844WithSidecar :: eip2718_decode ( & mut raw. as_ref ( ) )
1170
+ . map_err ( |err| {
1171
+ panic ! ( "Failed to decode transaction: {:?} {:?}" , err, entry. path( ) ) ;
1172
+ } )
1173
+ . unwrap ( ) ;
1174
+
1175
+ // Test roundtrip
1176
+ let encoded = tx. encoded_2718 ( ) ;
1177
+ assert_eq ! ( encoded. as_slice( ) , & raw[ ..] , "{:?}" , entry. path( ) ) ;
1178
+
1179
+ let TxEip4844WithSidecar { tx, sidecar } = tx. tx ( ) ;
1180
+ assert_matches ! ( sidecar, BlobTransactionSidecarVariant :: Eip7594 ( _) ) ;
1181
+
1182
+ let result = sidecar. validate ( & tx. blob_versioned_hashes , kzg_settings. get ( ) ) ;
1183
+ assert_matches ! ( result, Err ( _) ) ;
1184
+ }
1185
+ }
1114
1186
}
0 commit comments