@@ -61,6 +61,10 @@ const TWO_POW_96: U256 = U256([0, 0x100000000, 0, 0]); //0x1 00000000 00000000 0
6161const TWO_POW_224 : U256 = U256 ( [ 0 , 0 , 0 , 0x100000000 ] ) ; //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
6262const TWO_POW_248 : U256 = U256 ( [ 0 , 0 , 0 , 0x100000000000000 ] ) ; //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000
6363
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+
6468fn to_biguint ( x : U256 ) -> BigUint {
6569 let mut bytes = [ 0u8 ; 32 ] ;
6670 x. to_little_endian ( & mut bytes) ;
@@ -101,6 +105,8 @@ enum InstructionResult<Gas> {
101105 Ok ,
102106 UnusedGas ( Gas ) ,
103107 JumpToPosition ( U256 ) ,
108+ JumpToSubroutine ( U256 ) ,
109+ ReturnFromSubroutine ( usize ) ,
104110 StopExecutionNeedsReturn {
105111 /// Gas left.
106112 gas : Gas ,
@@ -183,8 +189,10 @@ pub struct Interpreter<Cost: CostType> {
183189 do_trace : bool ,
184190 done : bool ,
185191 valid_jump_destinations : Option < Arc < BitSet > > ,
192+ valid_subroutine_destinations : Option < Arc < BitSet > > ,
186193 gasometer : Option < Gasometer < Cost > > ,
187194 stack : VecStack < U256 > ,
195+ return_stack : Vec < usize > ,
188196 resume_output_range : Option < ( U256 , U256 ) > ,
189197 resume_result : Option < InstructionResult < Cost > > ,
190198 last_stack_ret_len : usize ,
@@ -290,19 +298,23 @@ impl<Cost: CostType> Interpreter<Cost> {
290298 let params = InterpreterParams :: from ( params) ;
291299 let informant = informant:: EvmInformant :: new ( depth) ;
292300 let valid_jump_destinations = None ;
301+ let valid_subroutine_destinations = None ;
293302 let gasometer = Cost :: from_u256 ( params. gas )
294303 . ok ( )
295304 . map ( |gas| Gasometer :: < Cost > :: new ( gas) ) ;
296305 let stack = VecStack :: with_capacity ( schedule. stack_limit , U256 :: zero ( ) ) ;
306+ let return_stack = Vec :: with_capacity ( MAX_SUB_STACK_SIZE ) ;
297307
298308 Interpreter {
299309 cache,
300310 params,
301311 reader,
302312 informant,
303313 valid_jump_destinations,
314+ valid_subroutine_destinations,
304315 gasometer,
305316 stack,
317+ return_stack,
306318 done : false ,
307319 // Overridden in `step_inner` based on
308320 // the result of `ext.trace_next_instruction`.
@@ -478,7 +490,8 @@ impl<Cost: CostType> Interpreter<Cost> {
478490 if self . valid_jump_destinations . is_none ( ) {
479491 self . valid_jump_destinations = Some (
480492 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 ,
482495 ) ;
483496 }
484497 let jump_destinations = self
@@ -491,6 +504,28 @@ impl<Cost: CostType> Interpreter<Cost> {
491504 } ;
492505 self . reader . position = pos;
493506 }
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+ }
494529 InstructionResult :: StopExecutionNeedsReturn {
495530 gas,
496531 init_off,
@@ -537,20 +572,20 @@ impl<Cost: CostType> Interpreter<Cost> {
537572 ) -> vm:: Result < ( ) > {
538573 let schedule = ext. schedule ( ) ;
539574
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 )
545580 && !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 )
550583 && !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 )
554589 {
555590 return Err ( vm:: Error :: BadInstruction {
556591 instruction : instruction as u8 ,
@@ -623,6 +658,29 @@ impl<Cost: CostType> Interpreter<Cost> {
623658 instructions:: JUMPDEST => {
624659 // ignore
625660 }
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+ }
626684 instructions:: CREATE | instructions:: CREATE2 => {
627685 let endowment = self . stack . pop_back ( ) ;
628686 let init_off = self . stack . pop_back ( ) ;
@@ -1413,6 +1471,7 @@ impl<Cost: CostType> Interpreter<Cost> {
14131471 if valid_jump_destinations. contains ( jump) && U256 :: from ( jump) == jump_u {
14141472 Ok ( jump)
14151473 } else {
1474+ // Note: if jump > usize, BadJumpDestination value is trimmed
14161475 Err ( vm:: Error :: BadJumpDestination { destination : jump } )
14171476 }
14181477 }
0 commit comments