@@ -48,6 +48,7 @@ use namada::ledger::storage::{
4848 DBIter , Sha256Hasher , Storage , StorageHasher , TempWlStorage , WlStorage , DB ,
4949 EPOCH_SWITCH_BLOCKS_DELAY ,
5050} ;
51+ use namada:: ledger:: storage_api:: tx:: validate_tx_bytes;
5152use namada:: ledger:: storage_api:: { self , StorageRead } ;
5253use namada:: ledger:: { parameters, pos, protocol} ;
5354use namada:: proof_of_stake:: { self , process_slashes, read_pos_params, slash} ;
@@ -154,6 +155,7 @@ pub enum ErrorCodes {
154155 TxGasLimit = 11 ,
155156 FeeError = 12 ,
156157 InvalidVoteExtension = 13 ,
158+ TooLarge = 14 ,
157159}
158160
159161impl ErrorCodes {
@@ -167,7 +169,8 @@ impl ErrorCodes {
167169 Ok | WasmRuntimeError => true ,
168170 InvalidTx | InvalidSig | InvalidOrder | ExtraTxs
169171 | Undecryptable | AllocationError | ReplayTx | InvalidChainId
170- | ExpiredTx | TxGasLimit | FeeError | InvalidVoteExtension => false ,
172+ | ExpiredTx | TxGasLimit | FeeError | InvalidVoteExtension
173+ | TooLarge => false ,
171174 }
172175 }
173176}
@@ -1073,6 +1076,18 @@ where
10731076 const VALID_MSG : & str = "Mempool validation passed" ;
10741077 const INVALID_MSG : & str = "Mempool validation failed" ;
10751078
1079+ // check tx bytes
1080+ //
1081+ // NB: always keep this as the first tx check,
1082+ // as it is a pretty cheap one
1083+ if !validate_tx_bytes ( & self . wl_storage , tx_bytes. len ( ) )
1084+ . expect ( "Failed to get max tx bytes param from storage" )
1085+ {
1086+ response. code = ErrorCodes :: TooLarge . into ( ) ;
1087+ response. log = format ! ( "{INVALID_MSG}: Tx too large" ) ;
1088+ return response;
1089+ }
1090+
10761091 // Tx format check
10771092 let tx = match Tx :: try_from ( tx_bytes) . map_err ( Error :: TxDecoding ) {
10781093 Ok ( t) => t,
@@ -2091,6 +2106,7 @@ mod test_utils {
20912106 . new_epoch ( BlockHeight ( 1 ) ) ;
20922107 // initialize parameter storage
20932108 let params = Parameters {
2109+ max_tx_bytes : 1024 * 1024 ,
20942110 epoch_duration : EpochDuration {
20952111 min_num_of_blocks : 1 ,
20962112 min_duration : DurationSecs ( 3600 ) ,
@@ -2945,4 +2961,57 @@ mod shell_tests {
29452961 ) ;
29462962 assert_eq ! ( result. code, ErrorCodes :: FeeError . into( ) ) ;
29472963 }
2964+
2965+ /// Test max tx bytes parameter in CheckTx
2966+ #[ test]
2967+ fn test_max_tx_bytes_check_tx ( ) {
2968+ let ( shell, _recv, _, _) = test_utils:: setup ( ) ;
2969+
2970+ let max_tx_bytes: u32 = {
2971+ let key = parameters:: storage:: get_max_tx_bytes_key ( ) ;
2972+ shell
2973+ . wl_storage
2974+ . read ( & key)
2975+ . expect ( "Failed to read from storage" )
2976+ . expect ( "Max tx bytes should have been written to storage" )
2977+ } ;
2978+
2979+ let new_tx = |size : u32 | {
2980+ let keypair = super :: test_utils:: gen_keypair ( ) ;
2981+ let mut wrapper =
2982+ Tx :: from_type ( TxType :: Wrapper ( Box :: new ( WrapperTx :: new (
2983+ Fee {
2984+ amount_per_gas_unit : 100 . into ( ) ,
2985+ token : shell. wl_storage . storage . native_token . clone ( ) ,
2986+ } ,
2987+ keypair. ref_to ( ) ,
2988+ Epoch ( 0 ) ,
2989+ GAS_LIMIT_MULTIPLIER . into ( ) ,
2990+ None ,
2991+ ) ) ) ) ;
2992+ wrapper. header . chain_id = shell. chain_id . clone ( ) ;
2993+ wrapper. set_code ( Code :: new ( "wasm_code" . as_bytes ( ) . to_owned ( ) ) ) ;
2994+ wrapper. set_data ( Data :: new ( vec ! [ 0 ; size as usize ] ) ) ;
2995+ wrapper. add_section ( Section :: Signature ( Signature :: new (
2996+ wrapper. sechashes ( ) ,
2997+ [ ( 0 , keypair) ] . into_iter ( ) . collect ( ) ,
2998+ None ,
2999+ ) ) ) ;
3000+ wrapper
3001+ } ;
3002+
3003+ // test a small tx
3004+ let result = shell. mempool_validate (
3005+ new_tx ( 50 ) . to_bytes ( ) . as_ref ( ) ,
3006+ MempoolTxType :: NewTransaction ,
3007+ ) ;
3008+ assert ! ( result. code != ErrorCodes :: TooLarge . into( ) ) ;
3009+
3010+ // max tx bytes + 1, on the other hand, is not
3011+ let result = shell. mempool_validate (
3012+ new_tx ( max_tx_bytes + 1 ) . to_bytes ( ) . as_ref ( ) ,
3013+ MempoolTxType :: NewTransaction ,
3014+ ) ;
3015+ assert_eq ! ( result. code, ErrorCodes :: TooLarge . into( ) ) ;
3016+ }
29483017}
0 commit comments