@@ -38,6 +38,7 @@ public partial class ApplicationEngine : ExecutionEngine
3838 {
3939 protected static readonly JumpTable DefaultJumpTable = ComposeDefaultJumpTable ( ) ;
4040 protected static readonly JumpTable NotEchidnaJumpTable = ComposeNotEchidnaJumpTable ( ) ;
41+ protected static readonly JumpTable NotGorgonJumpTable = ComposeNotGorgonJumpTable ( ) ;
4142
4243 /// <summary>
4344 /// The maximum cost that can be spent when a contract is executed in test mode.
@@ -270,11 +271,174 @@ private static JumpTable ComposeDefaultJumpTable()
270271
271272 public static JumpTable ComposeNotEchidnaJumpTable ( )
272273 {
273- var jumpTable = ComposeDefaultJumpTable ( ) ;
274- jumpTable [ OpCode . SUBSTR ] = VulnerableSubStr ;
275- return jumpTable ;
274+ var table = ComposeNotGorgonJumpTable ( ) ;
275+
276+ table [ OpCode . SUBSTR ] = VulnerableSubStr ;
277+
278+ return table ;
279+ }
280+
281+ public static JumpTable ComposeNotGorgonJumpTable ( )
282+ {
283+ var table = ComposeDefaultJumpTable ( ) ;
284+
285+ // Before https://github.com/neo-project/neo-vm/pull/543
286+ table [ OpCode . HASKEY ] = HasKey_Before543 ;
287+ table [ OpCode . PICKITEM ] = PickItem_Before543 ;
288+ table [ OpCode . SETITEM ] = SetItem_Before543 ;
289+ table [ OpCode . REMOVE ] = Remove_Before543 ;
290+
291+ return table ;
276292 }
277293
294+ private static void Remove_Before543 ( ExecutionEngine engine , Instruction instruction )
295+ {
296+ var key = engine . Pop < PrimitiveType > ( ) ;
297+ var x = engine . Pop ( ) ;
298+ switch ( x )
299+ {
300+ case VMArray array :
301+ var index = ( int ) key . GetInteger ( ) ;
302+ if ( index < 0 || index >= array . Count )
303+ throw new InvalidOperationException ( $ "The index of { nameof ( VMArray ) } is out of range, { index } /[0, { array . Count } ).") ;
304+ array . RemoveAt ( index ) ;
305+ break ;
306+ case Map map :
307+ map . Remove ( key ) ;
308+ break ;
309+ default :
310+ throw new InvalidOperationException ( $ "Invalid type for { instruction . OpCode } : { x . Type } ") ;
311+ }
312+ }
313+
314+ private static void SetItem_Before543 ( ExecutionEngine engine , Instruction instruction )
315+ {
316+ var value = engine . Pop ( ) ;
317+ if ( value is Struct s ) value = s . Clone ( engine . Limits ) ;
318+ var key = engine . Pop < PrimitiveType > ( ) ;
319+ var x = engine . Pop ( ) ;
320+ switch ( x )
321+ {
322+ case VMArray array :
323+ {
324+ var index = ( int ) key . GetInteger ( ) ;
325+ if ( index < 0 || index >= array . Count )
326+ throw new CatchableException ( $ "The index of { nameof ( VMArray ) } is out of range, { index } /[0, { array . Count } ).") ;
327+ array [ index ] = value ;
328+ break ;
329+ }
330+ case Map map :
331+ {
332+ map [ key ] = value ;
333+ break ;
334+ }
335+ case VM . Types . Buffer buffer :
336+ {
337+ var index = ( int ) key . GetInteger ( ) ;
338+ if ( index < 0 || index >= buffer . Size )
339+ throw new CatchableException ( $ "The index of { nameof ( Buffer ) } is out of range, { index } /[0, { buffer . Size } ).") ;
340+ if ( value is not PrimitiveType p )
341+ throw new InvalidOperationException ( $ "Only primitive type values can be set in { nameof ( Buffer ) } in { instruction . OpCode } .") ;
342+ var b = ( int ) p . GetInteger ( ) ;
343+ if ( b < sbyte . MinValue || b > byte . MaxValue )
344+ throw new InvalidOperationException ( $ "Overflow in { instruction . OpCode } , { b } is not a byte type.") ;
345+ buffer . InnerBuffer . Span [ index ] = ( byte ) b ;
346+ break ;
347+ }
348+ default :
349+ throw new InvalidOperationException ( $ "Invalid type for { instruction . OpCode } : { x . Type } ") ;
350+ }
351+ }
352+
353+ private static void PickItem_Before543 ( ExecutionEngine engine , Instruction instruction )
354+ {
355+ var key = engine . Pop < PrimitiveType > ( ) ;
356+ var x = engine . Pop ( ) ;
357+ switch ( x )
358+ {
359+ case VMArray array :
360+ {
361+ var index = ( int ) key . GetInteger ( ) ;
362+ if ( index < 0 || index >= array . Count )
363+ throw new CatchableException ( $ "The index of { nameof ( VMArray ) } is out of range, { index } /[0, { array . Count } ).") ;
364+ engine . Push ( array [ index ] ) ;
365+ break ;
366+ }
367+ case Map map :
368+ {
369+ if ( ! map . TryGetValue ( key , out var value ) )
370+ throw new CatchableException ( $ "Key { key } not found in { nameof ( Map ) } .") ;
371+ engine . Push ( value ) ;
372+ break ;
373+ }
374+ case PrimitiveType primitive :
375+ {
376+ var byteArray = primitive . GetSpan ( ) ;
377+ var index = ( int ) key . GetInteger ( ) ;
378+ if ( index < 0 || index >= byteArray . Length )
379+ throw new CatchableException ( $ "The index of { nameof ( PrimitiveType ) } is out of range, { index } /[0, { byteArray . Length } ).") ;
380+ engine . Push ( ( BigInteger ) byteArray [ index ] ) ;
381+ break ;
382+ }
383+ case Buffer buffer :
384+ {
385+ var index = ( int ) key . GetInteger ( ) ;
386+ if ( index < 0 || index >= buffer . Size )
387+ throw new CatchableException ( $ "The index of { nameof ( Buffer ) } is out of range, { index } /[0, { buffer . Size } ).") ;
388+ engine . Push ( ( BigInteger ) buffer . InnerBuffer . Span [ index ] ) ;
389+ break ;
390+ }
391+ default :
392+ throw new InvalidOperationException ( $ "Invalid type for { instruction . OpCode } : { x . Type } ") ;
393+ }
394+ }
395+
396+ private static void HasKey_Before543 ( ExecutionEngine engine , Instruction instruction )
397+ {
398+ var key = engine . Pop < PrimitiveType > ( ) ;
399+ var x = engine . Pop ( ) ;
400+ // Check the type of the top item and perform the corresponding action.
401+ switch ( x )
402+ {
403+ // For arrays, check if the index is within bounds and push the result onto the stack.
404+ case VMArray array :
405+ {
406+ var index = ( int ) key . GetInteger ( ) ;
407+ if ( index < 0 )
408+ throw new InvalidOperationException ( $ "The negative index { index } is invalid for OpCode { instruction . OpCode } .") ;
409+ engine . Push ( index < array . Count ) ;
410+ break ;
411+ }
412+ // For maps, check if the key exists and push the result onto the stack.
413+ case Map map :
414+ {
415+ engine . Push ( map . ContainsKey ( key ) ) ;
416+ break ;
417+ }
418+ // For buffers, check if the index is within bounds and push the result onto the stack.
419+ case VM . Types . Buffer buffer :
420+ {
421+ var index = ( int ) key . GetInteger ( ) ;
422+ if ( index < 0 )
423+ throw new InvalidOperationException ( $ "The negative index { index } is invalid for OpCode { instruction . OpCode } .") ;
424+ engine . Push ( index < buffer . Size ) ;
425+ break ;
426+ }
427+ // For byte strings, check if the index is within bounds and push the result onto the stack.
428+ case ByteString array :
429+ {
430+ var index = ( int ) key . GetInteger ( ) ;
431+ if ( index < 0 )
432+ throw new InvalidOperationException ( $ "The negative index { index } is invalid for OpCode { instruction . OpCode } .") ;
433+ engine . Push ( index < array . Size ) ;
434+ break ;
435+ }
436+ default :
437+ throw new InvalidOperationException ( $ "Invalid type for { instruction . OpCode } : { x . Type } ") ;
438+ }
439+ }
440+
441+
278442 protected static void OnCallT ( ExecutionEngine engine , Instruction instruction )
279443 {
280444 if ( engine is ApplicationEngine app )
@@ -495,7 +659,25 @@ public static ApplicationEngine Create(TriggerType trigger, IVerifiable? contain
495659 var index = persistingBlock ? . Index ?? NativeContract . Ledger . CurrentIndex ( snapshot ) ;
496660 settings ??= ProtocolSettings . Default ;
497661 // Adjust jump table according persistingBlock
498- var jumpTable = settings . IsHardforkEnabled ( Hardfork . HF_Echidna , index ) ? DefaultJumpTable : NotEchidnaJumpTable ;
662+
663+ JumpTable jumpTable ;
664+
665+ if ( settings . IsHardforkEnabled ( Hardfork . HF_Gorgon , index ) )
666+ {
667+ jumpTable = DefaultJumpTable ;
668+ }
669+ else
670+ {
671+ if ( ! settings . IsHardforkEnabled ( Hardfork . HF_Echidna , index ) )
672+ {
673+ jumpTable = NotEchidnaJumpTable ;
674+ }
675+ else
676+ {
677+ jumpTable = NotGorgonJumpTable ;
678+ }
679+ }
680+
499681 var engine = Provider ? . Create ( trigger , container , snapshot , persistingBlock , settings , gas , diagnostic , jumpTable )
500682 ?? new ApplicationEngine ( trigger , container , snapshot , persistingBlock , settings , gas , diagnostic , jumpTable ) ;
501683
0 commit comments