@@ -61,6 +61,10 @@ const TWO_POW_96: U256 = U256([0, 0x100000000, 0, 0]); //0x1 00000000 00000000 0
61
61
const TWO_POW_224 : U256 = U256 ( [ 0 , 0 , 0 , 0x100000000 ] ) ; //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
62
62
const TWO_POW_248 : U256 = U256 ( [ 0 , 0 , 0 , 0x100000000000000 ] ) ; //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000
63
63
64
+ /// Maximum subroutine stack size as specified in
65
+ /// https://eips.ethereum.org/EIPS/eip-2315.
66
+ pub const MAX_SUB_STACK_SIZE : usize = 1023 ;
67
+
64
68
fn to_biguint ( x : U256 ) -> BigUint {
65
69
let mut bytes = [ 0u8 ; 32 ] ;
66
70
x. to_little_endian ( & mut bytes) ;
@@ -101,6 +105,8 @@ enum InstructionResult<Gas> {
101
105
Ok ,
102
106
UnusedGas ( Gas ) ,
103
107
JumpToPosition ( U256 ) ,
108
+ JumpToSubroutine ( U256 ) ,
109
+ ReturnFromSubroutine ( usize ) ,
104
110
StopExecutionNeedsReturn {
105
111
/// Gas left.
106
112
gas : Gas ,
@@ -183,8 +189,10 @@ pub struct Interpreter<Cost: CostType> {
183
189
do_trace : bool ,
184
190
done : bool ,
185
191
valid_jump_destinations : Option < Arc < BitSet > > ,
192
+ valid_subroutine_destinations : Option < Arc < BitSet > > ,
186
193
gasometer : Option < Gasometer < Cost > > ,
187
194
stack : VecStack < U256 > ,
195
+ return_stack : Vec < usize > ,
188
196
resume_output_range : Option < ( U256 , U256 ) > ,
189
197
resume_result : Option < InstructionResult < Cost > > ,
190
198
last_stack_ret_len : usize ,
@@ -290,19 +298,23 @@ impl<Cost: CostType> Interpreter<Cost> {
290
298
let params = InterpreterParams :: from ( params) ;
291
299
let informant = informant:: EvmInformant :: new ( depth) ;
292
300
let valid_jump_destinations = None ;
301
+ let valid_subroutine_destinations = None ;
293
302
let gasometer = Cost :: from_u256 ( params. gas )
294
303
. ok ( )
295
304
. map ( |gas| Gasometer :: < Cost > :: new ( gas) ) ;
296
305
let stack = VecStack :: with_capacity ( schedule. stack_limit , U256 :: zero ( ) ) ;
306
+ let return_stack = Vec :: with_capacity ( MAX_SUB_STACK_SIZE ) ;
297
307
298
308
Interpreter {
299
309
cache,
300
310
params,
301
311
reader,
302
312
informant,
303
313
valid_jump_destinations,
314
+ valid_subroutine_destinations,
304
315
gasometer,
305
316
stack,
317
+ return_stack,
306
318
done : false ,
307
319
// Overridden in `step_inner` based on
308
320
// the result of `ext.trace_next_instruction`.
@@ -478,7 +490,8 @@ impl<Cost: CostType> Interpreter<Cost> {
478
490
if self . valid_jump_destinations . is_none ( ) {
479
491
self . valid_jump_destinations = Some (
480
492
self . cache
481
- . jump_destinations ( & self . params . code_hash , & self . reader . code ) ,
493
+ . jump_and_sub_destinations ( & self . params . code_hash , & self . reader . code )
494
+ . 0 ,
482
495
) ;
483
496
}
484
497
let jump_destinations = self
@@ -491,6 +504,28 @@ impl<Cost: CostType> Interpreter<Cost> {
491
504
} ;
492
505
self . reader . position = pos;
493
506
}
507
+ InstructionResult :: JumpToSubroutine ( position) => {
508
+ if self . valid_subroutine_destinations . is_none ( ) {
509
+ self . valid_subroutine_destinations = Some (
510
+ self . cache
511
+ . jump_and_sub_destinations ( & self . params . code_hash , & self . reader . code )
512
+ . 1 ,
513
+ ) ;
514
+ }
515
+ let subroutine_destinations = self
516
+ . valid_subroutine_destinations
517
+ . as_ref ( )
518
+ . expect ( "subroutine_destinations are initialized on first jump; qed" ) ;
519
+ let pos = match self . verify_jump ( position, subroutine_destinations) {
520
+ Ok ( x) => x,
521
+ Err ( e) => return InterpreterResult :: Done ( Err ( e) ) ,
522
+ } ;
523
+ self . return_stack . push ( self . reader . position ) ;
524
+ self . reader . position = pos + 1 ;
525
+ }
526
+ InstructionResult :: ReturnFromSubroutine ( pos) => {
527
+ self . reader . position = pos;
528
+ }
494
529
InstructionResult :: StopExecutionNeedsReturn {
495
530
gas,
496
531
init_off,
@@ -537,20 +572,20 @@ impl<Cost: CostType> Interpreter<Cost> {
537
572
) -> vm:: Result < ( ) > {
538
573
let schedule = ext. schedule ( ) ;
539
574
540
- if ( instruction == instructions:: DELEGATECALL && !schedule . have_delegate_call )
541
- || ( instruction == instructions :: CREATE2 && !schedule. have_create2 )
542
- || ( instruction == instructions :: STATICCALL && !schedule. have_static_call )
543
- || ( ( instruction == instructions :: RETURNDATACOPY
544
- || instruction == instructions :: RETURNDATASIZE )
575
+ use instructions:: * ;
576
+ if ( instruction == DELEGATECALL && !schedule. have_delegate_call )
577
+ || ( instruction == CREATE2 && !schedule. have_create2 )
578
+ || ( instruction == STATICCALL && !schedule . have_static_call )
579
+ || ( ( instruction == RETURNDATACOPY || instruction == RETURNDATASIZE )
545
580
&& !schedule. have_return_data )
546
- || ( instruction == instructions:: REVERT && !schedule. have_revert )
547
- || ( ( instruction == instructions:: SHL
548
- || instruction == instructions:: SHR
549
- || instruction == instructions:: SAR )
581
+ || ( instruction == REVERT && !schedule. have_revert )
582
+ || ( ( instruction == SHL || instruction == SHR || instruction == SAR )
550
583
&& !schedule. have_bitwise_shifting )
551
- || ( instruction == instructions:: EXTCODEHASH && !schedule. have_extcodehash )
552
- || ( instruction == instructions:: CHAINID && !schedule. have_chain_id )
553
- || ( instruction == instructions:: SELFBALANCE && !schedule. have_selfbalance )
584
+ || ( instruction == EXTCODEHASH && !schedule. have_extcodehash )
585
+ || ( instruction == CHAINID && !schedule. have_chain_id )
586
+ || ( instruction == SELFBALANCE && !schedule. have_selfbalance )
587
+ || ( ( instruction == BEGINSUB || instruction == JUMPSUB || instruction == RETURNSUB )
588
+ && !schedule. have_subs )
554
589
{
555
590
return Err ( vm:: Error :: BadInstruction {
556
591
instruction : instruction as u8 ,
@@ -623,6 +658,29 @@ impl<Cost: CostType> Interpreter<Cost> {
623
658
instructions:: JUMPDEST => {
624
659
// ignore
625
660
}
661
+ instructions:: BEGINSUB => {
662
+ return Err ( vm:: Error :: InvalidSubEntry ) ;
663
+ }
664
+ instructions:: JUMPSUB => {
665
+ if self . return_stack . len ( ) >= MAX_SUB_STACK_SIZE {
666
+ return Err ( vm:: Error :: OutOfSubStack {
667
+ wanted : 1 ,
668
+ limit : MAX_SUB_STACK_SIZE ,
669
+ } ) ;
670
+ }
671
+ let sub_destination = self . stack . pop_back ( ) ;
672
+ return Ok ( InstructionResult :: JumpToSubroutine ( sub_destination) ) ;
673
+ }
674
+ instructions:: RETURNSUB => {
675
+ if let Some ( pos) = self . return_stack . pop ( ) {
676
+ return Ok ( InstructionResult :: ReturnFromSubroutine ( pos) ) ;
677
+ } else {
678
+ return Err ( vm:: Error :: SubStackUnderflow {
679
+ wanted : 1 ,
680
+ on_stack : 0 ,
681
+ } ) ;
682
+ }
683
+ }
626
684
instructions:: CREATE | instructions:: CREATE2 => {
627
685
let endowment = self . stack . pop_back ( ) ;
628
686
let init_off = self . stack . pop_back ( ) ;
@@ -1413,6 +1471,7 @@ impl<Cost: CostType> Interpreter<Cost> {
1413
1471
if valid_jump_destinations. contains ( jump) && U256 :: from ( jump) == jump_u {
1414
1472
Ok ( jump)
1415
1473
} else {
1474
+ // Note: if jump > usize, BadJumpDestination value is trimmed
1416
1475
Err ( vm:: Error :: BadJumpDestination { destination : jump } )
1417
1476
}
1418
1477
}
0 commit comments