@@ -20,6 +20,54 @@ namespace Neo.UnitTests.SmartContract
2020{
2121 public partial class UT_ApplicationEngine
2222 {
23+ [ TestMethod ]
24+ public void TestSHR_SHL_WithDifferentHF ( )
25+ {
26+ foreach ( var op in new OpCode [ ] { OpCode . SHL , OpCode . SHR } )
27+ {
28+ using var sb = new ScriptBuilder ( ) ;
29+
30+ sb . Emit ( OpCode . NEWARRAY0 ) ; // intentionally wrong argument for SHL or SHR.
31+ sb . EmitPush ( 0 ) ; // zero shift.
32+ sb . Emit ( op ) ;
33+
34+ var script = sb . ToArray ( ) ;
35+
36+ const uint EchidnaEnable = 10u ;
37+ const uint GorgonEnable = 20u ;
38+ // Hardfork heights:
39+ // Echidna at 10, Gorgon at 20
40+ // - index=5 => pre-Echidna (NotEchidnaJumpTable)
41+ // - index=15 => Echidna enabled, Gorgon NOT enabled (NotGorgonJumpTable)
42+ // - index=30 => Gorgon enabled (DefaultJumpTable)
43+ var settings = ProtocolSettings . Default with
44+ {
45+ Hardforks = ProtocolSettings . Default . Hardforks
46+ . SetItem ( Hardfork . HF_Echidna , EchidnaEnable )
47+ . SetItem ( Hardfork . HF_Gorgon , GorgonEnable )
48+ } ;
49+
50+ Assert . IsFalse ( settings . IsHardforkEnabled ( Hardfork . HF_Echidna , 5u ) ) ;
51+ Assert . IsTrue ( settings . IsHardforkEnabled ( Hardfork . HF_Echidna , 15u ) ) ;
52+ Assert . IsTrue ( settings . IsHardforkEnabled ( Hardfork . HF_Echidna , 30u ) ) ;
53+ Assert . IsFalse ( settings . IsHardforkEnabled ( Hardfork . HF_Gorgon , 15u ) ) ;
54+ Assert . IsTrue ( settings . IsHardforkEnabled ( Hardfork . HF_Gorgon , 30u ) ) ;
55+
56+ // Case A: pre-Echidna => no exception.
57+ var engine = Execute ( script , settings , index : 5u ) ;
58+ Assert . AreEqual ( VMState . HALT , engine . State ) ;
59+ Assert . AreEqual ( 1 , engine . ResultStack . Count ) ;
60+
61+ // Case B: Echidna enabled but pre-Gorgon => no exception.
62+ engine = Execute ( script , settings , index : 15u ) ;
63+ Assert . AreEqual ( VMState . HALT , engine . State ) ;
64+ Assert . AreEqual ( 1 , engine . ResultStack . Count ) ;
65+
66+ // Case C: Gorgon enabled => InvalidCastException on attempt to convert Array to Integer.
67+ ExecuteAndAssertFault < InvalidCastException > ( script , settings , index : 30u ) ;
68+ }
69+ }
70+
2371 [ TestMethod ]
2472 public void TestHasKeyWithDifferentHF ( )
2573 {
@@ -76,6 +124,16 @@ private static byte[] BuildHasKeyLargeIndexScript()
76124 }
77125
78126 private static void ExecuteAndAssertFault < TException > ( byte [ ] script , ProtocolSettings settings , uint index ) where TException : Exception
127+ {
128+ var engine = Execute ( script , settings , index ) ;
129+
130+ Assert . AreEqual ( VMState . FAULT , engine . State , $ "Expected FAULT at index={ index } .") ;
131+ Assert . IsNotNull ( engine . FaultException , $ "Expected FaultException at index={ index } .") ;
132+ Assert . IsInstanceOfType ( engine . FaultException , typeof ( TException ) ,
133+ $ "Expected { typeof ( TException ) . Name } at index={ index } , but got { engine . FaultException . GetType ( ) . Name } .") ;
134+ }
135+
136+ private static ApplicationEngine Execute ( byte [ ] script , ProtocolSettings settings , uint index )
79137 {
80138 var snapshotCache = TestBlockchain . GetTestSnapshotCache ( ) ;
81139 var block = new Block
@@ -102,10 +160,7 @@ private static void ExecuteAndAssertFault<TException>(byte[] script, ProtocolSet
102160 engine . LoadScript ( script ) ;
103161 engine . Execute ( ) ;
104162
105- Assert . AreEqual ( VMState . FAULT , engine . State , $ "Expected FAULT at index={ index } .") ;
106- Assert . IsNotNull ( engine . FaultException , $ "Expected FaultException at index={ index } .") ;
107- Assert . IsInstanceOfType ( engine . FaultException , typeof ( TException ) ,
108- $ "Expected { typeof ( TException ) . Name } at index={ index } , but got { engine . FaultException . GetType ( ) . Name } .") ;
163+ return engine ;
109164 }
110165 }
111166}
0 commit comments