@@ -753,3 +753,84 @@ fn catch_constructor_test() {
753753 assert_eq ! ( "revert: invalid address" , gas_trace. calls[ 0 ] . revert_reason. as_ref( ) . unwrap( ) ) ;
754754 } ) ;
755755}
756+
757+ /// Regression test for proxy contract delegatecall with large deposit limits.
758+ ///
759+ /// When deposit_left is very large (u128::MAX in production), remaining_gas becomes huge,
760+ /// causing ratio = gas_limit / remaining_gas ≈ 0. This resulted in nested calls receiving
761+ /// almost no weight. The fix caps remaining_gas to u64::MAX since Ethereum gas is u64.
762+ ///
763+ /// Note: This test uses Balance = u64, so the bug doesn't fully manifest here.
764+ /// The fix is a no-op in u64 configs but critical for u128 production configs.
765+ #[ test]
766+ fn substrate_nesting_with_large_deposit_and_max_gas_request ( ) {
767+ use super :: math:: substrate_execution;
768+
769+ ExtBuilder :: default ( )
770+ . with_next_fee_multiplier ( FixedU128 :: from_rational ( 1 , 5 ) )
771+ . build ( )
772+ . execute_with ( || {
773+ let weight_limit = Weight :: from_parts ( 1_000_000_000 , 10_000 ) ;
774+ let deposit_limit = u64:: MAX ;
775+
776+ let mut root_meter =
777+ substrate_execution:: new_root :: < Test > ( weight_limit, deposit_limit) . unwrap ( ) ;
778+
779+ root_meter. charge_weight_token ( TestToken ( 1000 , 100 ) ) . unwrap ( ) ;
780+ root_meter. charge_deposit ( & StorageDeposit :: Charge ( 1000 ) ) . unwrap ( ) ;
781+
782+ let weight_left_before = root_meter. weight_left ( ) . unwrap ( ) ;
783+
784+ let gas_scale: u64 = <Test as Config >:: GasScale :: get ( ) . into ( ) ;
785+ let max_eth_gas = u64:: MAX / gas_scale;
786+
787+ let nested = root_meter
788+ . new_nested ( & CallResources :: Ethereum { gas : max_eth_gas, add_stipend : false } )
789+ . unwrap ( ) ;
790+
791+ let nested_weight_left = nested. weight_left ( ) . unwrap ( ) ;
792+
793+ assert ! (
794+ nested_weight_left. ref_time( ) >= weight_left_before. ref_time( ) / 2 ,
795+ "Nested meter should get at least 50% of remaining weight. \
796+ Got ref_time: {}, expected at least: {}",
797+ nested_weight_left. ref_time( ) ,
798+ weight_left_before. ref_time( ) / 2
799+ ) ;
800+
801+ assert ! ( nested. deposit_left( ) . unwrap( ) > 0 ) ;
802+ } ) ;
803+ }
804+
805+ /// Test ratio-based weight scaling for partial gas requests in substrate execution.
806+ #[ test]
807+ fn substrate_nesting_with_partial_gas_request_scales_weight ( ) {
808+ use super :: math:: substrate_execution;
809+
810+ ExtBuilder :: default ( )
811+ . with_next_fee_multiplier ( FixedU128 :: from_rational ( 1 , 5 ) )
812+ . build ( )
813+ . execute_with ( || {
814+ let weight_limit = Weight :: from_parts ( 1_000_000_000 , 10_000 ) ;
815+ let deposit_limit = 1_000_000_000u64 ;
816+
817+ let mut root_meter =
818+ substrate_execution:: new_root :: < Test > ( weight_limit, deposit_limit) . unwrap ( ) ;
819+
820+ root_meter. charge_weight_token ( TestToken ( 1000 , 100 ) ) . unwrap ( ) ;
821+
822+ let weight_left_before = root_meter. weight_left ( ) . unwrap ( ) ;
823+
824+ let gas_scale: u64 = <Test as Config >:: GasScale :: get ( ) . into ( ) ;
825+ let partial_gas = ( u64:: MAX / gas_scale) / 10 ;
826+
827+ let nested = root_meter
828+ . new_nested ( & CallResources :: Ethereum { gas : partial_gas, add_stipend : false } )
829+ . unwrap ( ) ;
830+
831+ let nested_weight_left = nested. weight_left ( ) . unwrap ( ) ;
832+
833+ assert ! ( nested_weight_left. ref_time( ) > 0 ) ;
834+ assert ! ( nested_weight_left. ref_time( ) <= weight_left_before. ref_time( ) ) ;
835+ } ) ;
836+ }
0 commit comments