@@ -6,7 +6,7 @@ use alloy_sol_types::SolValue;
66use foundry_cheatcodes:: {
77 Broadcast , BroadcastableTransactions , CheatcodeInspectorStrategy ,
88 CheatcodeInspectorStrategyContext , CheatcodeInspectorStrategyRunner , CheatsConfig , CheatsCtxt ,
9- CommonCreateInput , Ecx , EvmCheatcodeInspectorStrategyRunner , Result ,
9+ CommonCreateInput , DynCheatcode , Ecx , EvmCheatcodeInspectorStrategyRunner , Result ,
1010 Vm :: {
1111 AccountAccessKind , chainIdCall, coinbaseCall, dealCall, etchCall, getNonce_0Call, loadCall,
1212 polkadot_0Call, polkadot_1Call, polkadotSkipCall, resetNonceCall,
@@ -318,8 +318,9 @@ impl CheatcodeInspectorStrategyRunner for PvmCheatcodeInspectorStrategyRunner {
318318 tracing:: info!( cheatcode = ?cheatcode. as_debug( ) , using_revive = ?using_revive) ;
319319 let dealCall { account, newBalance } = cheatcode. as_any ( ) . downcast_ref ( ) . unwrap ( ) ;
320320
321- ctx. externalities . set_balance ( * account, * newBalance) ;
322- cheatcode. dyn_apply ( ccx, executor)
321+ let clamped_balance = ctx. externalities . set_balance ( * account, * newBalance) ;
322+ let clamped_deal = dealCall { account : * account, newBalance : clamped_balance } ;
323+ clamped_deal. dyn_apply ( ccx, executor)
323324 }
324325 t if using_revive && is :: < setNonceCall > ( t) => {
325326 tracing:: info!( cheatcode = ?cheatcode. as_debug( ) , using_revive = ?using_revive) ;
@@ -354,29 +355,10 @@ impl CheatcodeInspectorStrategyRunner for PvmCheatcodeInspectorStrategyRunner {
354355 }
355356 t if using_revive && is :: < rollCall > ( t) => {
356357 let & rollCall { newHeight } = cheatcode. as_any ( ) . downcast_ref ( ) . unwrap ( ) ;
357- let new_block_number: u64 = newHeight. saturating_to ( ) ;
358-
359- // blockhash should be the same on both revive and revm sides, so fetch it before
360- // changing the block number.
361- let prev_new_height_hash = ccx
362- . ecx
363- . journaled_state
364- . database
365- . block_hash ( new_block_number. saturating_sub ( 1 ) )
366- . expect ( "Should not fail" ) ;
367- let new_height_hash = ccx
368- . ecx
369- . journaled_state
370- . database
371- . block_hash ( new_block_number)
372- . expect ( "Should not fail" ) ;
373- ctx. externalities . set_block_number (
374- newHeight,
375- prev_new_height_hash,
376- new_height_hash,
377- ) ;
358+ let clamped_height =
359+ ctx. externalities . roll ( newHeight, & mut * ccx. ecx . journaled_state . database ) ;
378360
379- cheatcode . dyn_apply ( ccx, executor)
361+ rollCall { newHeight : clamped_height } . dyn_apply ( ccx, executor)
380362 }
381363 t if using_revive && is :: < snapshotStateCall > ( t) => {
382364 ctx. externalities . start_snapshotting ( ) ;
@@ -398,10 +380,9 @@ impl CheatcodeInspectorStrategyRunner for PvmCheatcodeInspectorStrategyRunner {
398380 t if using_revive && is :: < warpCall > ( t) => {
399381 let & warpCall { newTimestamp } = cheatcode. as_any ( ) . downcast_ref ( ) . unwrap ( ) ;
400382
401- tracing:: info!( cheatcode = ?cheatcode. as_debug( ) , using_revive = ?using_revive) ;
402- ctx. externalities . set_timestamp ( newTimestamp) ;
383+ let clamped_timestamp = ctx. externalities . set_timestamp ( newTimestamp) ;
403384
404- cheatcode . dyn_apply ( ccx, executor)
385+ warpCall { newTimestamp : clamped_timestamp } . dyn_apply ( ccx, executor)
405386 }
406387
407388 t if using_revive && is :: < chainIdCall > ( t) => {
@@ -425,19 +406,30 @@ impl CheatcodeInspectorStrategyRunner for PvmCheatcodeInspectorStrategyRunner {
425406 cheatcode. as_any ( ) . downcast_ref ( ) . unwrap ( ) ;
426407
427408 tracing:: info!( cheatcode = ?cheatcode. as_debug( ) , using_revive = ?using_revive) ;
409+ let u64_max: U256 = U256 :: from ( u64:: MAX ) ;
410+ let clamped_block_number = if blockNumber > u64_max {
411+ tracing:: warn!(
412+ blockNumber = ?blockNumber,
413+ max = ?u64_max,
414+ "Block number exceeds u64::MAX. Clamping to u64::MAX."
415+ ) ;
416+ u64_max
417+ } else {
418+ blockNumber
419+ } ;
428420
429421 // Validate blockNumber is not in the future
430422 let current_block = ctx. externalities . get_block_number ( ) ;
431- if blockNumber > current_block {
423+ if clamped_block_number > current_block {
432424 return Err ( foundry_cheatcodes:: Error :: from (
433425 "block number must be less than or equal to the current block number" ,
434426 ) ) ;
435427 }
436428
437- let block_num_u64 = blockNumber. to :: < u64 > ( ) ;
438- ctx. externalities . set_blockhash ( block_num_u64, blockHash) ;
429+ ctx. externalities . set_blockhash ( clamped_block_number. to ( ) , blockHash) ;
439430
440- cheatcode. dyn_apply ( ccx, executor)
431+ setBlockhashCall { blockNumber : clamped_block_number, blockHash }
432+ . dyn_apply ( ccx, executor)
441433 }
442434 t if using_revive && is :: < etchCall > ( t) => {
443435 let etchCall { target, newRuntimeBytecode } =
@@ -669,15 +661,15 @@ fn select_revive(
669661
670662 let block_number = data. block . number ;
671663 let timestamp = data. block . timestamp ;
664+ ctx. externalities . set_timestamp ( timestamp) ;
665+ ctx. externalities . roll ( block_number, & mut * data. journaled_state . database ) ;
672666
673667 ctx. externalities . execute_with ( ||{
674668 // Enable debug mode to bypass EIP-170 size checks during testing
675669 if data. cfg . limit_contract_code_size == Some ( usize:: MAX ) {
676670 let debug_settings = DebugSettings :: new ( true , true , true ) ;
677671 debug_settings. write_to_storage :: < Runtime > ( ) ;
678672 }
679- System :: set_block_number ( block_number. saturating_to ( ) ) ;
680- Timestamp :: set_timestamp ( timestamp. saturating_to :: < u64 > ( ) * 1000 ) ;
681673 <revive_env:: Runtime as polkadot_sdk:: pallet_revive:: Config >:: ChainId :: set (
682674 & data. cfg . chain_id ,
683675 ) ;
@@ -703,7 +695,22 @@ fn select_revive(
703695 let account = H160 :: from_slice ( address. as_slice ( ) ) ;
704696 let account_id =
705697 AccountId32Mapper :: < Runtime > :: to_fallback_account_id ( & account) ;
706- let amount_pvm = sp_core:: U256 :: from_little_endian ( & amount. as_le_bytes ( ) ) . min ( u128:: MAX . into ( ) ) ;
698+
699+ let u128_max: U256 = U256 :: from ( u128:: MAX ) ;
700+ let clamped_amount = if amount > u128_max {
701+ tracing:: info!(
702+ address = ?address,
703+ requested = ?amount,
704+ actual = ?u128_max,
705+ "Migration: balance exceeds u128::MAX, clamping to u128::MAX. \
706+ pallet-revive uses u128 for balances."
707+ ) ;
708+ u128_max
709+ } else {
710+ amount
711+ } ;
712+
713+ let amount_pvm = sp_core:: U256 :: from_little_endian ( & clamped_amount. as_le_bytes ( ) ) ;
707714 Pallet :: < Runtime > :: set_evm_balance ( & account, amount_pvm)
708715 . expect ( "failed to set evm balance" ) ;
709716
@@ -1045,6 +1052,30 @@ impl foundry_cheatcodes::CheatcodeInspectorStrategyExt for PvmCheatcodeInspector
10451052 }
10461053 } ;
10471054
1055+ let u128_max: U256 = U256 :: from ( u128:: MAX ) ;
1056+ if input. value ( ) > u128_max {
1057+ tracing:: warn!(
1058+ caller = ?input. caller( ) ,
1059+ value = ?input. value( ) ,
1060+ max = ?u128_max,
1061+ "Create value exceeds u128::MAX. pallet-revive uses u128 for balances."
1062+ ) ;
1063+ return Some ( CreateOutcome {
1064+ result : InterpreterResult {
1065+ result : InstructionResult :: Revert ,
1066+ output : Bytes :: from_iter (
1067+ format ! (
1068+ "Create value {} exceeds u128::MAX ({}). pallet-revive uses u128 for balances." ,
1069+ input. value( ) ,
1070+ u128 :: MAX
1071+ ) . as_bytes ( ) ,
1072+ ) ,
1073+ gas : Gas :: new ( input. gas_limit ( ) ) ,
1074+ } ,
1075+ address : None ,
1076+ } ) ;
1077+ }
1078+
10481079 let gas_price_pvm =
10491080 sp_core:: U256 :: from_little_endian ( & U256 :: from ( ecx. tx . gas_price ) . as_le_bytes ( ) ) ;
10501081 let mut tracer = Tracer :: new ( state. expected_calls . clone ( ) , state. expected_creates . clone ( ) ) ;
@@ -1217,6 +1248,32 @@ impl foundry_cheatcodes::CheatcodeInspectorStrategyExt for PvmCheatcodeInspector
12171248
12181249 tracing:: info!( "running call on pallet-revive with {} {:#?}" , ctx. runtime_mode, call) ;
12191250
1251+ let u128_max: U256 = U256 :: from ( u128:: MAX ) ;
1252+ let call_value = call. call_value ( ) ;
1253+ if call_value > u128_max {
1254+ tracing:: warn!(
1255+ caller = ?call. caller,
1256+ target = ?call. target_address,
1257+ value = ?call_value,
1258+ max = ?u128_max,
1259+ "Call value exceeds u128::MAX. pallet-revive uses u128 for balances."
1260+ ) ;
1261+ return Some ( CallOutcome {
1262+ result : InterpreterResult {
1263+ result : InstructionResult :: Revert ,
1264+ output : Bytes :: from_iter (
1265+ format ! (
1266+ "Call value {} exceeds u128::MAX ({}). pallet-revive uses u128 for balances." ,
1267+ call_value,
1268+ u128 :: MAX
1269+ ) . as_bytes ( ) ,
1270+ ) ,
1271+ gas : Gas :: new ( call. gas_limit ) ,
1272+ } ,
1273+ memory_offset : call. return_memory_offset . clone ( ) ,
1274+ } ) ;
1275+ }
1276+
12201277 let gas_price_pvm =
12211278 sp_core:: U256 :: from_little_endian ( & U256 :: from ( ecx. tx . gas_price ) . as_le_bytes ( ) ) ;
12221279 let mock_handler = MockHandlerImpl :: new (
0 commit comments