@@ -34,7 +34,6 @@ pub fn push<const N: usize, WIRE: InterpreterTypes, H: ?Sized>(
3434 return ;
3535 }
3636
37- // Can ignore return. as relative N jump is safe operation
3837 context. interpreter . bytecode . relative_jump ( N as isize ) ;
3938}
4039
@@ -60,3 +59,173 @@ pub fn swap<const N: usize, WIRE: InterpreterTypes, H: ?Sized>(
6059 context. interpreter . halt ( InstructionResult :: StackOverflow ) ;
6160 }
6261}
62+
63+ /// Implements the DUPN instruction.
64+ ///
65+ /// Duplicates the Nth stack item to the top of the stack, with N given by an immediate.
66+ pub fn dupn < WIRE : InterpreterTypes , H : ?Sized > (
67+ context : InstructionContext < ' _ , H , WIRE > ,
68+ ) {
69+ check ! ( context. interpreter, AMSTERDAM ) ;
70+ let x: usize = context. interpreter . bytecode . read_u8 ( ) . into ( ) ;
71+ if let Some ( n) = decode_single ( x) {
72+ if !context. interpreter . stack . dup ( n) {
73+ context. interpreter . halt ( InstructionResult :: StackOverflow ) ;
74+ }
75+ context. interpreter . bytecode . relative_jump ( 1 ) ;
76+ } else {
77+ context. interpreter . halt ( InstructionResult :: InvalidImmediateEncoding ) ;
78+ }
79+ }
80+
81+ /// Implements the SWAPN instruction.
82+ ///
83+ /// Swaps the top stack item with the N+1th stack item, with N given by an immediate.
84+ pub fn swapn < WIRE : InterpreterTypes , H : ?Sized > (
85+ context : InstructionContext < ' _ , H , WIRE > ,
86+ ) {
87+ check ! ( context. interpreter, AMSTERDAM ) ;
88+ let x: usize = context. interpreter . bytecode . read_u8 ( ) . into ( ) ;
89+ if let Some ( n) = decode_single ( x) {
90+ if !context. interpreter . stack . exchange ( 0 , n) {
91+ context. interpreter . halt ( InstructionResult :: StackOverflow ) ;
92+ }
93+ context. interpreter . bytecode . relative_jump ( 1 ) ;
94+ } else {
95+ context. interpreter . halt ( InstructionResult :: InvalidImmediateEncoding ) ;
96+ }
97+ }
98+
99+ /// Implements the EXCHANGE instruction.
100+ ///
101+ /// Swaps the N+1th stack item with the M+1th stack item, with N, M given by an immediate.
102+ pub fn exchange < WIRE : InterpreterTypes , H : ?Sized > (
103+ context : InstructionContext < ' _ , H , WIRE > ,
104+ ) {
105+ check ! ( context. interpreter, AMSTERDAM ) ;
106+ let x: usize = context. interpreter . bytecode . read_u8 ( ) . into ( ) ;
107+ if let Some ( ( n, m) ) = decode_pair ( x) {
108+ if !context. interpreter . stack . exchange ( n, m - n) {
109+ context. interpreter . halt ( InstructionResult :: StackOverflow ) ;
110+ }
111+ context. interpreter . bytecode . relative_jump ( 1 ) ;
112+ } else {
113+ context. interpreter . halt ( InstructionResult :: InvalidImmediateEncoding ) ;
114+ }
115+ }
116+
117+ fn decode_single ( x : usize ) -> Option < usize > {
118+ if x <= 90 {
119+ Some ( x + 17 )
120+ } else if x >= 128 {
121+ Some ( x - 20 )
122+ } else {
123+ None
124+ }
125+ }
126+
127+ fn decode_pair ( x : usize ) -> Option < ( usize , usize ) > {
128+ let k = if x <= 79 {
129+ x
130+ } else if x >= 128 {
131+ x - 48
132+ } else {
133+ return None ;
134+ } ;
135+ let q = k / 16 ;
136+ let r = k % 16 ;
137+ if q < r {
138+ Some ( ( q + 1 , r + 1 ) )
139+ } else {
140+ Some ( ( r + 1 , 29 - q) )
141+ }
142+ }
143+
144+ #[ cfg( test) ]
145+ mod tests {
146+ use crate :: {
147+ gas:: params:: GasParams , host:: DummyHost , instructions:: instruction_table, interpreter:: { EthInterpreter , ExtBytecode , InputsImpl , SharedMemory } , interpreter_types:: LoopControl , Interpreter
148+ } ;
149+ use bytecode:: Bytecode ;
150+ use primitives:: { hardfork:: SpecId , Bytes , U256 } ;
151+
152+ fn run_bytecode ( code : & [ u8 ] ) -> Interpreter {
153+ let bytecode = Bytecode :: new_raw ( Bytes :: copy_from_slice ( code) ) ;
154+ let mut interpreter = Interpreter :: < EthInterpreter > :: new (
155+ SharedMemory :: new ( ) ,
156+ ExtBytecode :: new ( bytecode) ,
157+ InputsImpl :: default ( ) ,
158+ false ,
159+ SpecId :: OSAKA ,
160+ u64:: MAX ,
161+ GasParams :: default ( ) ,
162+ ) ;
163+ let table = instruction_table :: < EthInterpreter , DummyHost > ( ) ;
164+ let mut host = DummyHost ;
165+ interpreter. run_plain ( & table, & mut host) ;
166+ interpreter
167+ }
168+
169+ #[ test]
170+ fn test_dupn ( ) {
171+ let interpreter = run_bytecode ( & [
172+ 0x60 , 0x01 , 0x60 , 0x00 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 ,
173+ 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0xe6 , 0x00 ,
174+ ] ) ;
175+ assert_eq ! ( interpreter. stack. len( ) , 18 ) ;
176+ assert_eq ! ( interpreter. stack. data( ) [ 17 ] , U256 :: from( 1 ) ) ;
177+ assert_eq ! ( interpreter. stack. data( ) [ 0 ] , U256 :: from( 1 ) ) ;
178+ for i in 1 ..17 {
179+ assert_eq ! ( interpreter. stack. data( ) [ i] , U256 :: ZERO ) ;
180+ }
181+ }
182+
183+ #[ test]
184+ fn test_swapn ( ) {
185+ let interpreter = run_bytecode ( & [
186+ 0x60 , 0x01 , 0x60 , 0x00 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x80 ,
187+ 0x80 , 0x80 , 0x80 , 0x80 , 0x80 , 0x60 , 0x02 , 0xe7 , 0x00 ,
188+ ] ) ;
189+ assert_eq ! ( interpreter. stack. len( ) , 18 ) ;
190+ assert_eq ! ( interpreter. stack. data( ) [ 17 ] , U256 :: from( 1 ) ) ;
191+ assert_eq ! ( interpreter. stack. data( ) [ 0 ] , U256 :: from( 2 ) ) ;
192+ for i in 1 ..17 {
193+ assert_eq ! ( interpreter. stack. data( ) [ i] , U256 :: ZERO ) ;
194+ }
195+ }
196+
197+ #[ test]
198+ fn test_exchange ( ) {
199+ let interpreter = run_bytecode ( & [ 0x60 , 0x00 , 0x60 , 0x01 , 0x60 , 0x02 , 0xe8 , 0x01 ] ) ;
200+ assert_eq ! ( interpreter. stack. len( ) , 3 ) ;
201+ assert_eq ! ( interpreter. stack. data( ) [ 2 ] , U256 :: from( 2 ) ) ;
202+ assert_eq ! ( interpreter. stack. data( ) [ 1 ] , U256 :: from( 0 ) ) ;
203+ assert_eq ! ( interpreter. stack. data( ) [ 0 ] , U256 :: from( 1 ) ) ;
204+ }
205+
206+ #[ test]
207+ fn test_swapn_invalid_immediate ( ) {
208+ let mut interpreter = run_bytecode ( & [ 0xe7 , 0x5b ] ) ;
209+ assert ! ( interpreter
210+ . bytecode
211+ . instruction_result( )
212+ . is_none( ) ) ;
213+ }
214+
215+ #[ test]
216+ fn test_jump_over_invalid_dupn ( ) {
217+ let interpreter = run_bytecode ( & [ 0x60 , 0x04 , 0x56 , 0xe6 , 0x5b ] ) ;
218+ assert ! ( interpreter
219+ . bytecode
220+ . is_not_end( ) ) ;
221+ }
222+
223+ #[ test]
224+ fn test_exchange_with_iszero ( ) {
225+ let interpreter = run_bytecode ( & [ 0x60 , 0x00 , 0x60 , 0x00 , 0x60 , 0x00 , 0xe8 , 0x01 , 0x15 ] ) ;
226+ assert_eq ! ( interpreter. stack. len( ) , 3 ) ;
227+ assert_eq ! ( interpreter. stack. data( ) [ 2 ] , U256 :: from( 1 ) ) ;
228+ assert_eq ! ( interpreter. stack. data( ) [ 1 ] , U256 :: ZERO ) ;
229+ assert_eq ! ( interpreter. stack. data( ) [ 0 ] , U256 :: ZERO ) ;
230+ }
231+ }
0 commit comments