diff --git a/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs b/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs new file mode 100644 index 0000000000..dd7df7d3d1 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs @@ -0,0 +1,101 @@ +using System.Diagnostics; + +namespace Neo.VM +{ + public static class Benchmarks + { + public static void NeoIssue2528() + { + // https://github.com/neo-project/neo/issues/2528 + // L01: INITSLOT 1, 0 + // L02: NEWARRAY0 + // L03: DUP + // L04: DUP + // L05: PUSHINT16 2043 + // L06: STLOC 0 + // L07: PUSH1 + // L08: PACK + // L09: LDLOC 0 + // L10: DEC + // L11: STLOC 0 + // L12: LDLOC 0 + // L13: JMPIF_L L07 + // L14: PUSH1 + // L15: PACK + // L16: APPEND + // L17: PUSHINT32 38000 + // L18: STLOC 0 + // L19: PUSH0 + // L20: PICKITEM + // L21: LDLOC 0 + // L22: DEC + // L23: STLOC 0 + // L24: LDLOC 0 + // L25: JMPIF_L L19 + // L26: DROP + Run(nameof(NeoIssue2528), "VwEAwkpKAfsHdwARwG8AnXcAbwAl9////xHAzwJwlAAAdwAQzm8AnXcAbwAl9////0U="); + } + + public static void NeoVMIssue418() + { + // https://github.com/neo-project/neo-vm/issues/418 + // L00: NEWARRAY0 + // L01: PUSH0 + // L02: PICK + // L03: PUSH1 + // L04: PACK + // L05: PUSH1 + // L06: PICK + // L07: PUSH1 + // L08: PACK + // L09: INITSSLOT 1 + // L10: PUSHINT16 510 + // L11: DEC + // L12: STSFLD0 + // L13: PUSH1 + // L14: PICK + // L15: PUSH1 + // L16: PICK + // L17: PUSH2 + // L18: PACK + // L19: REVERSE3 + // L20: PUSH2 + // L21: PACK + // L22: LDSFLD0 + // L23: DUP + // L24: JMPIF L11 + // L25: DROP + // L26: ROT + // L27: DROP + Run(nameof(NeoVMIssue418), "whBNEcARTRHAVgEB/gGdYBFNEU0SwFMSwFhKJPNFUUU="); + } + + public static void NeoIssue2723() + { + // L00: INITSSLOT 1 + // L01: PUSHINT32 130000 + // L02: STSFLD 0 + // L03: PUSHINT32 1048576 + // L04: NEWBUFFER + // L05: DROP + // L06: LDSFLD 0 + // L07: DEC + // L08: DUP + // L09: STSFLD 0 + // L10: JMPIF L03 + Run(nameof(NeoIssue2723), "VgEC0PsBAGcAAgAAEACIRV8AnUpnACTz"); + } + + private static void Run(string name, string poc) + { + byte[] script = Convert.FromBase64String(poc); + using ExecutionEngine engine = new(); + engine.LoadScript(script); + Stopwatch stopwatch = Stopwatch.StartNew(); + engine.Execute(); + stopwatch.Stop(); + Debug.Assert(engine.State == VMState.HALT); + Console.WriteLine($"Benchmark: {name},\tTime: {stopwatch.Elapsed}"); + } + } +} diff --git a/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj new file mode 100644 index 0000000000..bdca77ae89 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj @@ -0,0 +1,16 @@ + + + + Exe + net7.0 + Neo.VM + enable + enable + false + + + + + + + diff --git a/benchmarks/Neo.VM.Benchmarks/Program.cs b/benchmarks/Neo.VM.Benchmarks/Program.cs new file mode 100644 index 0000000000..4ab0a66926 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/Program.cs @@ -0,0 +1,7 @@ +using Neo.VM; +using System.Reflection; + +foreach (var method in typeof(Benchmarks).GetMethods(BindingFlags.Public | BindingFlags.Static)) +{ + method.CreateDelegate().Invoke(); +} diff --git a/neo.sln b/neo.sln index e705e23988..827bddc1b2 100644 --- a/neo.sln +++ b/neo.sln @@ -8,7 +8,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "src\Neo.Json\Ne EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.UnitTests", "tests\Neo.UnitTests\Neo.UnitTests.csproj", "{5B783B30-B422-4C2F-AC22-187A8D1993F4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Json.UnitTests", "tests\Neo.Json.UnitTests\Neo.Json.UnitTests.csproj", "{AE6C32EE-8447-4E01-8187-2AE02BB64251}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json.UnitTests", "tests\Neo.Json.UnitTests\Neo.Json.UnitTests.csproj", "{AE6C32EE-8447-4E01-8187-2AE02BB64251}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Benchmarks", "benchmarks\Neo.Benchmarks\Neo.Benchmarks.csproj", "{BCD03521-5F8F-4775-9ADF-FA361480804F}" EndProject @@ -18,6 +18,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{EDE05FA8 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{C25EB0B0-0CAC-4CC1-8F36-F9229EFB99EC}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM.Benchmarks", "benchmarks\Neo.VM.Benchmarks\Neo.VM.Benchmarks.csproj", "{E83633BA-FCF0-4A1A-B5BC-42000E24D437}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "src\Neo.VM\Neo.VM.csproj", "{0603710E-E0BA-494C-AA0F-6FB0C8A8C754}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM.Tests", "tests\Neo.VM.Tests\Neo.VM.Tests.csproj", "{005F84EB-EA2E-449F-930A-7B4173DDC7EC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,6 +50,18 @@ Global {BCD03521-5F8F-4775-9ADF-FA361480804F}.Debug|Any CPU.Build.0 = Debug|Any CPU {BCD03521-5F8F-4775-9ADF-FA361480804F}.Release|Any CPU.ActiveCfg = Release|Any CPU {BCD03521-5F8F-4775-9ADF-FA361480804F}.Release|Any CPU.Build.0 = Release|Any CPU + {E83633BA-FCF0-4A1A-B5BC-42000E24D437}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E83633BA-FCF0-4A1A-B5BC-42000E24D437}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E83633BA-FCF0-4A1A-B5BC-42000E24D437}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E83633BA-FCF0-4A1A-B5BC-42000E24D437}.Release|Any CPU.Build.0 = Release|Any CPU + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754}.Release|Any CPU.Build.0 = Release|Any CPU + {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -54,6 +72,9 @@ Global {5B783B30-B422-4C2F-AC22-187A8D1993F4} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} {AE6C32EE-8447-4E01-8187-2AE02BB64251} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} {BCD03521-5F8F-4775-9ADF-FA361480804F} = {C25EB0B0-0CAC-4CC1-8F36-F9229EFB99EC} + {E83633BA-FCF0-4A1A-B5BC-42000E24D437} = {C25EB0B0-0CAC-4CC1-8F36-F9229EFB99EC} + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {005F84EB-EA2E-449F-930A-7B4173DDC7EC} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo.VM/BadScriptException.cs b/src/Neo.VM/BadScriptException.cs new file mode 100644 index 0000000000..fcf4b9f2b4 --- /dev/null +++ b/src/Neo.VM/BadScriptException.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; + +namespace Neo.VM +{ + /// + /// Represents the exception thrown when the bad script is parsed. + /// + public class BadScriptException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public BadScriptException() { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The message that describes the error. + public BadScriptException(string message) : base(message) { } + } +} diff --git a/src/Neo.VM/CatchableException.cs b/src/Neo.VM/CatchableException.cs new file mode 100644 index 0000000000..9235ac5c31 --- /dev/null +++ b/src/Neo.VM/CatchableException.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; + +namespace Neo.VM +{ + public class CatchableException : Exception + { + public CatchableException(string message) : base(message) + { + } + } +} diff --git a/src/Neo.VM/Collections/OrderedDictionary.cs b/src/Neo.VM/Collections/OrderedDictionary.cs new file mode 100644 index 0000000000..5f2d593067 --- /dev/null +++ b/src/Neo.VM/Collections/OrderedDictionary.cs @@ -0,0 +1,129 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Neo.VM.Collections +{ + internal class OrderedDictionary : IDictionary + where TKey : notnull + { + private class TItem + { + public readonly TKey Key; + public TValue Value; + + public TItem(TKey key, TValue value) + { + this.Key = key; + this.Value = value; + } + } + + private class InternalCollection : KeyedCollection + { + protected override TKey GetKeyForItem(TItem item) + { + return item.Key; + } + } + + private readonly InternalCollection collection = new(); + + public int Count => collection.Count; + public bool IsReadOnly => false; + public ICollection Keys => collection.Select(p => p.Key).ToArray(); + public ICollection Values => collection.Select(p => p.Value).ToArray(); + + public TValue this[TKey key] + { + get + { + return collection[key].Value; + } + set + { + if (collection.TryGetValue(key, out var entry)) + entry.Value = value; + else + Add(key, value); + } + } + + public void Add(TKey key, TValue value) + { + collection.Add(new TItem(key, value)); + } + + public bool ContainsKey(TKey key) + { + return collection.Contains(key); + } + + public bool Remove(TKey key) + { + return collection.Remove(key); + } + + // supress warning of value parameter nullability mismatch +#pragma warning disable CS8767 + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) +#pragma warning restore CS8767 + { + if (collection.TryGetValue(key, out var entry)) + { + value = entry.Value; + return true; + } + value = default; + return false; + } + + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public void Clear() + { + collection.Clear(); + } + + bool ICollection>.Contains(KeyValuePair item) + { + return collection.Contains(item.Key); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + for (int i = 0; i < collection.Count; i++) + array[i + arrayIndex] = new KeyValuePair(collection[i].Key, collection[i].Value); + } + + bool ICollection>.Remove(KeyValuePair item) + { + return collection.Remove(item.Key); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return collection.Select(p => new KeyValuePair(p.Key, p.Value)).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return collection.Select(p => new KeyValuePair(p.Key, p.Value)).GetEnumerator(); + } + } +} diff --git a/src/Neo.VM/Cryptography/BitOperations.cs b/src/Neo.VM/Cryptography/BitOperations.cs new file mode 100644 index 0000000000..40fc0171af --- /dev/null +++ b/src/Neo.VM/Cryptography/BitOperations.cs @@ -0,0 +1,27 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Runtime.CompilerServices; + +namespace Neo.VM.Cryptography +{ +#if !NET5_0_OR_GREATER + static class BitOperations + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) + => (value << offset) | (value >> (32 - offset)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong RotateLeft(ulong value, int offset) + => (value << offset) | (value >> (64 - offset)); + } +#endif +} diff --git a/src/Neo.VM/Cryptography/Murmur32.cs b/src/Neo.VM/Cryptography/Murmur32.cs new file mode 100644 index 0000000000..5cfa22d9b7 --- /dev/null +++ b/src/Neo.VM/Cryptography/Murmur32.cs @@ -0,0 +1,97 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Buffers.Binary; +using System.Numerics; +using System.Security.Cryptography; + +namespace Neo.VM.Cryptography +{ + /// + /// Computes the murmur hash for the input data. + /// + sealed class Murmur32 : HashAlgorithm + { + private const uint c1 = 0xcc9e2d51; + private const uint c2 = 0x1b873593; + private const int r1 = 15; + private const int r2 = 13; + private const uint m = 5; + private const uint n = 0xe6546b64; + + private readonly uint seed; + private uint hash; + private int length; + + public override int HashSize => 32; + + /// + /// Initializes a new instance of the class with the specified seed. + /// + /// The seed to be used. + public Murmur32(uint seed) + { + this.seed = seed; + Initialize(); + } + + protected override void HashCore(byte[] array, int ibStart, int cbSize) + { + length += cbSize; + int remainder = cbSize & 3; + int alignedLength = ibStart + (cbSize - remainder); + for (int i = ibStart; i < alignedLength; i += 4) + { + uint k = BinaryPrimitives.ReadUInt32LittleEndian(array.AsSpan(i)); + k *= c1; + k = BitOperations.RotateLeft(k, r1); + k *= c2; + hash ^= k; + hash = BitOperations.RotateLeft(hash, r2); + hash = hash * m + n; + } + if (remainder > 0) + { + uint remainingBytes = 0; + switch (remainder) + { + case 3: remainingBytes ^= (uint)array[alignedLength + 2] << 16; goto case 2; + case 2: remainingBytes ^= (uint)array[alignedLength + 1] << 8; goto case 1; + case 1: remainingBytes ^= array[alignedLength]; break; + } + remainingBytes *= c1; + remainingBytes = BitOperations.RotateLeft(remainingBytes, r1); + remainingBytes *= c2; + hash ^= remainingBytes; + } + } + + protected override byte[] HashFinal() + { + hash ^= (uint)length; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + + byte[] buffer = new byte[sizeof(uint)]; + BinaryPrimitives.WriteUInt32LittleEndian(buffer, hash); + return buffer; + } + + public override void Initialize() + { + hash = seed; + length = 0; + } + } +} diff --git a/src/Neo.VM/Debugger.cs b/src/Neo.VM/Debugger.cs new file mode 100644 index 0000000000..fef4d87e75 --- /dev/null +++ b/src/Neo.VM/Debugger.cs @@ -0,0 +1,137 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Collections.Generic; + +namespace Neo.VM +{ + /// + /// A simple debugger for . + /// + public class Debugger + { + private readonly ExecutionEngine engine; + private readonly Dictionary> break_points = new(); + + /// + /// Create a debugger on the specified . + /// + /// The to attach the debugger. + public Debugger(ExecutionEngine engine) + { + this.engine = engine; + } + + /// + /// Add a breakpoint at the specified position of the specified script. The VM will break the execution when it reaches the breakpoint. + /// + /// The script to add the breakpoint. + /// The position of the breakpoint in the script. + public void AddBreakPoint(Script script, uint position) + { + if (!break_points.TryGetValue(script, out HashSet? hashset)) + { + hashset = new HashSet(); + break_points.Add(script, hashset); + } + hashset.Add(position); + } + + /// + /// Start or continue execution of the VM. + /// + /// Returns the state of the VM after the execution. + public VMState Execute() + { + if (engine.State == VMState.BREAK) + engine.State = VMState.NONE; + while (engine.State == VMState.NONE) + ExecuteAndCheckBreakPoints(); + return engine.State; + } + + private void ExecuteAndCheckBreakPoints() + { + engine.ExecuteNext(); + if (engine.State == VMState.NONE && engine.InvocationStack.Count > 0 && break_points.Count > 0) + { + if (break_points.TryGetValue(engine.CurrentContext!.Script, out HashSet? hashset) && hashset.Contains((uint)engine.CurrentContext.InstructionPointer)) + engine.State = VMState.BREAK; + } + } + + /// + /// Removes the breakpoint at the specified position in the specified script. + /// + /// The script to remove the breakpoint. + /// The position of the breakpoint in the script. + /// + /// if the breakpoint is successfully found and removed; + /// otherwise, . + /// + public bool RemoveBreakPoint(Script script, uint position) + { + if (!break_points.TryGetValue(script, out HashSet? hashset)) return false; + if (!hashset.Remove(position)) return false; + if (hashset.Count == 0) break_points.Remove(script); + return true; + } + + /// + /// Execute the next instruction. If the instruction involves a call to a method, it steps into the method and breaks the execution on the first instruction of that method. + /// + /// The VM state after the instruction is executed. + public VMState StepInto() + { + if (engine.State == VMState.HALT || engine.State == VMState.FAULT) + return engine.State; + engine.ExecuteNext(); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + return engine.State; + } + + /// + /// Execute until the currently executed method is returned. + /// + /// The VM state after the currently executed method is returned. + public VMState StepOut() + { + if (engine.State == VMState.BREAK) + engine.State = VMState.NONE; + int c = engine.InvocationStack.Count; + while (engine.State == VMState.NONE && engine.InvocationStack.Count >= c) + ExecuteAndCheckBreakPoints(); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + return engine.State; + } + + /// + /// Execute the next instruction. If the instruction involves a call to a method, it does not step into the method (it steps over it instead). + /// + /// The VM state after the instruction is executed. + public VMState StepOver() + { + if (engine.State == VMState.HALT || engine.State == VMState.FAULT) + return engine.State; + engine.State = VMState.NONE; + int c = engine.InvocationStack.Count; + do + { + ExecuteAndCheckBreakPoints(); + } + while (engine.State == VMState.NONE && engine.InvocationStack.Count > c); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + return engine.State; + } + } +} diff --git a/src/Neo.VM/EvaluationStack.cs b/src/Neo.VM/EvaluationStack.cs new file mode 100644 index 0000000000..b5b728ed46 --- /dev/null +++ b/src/Neo.VM/EvaluationStack.cs @@ -0,0 +1,162 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Types; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Represents the evaluation stack in the VM. + /// + public sealed class EvaluationStack : IReadOnlyList + { + private readonly List innerList = new(); + private readonly ReferenceCounter referenceCounter; + + internal EvaluationStack(ReferenceCounter referenceCounter) + { + this.referenceCounter = referenceCounter; + } + + /// + /// Gets the number of items on the stack. + /// + public int Count => innerList.Count; + + internal void Clear() + { + foreach (StackItem item in innerList) + referenceCounter.RemoveStackReference(item); + innerList.Clear(); + } + + internal void CopyTo(EvaluationStack stack, int count = -1) + { + if (count < -1 || count > innerList.Count) + throw new ArgumentOutOfRangeException(nameof(count)); + if (count == 0) return; + if (count == -1 || count == innerList.Count) + stack.innerList.AddRange(innerList); + else + stack.innerList.AddRange(innerList.Skip(innerList.Count - count)); + } + + public IEnumerator GetEnumerator() + { + return innerList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return innerList.GetEnumerator(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Insert(int index, StackItem item) + { + if (index > innerList.Count) throw new InvalidOperationException($"Insert out of bounds: {index}/{innerList.Count}"); + innerList.Insert(innerList.Count - index, item); + referenceCounter.AddStackReference(item); + } + + internal void MoveTo(EvaluationStack stack, int count = -1) + { + if (count == 0) return; + CopyTo(stack, count); + if (count == -1 || count == innerList.Count) + innerList.Clear(); + else + innerList.RemoveRange(innerList.Count - count, count); + } + + /// + /// Returns the item at the specified index from the top of the stack without removing it. + /// + /// The index of the object from the top of the stack. + /// The item at the specified index. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackItem Peek(int index = 0) + { + if (index >= innerList.Count) throw new InvalidOperationException($"Peek out of bounds: {index}/{innerList.Count}"); + if (index < 0) + { + index += innerList.Count; + if (index < 0) throw new InvalidOperationException($"Peek out of bounds: {index}/{innerList.Count}"); + } + return innerList[innerList.Count - index - 1]; + } + + StackItem IReadOnlyList.this[int index] => Peek(index); + + /// + /// Pushes an item onto the top of the stack. + /// + /// The item to be pushed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(StackItem item) + { + innerList.Add(item); + referenceCounter.AddStackReference(item); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Reverse(int n) + { + if (n < 0 || n > innerList.Count) + throw new ArgumentOutOfRangeException(nameof(n)); + if (n <= 1) return; + innerList.Reverse(innerList.Count - n, n); + } + + /// + /// Removes and returns the item at the top of the stack. + /// + /// The item removed from the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackItem Pop() + { + return Remove(0); + } + + /// + /// Removes and returns the item at the top of the stack and convert it to the specified type. + /// + /// The type to convert to. + /// The item removed from the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Pop() where T : StackItem + { + return Remove(0); + } + + internal T Remove(int index) where T : StackItem + { + if (index >= innerList.Count) + throw new ArgumentOutOfRangeException(nameof(index)); + if (index < 0) + { + index += innerList.Count; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + } + index = innerList.Count - index - 1; + if (innerList[index] is not T item) + throw new InvalidCastException($"The item can't be casted to type {typeof(T)}"); + innerList.RemoveAt(index); + referenceCounter.RemoveStackReference(item); + return item; + } + } +} diff --git a/src/Neo.VM/ExceptionHandlingContext.cs b/src/Neo.VM/ExceptionHandlingContext.cs new file mode 100644 index 0000000000..dd3f03823e --- /dev/null +++ b/src/Neo.VM/ExceptionHandlingContext.cs @@ -0,0 +1,57 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Diagnostics; + +namespace Neo.VM +{ + /// + /// Represents the context used for exception handling. + /// + [DebuggerDisplay("State={State}, CatchPointer={CatchPointer}, FinallyPointer={FinallyPointer}, EndPointer={EndPointer}")] + public sealed class ExceptionHandlingContext + { + /// + /// The position of the block. + /// + public int CatchPointer { get; } + + /// + /// The position of the block. + /// + public int FinallyPointer { get; } + + /// + /// The end position of the -- block. + /// + public int EndPointer { get; internal set; } = -1; + + /// + /// Indicates whether the block is included in the context. + /// + public bool HasCatch => CatchPointer >= 0; + + /// + /// Indicates whether the block is included in the context. + /// + public bool HasFinally => FinallyPointer >= 0; + + /// + /// Indicates the state of the context. + /// + public ExceptionHandlingState State { get; internal set; } = ExceptionHandlingState.Try; + + internal ExceptionHandlingContext(int catchPointer, int finallyPointer) + { + this.CatchPointer = catchPointer; + this.FinallyPointer = finallyPointer; + } + } +} diff --git a/src/Neo.VM/ExceptionHandlingState.cs b/src/Neo.VM/ExceptionHandlingState.cs new file mode 100644 index 0000000000..ea3a484a9c --- /dev/null +++ b/src/Neo.VM/ExceptionHandlingState.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.VM +{ + /// + /// Indicates the state of the . + /// + public enum ExceptionHandlingState : byte + { + /// + /// Indicates that the block is being executed. + /// + Try, + + /// + /// Indicates that the block is being executed. + /// + Catch, + + /// + /// Indicates that the block is being executed. + /// + Finally + } +} diff --git a/src/Neo.VM/ExecutionContext.SharedStates.cs b/src/Neo.VM/ExecutionContext.SharedStates.cs new file mode 100644 index 0000000000..0e037fcf0a --- /dev/null +++ b/src/Neo.VM/ExecutionContext.SharedStates.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; + +namespace Neo.VM +{ + partial class ExecutionContext + { + private class SharedStates + { + public readonly Script Script; + public readonly EvaluationStack EvaluationStack; + public Slot? StaticFields; + public readonly Dictionary States; + + public SharedStates(Script script, ReferenceCounter referenceCounter) + { + this.Script = script; + this.EvaluationStack = new EvaluationStack(referenceCounter); + this.States = new Dictionary(); + } + } + } +} diff --git a/src/Neo.VM/ExecutionContext.cs b/src/Neo.VM/ExecutionContext.cs new file mode 100644 index 0000000000..be83be823e --- /dev/null +++ b/src/Neo.VM/ExecutionContext.cs @@ -0,0 +1,169 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Represents a frame in the VM execution stack. + /// + [DebuggerDisplay("InstructionPointer={InstructionPointer}")] + public sealed partial class ExecutionContext + { + private readonly SharedStates shared_states; + private int instructionPointer; + + /// + /// Indicates the number of values that the context should return when it is unloaded. + /// + public int RVCount { get; } + + /// + /// The script to run in this context. + /// + public Script Script => shared_states.Script; + + /// + /// The evaluation stack for this context. + /// + public EvaluationStack EvaluationStack => shared_states.EvaluationStack; + + /// + /// The slot used to store the static fields. + /// + public Slot? StaticFields + { + get => shared_states.StaticFields; + internal set => shared_states.StaticFields = value; + } + + /// + /// The slot used to store the local variables of the current method. + /// + public Slot? LocalVariables { get; internal set; } + + /// + /// The slot used to store the arguments of the current method. + /// + public Slot? Arguments { get; internal set; } + + /// + /// The stack containing nested . + /// + public Stack? TryStack { get; internal set; } + + /// + /// The pointer indicating the current instruction. + /// + public int InstructionPointer + { + get + { + return instructionPointer; + } + internal set + { + if (value < 0 || value > Script.Length) + throw new ArgumentOutOfRangeException(nameof(value)); + instructionPointer = value; + } + } + + /// + /// Returns the current . + /// + public Instruction? CurrentInstruction + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return GetInstruction(InstructionPointer); + } + } + + /// + /// Returns the next . + /// + public Instruction? NextInstruction + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + Instruction? current = CurrentInstruction; + if (current is null) return null; + return GetInstruction(InstructionPointer + current.Size); + } + } + + internal ExecutionContext(Script script, int rvcount, ReferenceCounter referenceCounter) + : this(new SharedStates(script, referenceCounter), rvcount, 0) + { + } + + private ExecutionContext(SharedStates shared_states, int rvcount, int initialPosition) + { + if (rvcount < -1 || rvcount > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(rvcount)); + this.shared_states = shared_states; + this.RVCount = rvcount; + this.InstructionPointer = initialPosition; + } + + /// + /// Clones the context so that they share the same script, stack, and static fields. + /// + /// The cloned context. + public ExecutionContext Clone() + { + return Clone(InstructionPointer); + } + + /// + /// Clones the context so that they share the same script, stack, and static fields. + /// + /// The instruction pointer of the new context. + /// The cloned context. + public ExecutionContext Clone(int initialPosition) + { + return new ExecutionContext(shared_states, 0, initialPosition); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Instruction? GetInstruction(int ip) => ip >= Script.Length ? null : Script.GetInstruction(ip); + + /// + /// Gets custom data of the specified type. If the data does not exist, create a new one. + /// + /// The type of data to be obtained. + /// A delegate used to create the entry. If factory is null, new() will be used. + /// The custom data of the specified type. + public T GetState(Func? factory = null) where T : class, new() + { + if (!shared_states.States.TryGetValue(typeof(T), out object? value)) + { + value = factory is null ? new T() : factory(); + shared_states.States[typeof(T)] = value; + } + return (T)value; + } + + internal bool MoveNext() + { + Instruction? current = CurrentInstruction; + if (current is null) return false; + InstructionPointer += current.Size; + return InstructionPointer < Script.Length; + } + } +} diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs new file mode 100644 index 0000000000..ab344b32ef --- /dev/null +++ b/src/Neo.VM/ExecutionEngine.cs @@ -0,0 +1,1702 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Types; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Runtime.CompilerServices; +using Buffer = Neo.VM.Types.Buffer; +using VMArray = Neo.VM.Types.Array; + +namespace Neo.VM +{ + /// + /// Represents the VM used to execute the script. + /// + public class ExecutionEngine : IDisposable + { + private VMState state = VMState.BREAK; + private bool isJumping = false; + + /// + /// Restrictions on the VM. + /// + public ExecutionEngineLimits Limits { get; } + + /// + /// Used for reference counting of objects in the VM. + /// + public ReferenceCounter ReferenceCounter { get; } + + /// + /// The invocation stack of the VM. + /// + public Stack InvocationStack { get; } = new Stack(); + + /// + /// The top frame of the invocation stack. + /// + public ExecutionContext? CurrentContext { get; private set; } + + /// + /// The bottom frame of the invocation stack. + /// + public ExecutionContext? EntryContext { get; private set; } + + /// + /// The stack to store the return values. + /// + public EvaluationStack ResultStack { get; } + + /// + /// The VM object representing the uncaught exception. + /// + public StackItem? UncaughtException { get; private set; } + + /// + /// The current state of the VM. + /// + public VMState State + { + get + { + return state; + } + internal protected set + { + if (state != value) + { + state = value; + OnStateChanged(); + } + } + } + + /// + /// Initializes a new instance of the class. + /// + public ExecutionEngine() : this(new ReferenceCounter(), ExecutionEngineLimits.Default) + { + } + + /// + /// Initializes a new instance of the class with the specified and . + /// + /// The reference counter to be used. + /// Restrictions on the VM. + protected ExecutionEngine(ReferenceCounter referenceCounter, ExecutionEngineLimits limits) + { + this.Limits = limits; + this.ReferenceCounter = referenceCounter; + this.ResultStack = new EvaluationStack(referenceCounter); + } + + /// + /// Called when a context is unloaded. + /// + /// The context being unloaded. + protected virtual void ContextUnloaded(ExecutionContext context) + { + if (InvocationStack.Count == 0) + { + CurrentContext = null; + EntryContext = null; + } + else + { + CurrentContext = InvocationStack.Peek(); + } + if (context.StaticFields != null && context.StaticFields != CurrentContext?.StaticFields) + { + context.StaticFields.ClearReferences(); + } + context.LocalVariables?.ClearReferences(); + context.Arguments?.ClearReferences(); + } + + public virtual void Dispose() + { + InvocationStack.Clear(); + } + + /// + /// Start execution of the VM. + /// + /// + public virtual VMState Execute() + { + if (State == VMState.BREAK) + State = VMState.NONE; + while (State != VMState.HALT && State != VMState.FAULT) + ExecuteNext(); + return State; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ExecuteCall(int position) + { + LoadContext(CurrentContext!.Clone(position)); + } + + private void ExecuteInstruction(Instruction instruction) + { + switch (instruction.OpCode) + { + //Push + case OpCode.PUSHINT8: + case OpCode.PUSHINT16: + case OpCode.PUSHINT32: + case OpCode.PUSHINT64: + case OpCode.PUSHINT128: + case OpCode.PUSHINT256: + { + Push(new BigInteger(instruction.Operand.Span)); + break; + } + case OpCode.PUSHT: + { + Push(StackItem.True); + break; + } + case OpCode.PUSHF: + { + Push(StackItem.False); + break; + } + case OpCode.PUSHA: + { + int position = checked(CurrentContext!.InstructionPointer + instruction.TokenI32); + if (position < 0 || position > CurrentContext.Script.Length) + throw new InvalidOperationException($"Bad pointer address: {position}"); + Push(new Pointer(CurrentContext.Script, position)); + break; + } + case OpCode.PUSHNULL: + { + Push(StackItem.Null); + break; + } + case OpCode.PUSHDATA1: + case OpCode.PUSHDATA2: + case OpCode.PUSHDATA4: + { + Limits.AssertMaxItemSize(instruction.Operand.Length); + Push(instruction.Operand); + break; + } + case OpCode.PUSHM1: + case OpCode.PUSH0: + case OpCode.PUSH1: + case OpCode.PUSH2: + case OpCode.PUSH3: + case OpCode.PUSH4: + case OpCode.PUSH5: + case OpCode.PUSH6: + case OpCode.PUSH7: + case OpCode.PUSH8: + case OpCode.PUSH9: + case OpCode.PUSH10: + case OpCode.PUSH11: + case OpCode.PUSH12: + case OpCode.PUSH13: + case OpCode.PUSH14: + case OpCode.PUSH15: + case OpCode.PUSH16: + { + Push((int)instruction.OpCode - (int)OpCode.PUSH0); + break; + } + + // Control + case OpCode.NOP: break; + case OpCode.JMP: + { + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMP_L: + { + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPIF: + { + if (Pop().GetBoolean()) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPIF_L: + { + if (Pop().GetBoolean()) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPIFNOT: + { + if (!Pop().GetBoolean()) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPIFNOT_L: + { + if (!Pop().GetBoolean()) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPEQ: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 == x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPEQ_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 == x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPNE: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 != x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPNE_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 != x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPGT: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 > x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPGT_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 > x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPGE: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 >= x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPGE_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 >= x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPLT: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 < x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPLT_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 < x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPLE: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 <= x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPLE_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 <= x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.CALL: + { + ExecuteCall(checked(CurrentContext!.InstructionPointer + instruction.TokenI8)); + break; + } + case OpCode.CALL_L: + { + ExecuteCall(checked(CurrentContext!.InstructionPointer + instruction.TokenI32)); + break; + } + case OpCode.CALLA: + { + var x = Pop(); + if (x.Script != CurrentContext!.Script) + throw new InvalidOperationException("Pointers can't be shared between scripts"); + ExecuteCall(x.Position); + break; + } + case OpCode.CALLT: + { + LoadToken(instruction.TokenU16); + break; + } + case OpCode.ABORT: + { + throw new Exception($"{OpCode.ABORT} is executed."); + } + case OpCode.ASSERT: + { + var x = Pop().GetBoolean(); + if (!x) + throw new Exception($"{OpCode.ASSERT} is executed with false result."); + break; + } + case OpCode.THROW: + { + ExecuteThrow(Pop()); + break; + } + case OpCode.TRY: + { + int catchOffset = instruction.TokenI8; + int finallyOffset = instruction.TokenI8_1; + ExecuteTry(catchOffset, finallyOffset); + break; + } + case OpCode.TRY_L: + { + int catchOffset = instruction.TokenI32; + int finallyOffset = instruction.TokenI32_1; + ExecuteTry(catchOffset, finallyOffset); + break; + } + case OpCode.ENDTRY: + { + int endOffset = instruction.TokenI8; + ExecuteEndTry(endOffset); + break; + } + case OpCode.ENDTRY_L: + { + int endOffset = instruction.TokenI32; + ExecuteEndTry(endOffset); + break; + } + case OpCode.ENDFINALLY: + { + if (CurrentContext!.TryStack is null) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (!CurrentContext.TryStack.TryPop(out ExceptionHandlingContext? currentTry)) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + + if (UncaughtException is null) + CurrentContext.InstructionPointer = currentTry.EndPointer; + else + HandleException(); + + isJumping = true; + break; + } + case OpCode.RET: + { + ExecutionContext context_pop = InvocationStack.Pop(); + EvaluationStack stack_eval = InvocationStack.Count == 0 ? ResultStack : InvocationStack.Peek().EvaluationStack; + if (context_pop.EvaluationStack != stack_eval) + { + if (context_pop.RVCount >= 0 && context_pop.EvaluationStack.Count != context_pop.RVCount) + throw new InvalidOperationException("RVCount doesn't match with EvaluationStack"); + context_pop.EvaluationStack.CopyTo(stack_eval); + } + if (InvocationStack.Count == 0) + State = VMState.HALT; + ContextUnloaded(context_pop); + isJumping = true; + break; + } + case OpCode.SYSCALL: + { + OnSysCall(instruction.TokenU32); + break; + } + + // Stack ops + case OpCode.DEPTH: + { + Push(CurrentContext!.EvaluationStack.Count); + break; + } + case OpCode.DROP: + { + Pop(); + break; + } + case OpCode.NIP: + { + CurrentContext!.EvaluationStack.Remove(1); + break; + } + case OpCode.XDROP: + { + int n = (int)Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + CurrentContext!.EvaluationStack.Remove(n); + break; + } + case OpCode.CLEAR: + { + CurrentContext!.EvaluationStack.Clear(); + break; + } + case OpCode.DUP: + { + Push(Peek()); + break; + } + case OpCode.OVER: + { + Push(Peek(1)); + break; + } + case OpCode.PICK: + { + int n = (int)Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + Push(Peek(n)); + break; + } + case OpCode.TUCK: + { + CurrentContext!.EvaluationStack.Insert(2, Peek()); + break; + } + case OpCode.SWAP: + { + var x = CurrentContext!.EvaluationStack.Remove(1); + Push(x); + break; + } + case OpCode.ROT: + { + var x = CurrentContext!.EvaluationStack.Remove(2); + Push(x); + break; + } + case OpCode.ROLL: + { + int n = (int)Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + if (n == 0) break; + var x = CurrentContext!.EvaluationStack.Remove(n); + Push(x); + break; + } + case OpCode.REVERSE3: + { + CurrentContext!.EvaluationStack.Reverse(3); + break; + } + case OpCode.REVERSE4: + { + CurrentContext!.EvaluationStack.Reverse(4); + break; + } + case OpCode.REVERSEN: + { + int n = (int)Pop().GetInteger(); + CurrentContext!.EvaluationStack.Reverse(n); + break; + } + + //Slot + case OpCode.INITSSLOT: + { + if (CurrentContext!.StaticFields != null) + throw new InvalidOperationException($"{instruction.OpCode} cannot be executed twice."); + if (instruction.TokenU8 == 0) + throw new InvalidOperationException($"The operand {instruction.TokenU8} is invalid for OpCode.{instruction.OpCode}."); + CurrentContext.StaticFields = new Slot(instruction.TokenU8, ReferenceCounter); + break; + } + case OpCode.INITSLOT: + { + if (CurrentContext!.LocalVariables != null || CurrentContext.Arguments != null) + throw new InvalidOperationException($"{instruction.OpCode} cannot be executed twice."); + if (instruction.TokenU16 == 0) + throw new InvalidOperationException($"The operand {instruction.TokenU16} is invalid for OpCode.{instruction.OpCode}."); + if (instruction.TokenU8 > 0) + { + CurrentContext.LocalVariables = new Slot(instruction.TokenU8, ReferenceCounter); + } + if (instruction.TokenU8_1 > 0) + { + StackItem[] items = new StackItem[instruction.TokenU8_1]; + for (int i = 0; i < instruction.TokenU8_1; i++) + { + items[i] = Pop(); + } + CurrentContext.Arguments = new Slot(items, ReferenceCounter); + } + break; + } + case OpCode.LDSFLD0: + case OpCode.LDSFLD1: + case OpCode.LDSFLD2: + case OpCode.LDSFLD3: + case OpCode.LDSFLD4: + case OpCode.LDSFLD5: + case OpCode.LDSFLD6: + { + ExecuteLoadFromSlot(CurrentContext!.StaticFields, instruction.OpCode - OpCode.LDSFLD0); + break; + } + case OpCode.LDSFLD: + { + ExecuteLoadFromSlot(CurrentContext!.StaticFields, instruction.TokenU8); + break; + } + case OpCode.STSFLD0: + case OpCode.STSFLD1: + case OpCode.STSFLD2: + case OpCode.STSFLD3: + case OpCode.STSFLD4: + case OpCode.STSFLD5: + case OpCode.STSFLD6: + { + ExecuteStoreToSlot(CurrentContext!.StaticFields, instruction.OpCode - OpCode.STSFLD0); + break; + } + case OpCode.STSFLD: + { + ExecuteStoreToSlot(CurrentContext!.StaticFields, instruction.TokenU8); + break; + } + case OpCode.LDLOC0: + case OpCode.LDLOC1: + case OpCode.LDLOC2: + case OpCode.LDLOC3: + case OpCode.LDLOC4: + case OpCode.LDLOC5: + case OpCode.LDLOC6: + { + ExecuteLoadFromSlot(CurrentContext!.LocalVariables, instruction.OpCode - OpCode.LDLOC0); + break; + } + case OpCode.LDLOC: + { + ExecuteLoadFromSlot(CurrentContext!.LocalVariables, instruction.TokenU8); + break; + } + case OpCode.STLOC0: + case OpCode.STLOC1: + case OpCode.STLOC2: + case OpCode.STLOC3: + case OpCode.STLOC4: + case OpCode.STLOC5: + case OpCode.STLOC6: + { + ExecuteStoreToSlot(CurrentContext!.LocalVariables, instruction.OpCode - OpCode.STLOC0); + break; + } + case OpCode.STLOC: + { + ExecuteStoreToSlot(CurrentContext!.LocalVariables, instruction.TokenU8); + break; + } + case OpCode.LDARG0: + case OpCode.LDARG1: + case OpCode.LDARG2: + case OpCode.LDARG3: + case OpCode.LDARG4: + case OpCode.LDARG5: + case OpCode.LDARG6: + { + ExecuteLoadFromSlot(CurrentContext!.Arguments, instruction.OpCode - OpCode.LDARG0); + break; + } + case OpCode.LDARG: + { + ExecuteLoadFromSlot(CurrentContext!.Arguments, instruction.TokenU8); + break; + } + case OpCode.STARG0: + case OpCode.STARG1: + case OpCode.STARG2: + case OpCode.STARG3: + case OpCode.STARG4: + case OpCode.STARG5: + case OpCode.STARG6: + { + ExecuteStoreToSlot(CurrentContext!.Arguments, instruction.OpCode - OpCode.STARG0); + break; + } + case OpCode.STARG: + { + ExecuteStoreToSlot(CurrentContext!.Arguments, instruction.TokenU8); + break; + } + + // Splice + case OpCode.NEWBUFFER: + { + int length = (int)Pop().GetInteger(); + Limits.AssertMaxItemSize(length); + Push(new Buffer(length)); + break; + } + case OpCode.MEMCPY: + { + int count = (int)Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + int si = (int)Pop().GetInteger(); + if (si < 0) + throw new InvalidOperationException($"The value {si} is out of range."); + ReadOnlySpan src = Pop().GetSpan(); + if (checked(si + count) > src.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + int di = (int)Pop().GetInteger(); + if (di < 0) + throw new InvalidOperationException($"The value {di} is out of range."); + Buffer dst = Pop(); + if (checked(di + count) > dst.Size) + throw new InvalidOperationException($"The value {count} is out of range."); + src.Slice(si, count).CopyTo(dst.InnerBuffer.Span[di..]); + break; + } + case OpCode.CAT: + { + var x2 = Pop().GetSpan(); + var x1 = Pop().GetSpan(); + int length = x1.Length + x2.Length; + Limits.AssertMaxItemSize(length); + Buffer result = new(length, false); + x1.CopyTo(result.InnerBuffer.Span); + x2.CopyTo(result.InnerBuffer.Span[x1.Length..]); + Push(result); + break; + } + case OpCode.SUBSTR: + { + int count = (int)Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + int index = (int)Pop().GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The value {index} is out of range."); + var x = Pop().GetSpan(); + if (index + count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Buffer result = new(count, false); + x.Slice(index, count).CopyTo(result.InnerBuffer.Span); + Push(result); + break; + } + case OpCode.LEFT: + { + int count = (int)Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + var x = Pop().GetSpan(); + if (count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Buffer result = new(count, false); + x[..count].CopyTo(result.InnerBuffer.Span); + Push(result); + break; + } + case OpCode.RIGHT: + { + int count = (int)Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + var x = Pop().GetSpan(); + if (count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Buffer result = new(count, false); + x[^count..^0].CopyTo(result.InnerBuffer.Span); + Push(result); + break; + } + + // Bitwise logic + case OpCode.INVERT: + { + var x = Pop().GetInteger(); + Push(~x); + break; + } + case OpCode.AND: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 & x2); + break; + } + case OpCode.OR: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 | x2); + break; + } + case OpCode.XOR: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 ^ x2); + break; + } + case OpCode.EQUAL: + { + StackItem x2 = Pop(); + StackItem x1 = Pop(); + Push(x1.Equals(x2, Limits)); + break; + } + case OpCode.NOTEQUAL: + { + StackItem x2 = Pop(); + StackItem x1 = Pop(); + Push(!x1.Equals(x2, Limits)); + break; + } + + // Numeric + case OpCode.SIGN: + { + var x = Pop().GetInteger(); + Push(x.Sign); + break; + } + case OpCode.ABS: + { + var x = Pop().GetInteger(); + Push(BigInteger.Abs(x)); + break; + } + case OpCode.NEGATE: + { + var x = Pop().GetInteger(); + Push(-x); + break; + } + case OpCode.INC: + { + var x = Pop().GetInteger(); + Push(x + 1); + break; + } + case OpCode.DEC: + { + var x = Pop().GetInteger(); + Push(x - 1); + break; + } + case OpCode.ADD: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 + x2); + break; + } + case OpCode.SUB: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 - x2); + break; + } + case OpCode.MUL: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 * x2); + break; + } + case OpCode.DIV: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 / x2); + break; + } + case OpCode.MOD: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 % x2); + break; + } + case OpCode.POW: + { + var exponent = (int)Pop().GetInteger(); + Limits.AssertShift(exponent); + var value = Pop().GetInteger(); + Push(BigInteger.Pow(value, exponent)); + break; + } + case OpCode.SQRT: + { + Push(Pop().GetInteger().Sqrt()); + break; + } + case OpCode.MODMUL: + { + var modulus = Pop().GetInteger(); + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 * x2 % modulus); + break; + } + case OpCode.MODPOW: + { + var modulus = Pop().GetInteger(); + var exponent = Pop().GetInteger(); + var value = Pop().GetInteger(); + var result = exponent == -1 + ? value.ModInverse(modulus) + : BigInteger.ModPow(value, exponent, modulus); + Push(result); + break; + } + case OpCode.SHL: + { + int shift = (int)Pop().GetInteger(); + Limits.AssertShift(shift); + if (shift == 0) break; + var x = Pop().GetInteger(); + Push(x << shift); + break; + } + case OpCode.SHR: + { + int shift = (int)Pop().GetInteger(); + Limits.AssertShift(shift); + if (shift == 0) break; + var x = Pop().GetInteger(); + Push(x >> shift); + break; + } + case OpCode.NOT: + { + var x = Pop().GetBoolean(); + Push(!x); + break; + } + case OpCode.BOOLAND: + { + var x2 = Pop().GetBoolean(); + var x1 = Pop().GetBoolean(); + Push(x1 && x2); + break; + } + case OpCode.BOOLOR: + { + var x2 = Pop().GetBoolean(); + var x1 = Pop().GetBoolean(); + Push(x1 || x2); + break; + } + case OpCode.NZ: + { + var x = Pop().GetInteger(); + Push(!x.IsZero); + break; + } + case OpCode.NUMEQUAL: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 == x2); + break; + } + case OpCode.NUMNOTEQUAL: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 != x2); + break; + } + case OpCode.LT: + { + var x2 = Pop(); + var x1 = Pop(); + if (x1.IsNull || x2.IsNull) + Push(false); + else + Push(x1.GetInteger() < x2.GetInteger()); + break; + } + case OpCode.LE: + { + var x2 = Pop(); + var x1 = Pop(); + if (x1.IsNull || x2.IsNull) + Push(false); + else + Push(x1.GetInteger() <= x2.GetInteger()); + break; + } + case OpCode.GT: + { + var x2 = Pop(); + var x1 = Pop(); + if (x1.IsNull || x2.IsNull) + Push(false); + else + Push(x1.GetInteger() > x2.GetInteger()); + break; + } + case OpCode.GE: + { + var x2 = Pop(); + var x1 = Pop(); + if (x1.IsNull || x2.IsNull) + Push(false); + else + Push(x1.GetInteger() >= x2.GetInteger()); + break; + } + case OpCode.MIN: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(BigInteger.Min(x1, x2)); + break; + } + case OpCode.MAX: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(BigInteger.Max(x1, x2)); + break; + } + case OpCode.WITHIN: + { + BigInteger b = Pop().GetInteger(); + BigInteger a = Pop().GetInteger(); + var x = Pop().GetInteger(); + Push(a <= x && x < b); + break; + } + + // Compound-type + case OpCode.PACKMAP: + { + int size = (int)Pop().GetInteger(); + if (size < 0 || size * 2 > CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + Map map = new(ReferenceCounter); + for (int i = 0; i < size; i++) + { + PrimitiveType key = Pop(); + StackItem value = Pop(); + map[key] = value; + } + Push(map); + break; + } + case OpCode.PACKSTRUCT: + { + int size = (int)Pop().GetInteger(); + if (size < 0 || size > CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + Struct @struct = new(ReferenceCounter); + for (int i = 0; i < size; i++) + { + StackItem item = Pop(); + @struct.Add(item); + } + Push(@struct); + break; + } + case OpCode.PACK: + { + int size = (int)Pop().GetInteger(); + if (size < 0 || size > CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + VMArray array = new(ReferenceCounter); + for (int i = 0; i < size; i++) + { + StackItem item = Pop(); + array.Add(item); + } + Push(array); + break; + } + case OpCode.UNPACK: + { + CompoundType compound = Pop(); + switch (compound) + { + case Map map: + foreach (var (key, value) in map.Reverse()) + { + Push(value); + Push(key); + } + break; + case VMArray array: + for (int i = array.Count - 1; i >= 0; i--) + { + Push(array[i]); + } + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {compound.Type}"); + } + Push(compound.Count); + break; + } + case OpCode.NEWARRAY0: + { + Push(new VMArray(ReferenceCounter)); + break; + } + case OpCode.NEWARRAY: + case OpCode.NEWARRAY_T: + { + int n = (int)Pop().GetInteger(); + if (n < 0 || n > Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {n}"); + StackItem item; + if (instruction.OpCode == OpCode.NEWARRAY_T) + { + StackItemType type = (StackItemType)instruction.TokenU8; + if (!Enum.IsDefined(typeof(StackItemType), type)) + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {instruction.TokenU8}"); + item = instruction.TokenU8 switch + { + (byte)StackItemType.Boolean => StackItem.False, + (byte)StackItemType.Integer => Integer.Zero, + (byte)StackItemType.ByteString => ByteString.Empty, + _ => StackItem.Null + }; + } + else + { + item = StackItem.Null; + } + Push(new VMArray(ReferenceCounter, Enumerable.Repeat(item, n))); + break; + } + case OpCode.NEWSTRUCT0: + { + Push(new Struct(ReferenceCounter)); + break; + } + case OpCode.NEWSTRUCT: + { + int n = (int)Pop().GetInteger(); + if (n < 0 || n > Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {n}"); + Struct result = new(ReferenceCounter); + for (var i = 0; i < n; i++) + result.Add(StackItem.Null); + Push(result); + break; + } + case OpCode.NEWMAP: + { + Push(new Map(ReferenceCounter)); + break; + } + case OpCode.SIZE: + { + var x = Pop(); + switch (x) + { + case CompoundType compound: + Push(compound.Count); + break; + case PrimitiveType primitive: + Push(primitive.Size); + break; + case Buffer buffer: + Push(buffer.Size); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.HASKEY: + { + PrimitiveType key = Pop(); + var x = Pop(); + switch (x) + { + case VMArray array: + { + int index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + Push(index < array.Count); + break; + } + case Map map: + { + Push(map.ContainsKey(key)); + break; + } + case Buffer buffer: + { + int index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + Push(index < buffer.Size); + break; + } + case ByteString array: + { + int index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + Push(index < array.Size); + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.KEYS: + { + Map map = Pop(); + Push(new VMArray(ReferenceCounter, map.Keys)); + break; + } + case OpCode.VALUES: + { + var x = Pop(); + IEnumerable values = x switch + { + VMArray array => array, + Map map => map.Values, + _ => throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"), + }; + VMArray newArray = new(ReferenceCounter); + foreach (StackItem item in values) + if (item is Struct s) + newArray.Add(s.Clone(Limits)); + else + newArray.Add(item); + Push(newArray); + break; + } + case OpCode.PICKITEM: + { + PrimitiveType key = Pop(); + var x = Pop(); + switch (x) + { + case VMArray array: + { + int index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new CatchableException($"The value {index} is out of range."); + Push(array[index]); + break; + } + case Map map: + { + if (!map.TryGetValue(key, out StackItem? value)) + throw new CatchableException($"Key not found in {nameof(Map)}"); + Push(value); + break; + } + case PrimitiveType primitive: + { + ReadOnlySpan byteArray = primitive.GetSpan(); + int index = (int)key.GetInteger(); + if (index < 0 || index >= byteArray.Length) + throw new CatchableException($"The value {index} is out of range."); + Push((BigInteger)byteArray[index]); + break; + } + case Buffer buffer: + { + int index = (int)key.GetInteger(); + if (index < 0 || index >= buffer.Size) + throw new CatchableException($"The value {index} is out of range."); + Push((BigInteger)buffer.InnerBuffer.Span[index]); + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.APPEND: + { + StackItem newItem = Pop(); + VMArray array = Pop(); + if (newItem is Struct s) newItem = s.Clone(Limits); + array.Add(newItem); + break; + } + case OpCode.SETITEM: + { + StackItem value = Pop(); + if (value is Struct s) value = s.Clone(Limits); + PrimitiveType key = Pop(); + var x = Pop(); + switch (x) + { + case VMArray array: + { + int index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new CatchableException($"The value {index} is out of range."); + array[index] = value; + break; + } + case Map map: + { + map[key] = value; + break; + } + case Buffer buffer: + { + int index = (int)key.GetInteger(); + if (index < 0 || index >= buffer.Size) + throw new CatchableException($"The value {index} is out of range."); + if (value is not PrimitiveType p) + throw new InvalidOperationException($"Value must be a primitive type in {instruction.OpCode}"); + int b = (int)p.GetInteger(); + if (b < sbyte.MinValue || b > byte.MaxValue) + throw new InvalidOperationException($"Overflow in {instruction.OpCode}, {b} is not a byte type."); + buffer.InnerBuffer.Span[index] = (byte)b; + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.REVERSEITEMS: + { + var x = Pop(); + switch (x) + { + case VMArray array: + array.Reverse(); + break; + case Buffer buffer: + buffer.InnerBuffer.Span.Reverse(); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.REMOVE: + { + PrimitiveType key = Pop(); + var x = Pop(); + switch (x) + { + case VMArray array: + int index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new InvalidOperationException($"The value {index} is out of range."); + array.RemoveAt(index); + break; + case Map map: + map.Remove(key); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.CLEARITEMS: + { + CompoundType x = Pop(); + x.Clear(); + break; + } + case OpCode.POPITEM: + { + VMArray x = Pop(); + int index = x.Count - 1; + Push(x[index]); + x.RemoveAt(index); + break; + } + + //Types + case OpCode.ISNULL: + { + var x = Pop(); + Push(x.IsNull); + break; + } + case OpCode.ISTYPE: + { + var x = Pop(); + StackItemType type = (StackItemType)instruction.TokenU8; + if (type == StackItemType.Any || !Enum.IsDefined(typeof(StackItemType), type)) + throw new InvalidOperationException($"Invalid type: {type}"); + Push(x.Type == type); + break; + } + case OpCode.CONVERT: + { + var x = Pop(); + Push(x.ConvertTo((StackItemType)instruction.TokenU8)); + break; + } + case OpCode.ABORTMSG: + { + var msg = Pop().GetString(); + throw new Exception($"{OpCode.ABORTMSG} is executed. Reason: {msg}"); + } + case OpCode.ASSERTMSG: + { + var msg = Pop().GetString(); + var x = Pop().GetBoolean(); + if (!x) + throw new Exception($"{OpCode.ASSERTMSG} is executed with false result. Reason: {msg}"); + break; + } + default: throw new InvalidOperationException($"Opcode {instruction.OpCode} is undefined."); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ExecuteEndTry(int endOffset) + { + if (CurrentContext!.TryStack is null) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (!CurrentContext.TryStack.TryPeek(out ExceptionHandlingContext? currentTry)) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (currentTry.State == ExceptionHandlingState.Finally) + throw new InvalidOperationException($"The opcode {OpCode.ENDTRY} can't be executed in a FINALLY block."); + + int endPointer = checked(CurrentContext.InstructionPointer + endOffset); + if (currentTry.HasFinally) + { + currentTry.State = ExceptionHandlingState.Finally; + currentTry.EndPointer = endPointer; + CurrentContext.InstructionPointer = currentTry.FinallyPointer; + } + else + { + CurrentContext.TryStack.Pop(); + CurrentContext.InstructionPointer = endPointer; + } + isJumping = true; + } + + /// + /// Jump to the specified position. + /// + /// The position to jump to. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void ExecuteJump(int position) + { + if (position < 0 || position >= CurrentContext!.Script.Length) + throw new ArgumentOutOfRangeException($"Jump out of range for position: {position}"); + CurrentContext.InstructionPointer = position; + isJumping = true; + } + + /// + /// Jump to the specified offset from the current position. + /// + /// The offset from the current position to jump to. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void ExecuteJumpOffset(int offset) + { + ExecuteJump(checked(CurrentContext!.InstructionPointer + offset)); + } + + private void ExecuteLoadFromSlot(Slot? slot, int index) + { + if (slot is null) + throw new InvalidOperationException("Slot has not been initialized."); + if (index < 0 || index >= slot.Count) + throw new InvalidOperationException($"Index out of range when loading from slot: {index}"); + Push(slot[index]); + } + + /// + /// Execute the next instruction. + /// + internal protected void ExecuteNext() + { + if (InvocationStack.Count == 0) + { + State = VMState.HALT; + } + else + { + try + { + ExecutionContext context = CurrentContext!; + Instruction instruction = context.CurrentInstruction ?? Instruction.RET; + PreExecuteInstruction(instruction); + try + { + ExecuteInstruction(instruction); + } + catch (CatchableException ex) when (Limits.CatchEngineExceptions) + { + ExecuteThrow(ex.Message); + } + PostExecuteInstruction(instruction); + if (!isJumping) context.MoveNext(); + isJumping = false; + } + catch (Exception e) + { + OnFault(e); + } + } + } + + private void ExecuteStoreToSlot(Slot? slot, int index) + { + if (slot is null) + throw new InvalidOperationException("Slot has not been initialized."); + if (index < 0 || index >= slot.Count) + throw new InvalidOperationException($"Index out of range when storing to slot: {index}"); + slot[index] = Pop(); + } + + /// + /// Throws a specified exception in the VM. + /// + /// The exception to be thrown. + protected void ExecuteThrow(StackItem ex) + { + UncaughtException = ex; + HandleException(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ExecuteTry(int catchOffset, int finallyOffset) + { + if (catchOffset == 0 && finallyOffset == 0) + throw new InvalidOperationException($"catchOffset and finallyOffset can't be 0 in a TRY block"); + if (CurrentContext!.TryStack is null) + CurrentContext.TryStack = new Stack(); + else if (CurrentContext.TryStack.Count >= Limits.MaxTryNestingDepth) + throw new InvalidOperationException("MaxTryNestingDepth exceed."); + int catchPointer = catchOffset == 0 ? -1 : checked(CurrentContext.InstructionPointer + catchOffset); + int finallyPointer = finallyOffset == 0 ? -1 : checked(CurrentContext.InstructionPointer + finallyOffset); + CurrentContext.TryStack.Push(new ExceptionHandlingContext(catchPointer, finallyPointer)); + } + + private void HandleException() + { + int pop = 0; + foreach (var executionContext in InvocationStack) + { + if (executionContext.TryStack != null) + { + while (executionContext.TryStack.TryPeek(out var tryContext)) + { + if (tryContext.State == ExceptionHandlingState.Finally || (tryContext.State == ExceptionHandlingState.Catch && !tryContext.HasFinally)) + { + executionContext.TryStack.Pop(); + continue; + } + for (int i = 0; i < pop; i++) + { + ContextUnloaded(InvocationStack.Pop()); + } + if (tryContext.State == ExceptionHandlingState.Try && tryContext.HasCatch) + { + tryContext.State = ExceptionHandlingState.Catch; + Push(UncaughtException!); + executionContext.InstructionPointer = tryContext.CatchPointer; + UncaughtException = null; + } + else + { + tryContext.State = ExceptionHandlingState.Finally; + executionContext.InstructionPointer = tryContext.FinallyPointer; + } + isJumping = true; + return; + } + } + ++pop; + } + + throw new VMUnhandledException(UncaughtException!); + } + + /// + /// Loads the specified context into the invocation stack. + /// + /// The context to load. + protected virtual void LoadContext(ExecutionContext context) + { + if (InvocationStack.Count >= Limits.MaxInvocationStackSize) + throw new InvalidOperationException($"MaxInvocationStackSize exceed: {InvocationStack.Count}"); + InvocationStack.Push(context); + if (EntryContext is null) EntryContext = context; + CurrentContext = context; + } + + /// + /// Create a new context with the specified script without loading. + /// + /// The script used to create the context. + /// The number of values that the context should return when it is unloaded. + /// The pointer indicating the current instruction. + /// The created context. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected ExecutionContext CreateContext(Script script, int rvcount, int initialPosition) + { + return new ExecutionContext(script, rvcount, ReferenceCounter) + { + InstructionPointer = initialPosition + }; + } + + /// + /// Create a new context with the specified script and load it. + /// + /// The script used to create the context. + /// The number of values that the context should return when it is unloaded. + /// The pointer indicating the current instruction. + /// The created context. + public ExecutionContext LoadScript(Script script, int rvcount = -1, int initialPosition = 0) + { + ExecutionContext context = CreateContext(script, rvcount, initialPosition); + LoadContext(context); + return context; + } + + /// + /// When overridden in a derived class, loads the specified method token. + /// Called when is executed. + /// + /// The method token to be loaded. + /// The created context. + protected virtual ExecutionContext LoadToken(ushort token) + { + throw new InvalidOperationException($"Token not found: {token}"); + } + + /// + /// Called when an exception that cannot be caught by the VM is thrown. + /// + /// The exception that caused the state. + protected virtual void OnFault(Exception ex) + { + State = VMState.FAULT; + } + + /// + /// Called when the state of the VM changed. + /// + protected virtual void OnStateChanged() + { + } + + /// + /// When overridden in a derived class, invokes the specified system call. + /// Called when is executed. + /// + /// The system call to be invoked. + protected virtual void OnSysCall(uint method) + { + throw new InvalidOperationException($"Syscall not found: {method}"); + } + + /// + /// Returns the item at the specified index from the top of the current stack without removing it. + /// + /// The index of the object from the top of the stack. + /// The item at the specified index. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackItem Peek(int index = 0) + { + return CurrentContext!.EvaluationStack.Peek(index); + } + + /// + /// Removes and returns the item at the top of the current stack. + /// + /// The item removed from the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackItem Pop() + { + return CurrentContext!.EvaluationStack.Pop(); + } + + /// + /// Removes and returns the item at the top of the current stack and convert it to the specified type. + /// + /// The type to convert to. + /// The item removed from the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Pop() where T : StackItem + { + return CurrentContext!.EvaluationStack.Pop(); + } + + /// + /// Called after an instruction is executed. + /// + protected virtual void PostExecuteInstruction(Instruction instruction) + { + if (ReferenceCounter.CheckZeroReferred() > Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {ReferenceCounter.Count}"); + } + + /// + /// Called before an instruction is executed. + /// + protected virtual void PreExecuteInstruction(Instruction instruction) { } + + /// + /// Pushes an item onto the top of the current stack. + /// + /// The item to be pushed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(StackItem item) + { + CurrentContext!.EvaluationStack.Push(item); + } + } +} diff --git a/src/Neo.VM/ExecutionEngineLimits.cs b/src/Neo.VM/ExecutionEngineLimits.cs new file mode 100644 index 0000000000..f31b40e5a1 --- /dev/null +++ b/src/Neo.VM/ExecutionEngineLimits.cs @@ -0,0 +1,87 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Represents the restrictions on the VM. + /// + public sealed record ExecutionEngineLimits + { + /// + /// The default strategy. + /// + public static readonly ExecutionEngineLimits Default = new(); + + /// + /// The maximum number of bits that and can shift. + /// + public int MaxShift { get; init; } = 256; + + /// + /// The maximum number of items that can be contained in the VM's evaluation stacks and slots. + /// + public uint MaxStackSize { get; init; } = 2 * 1024; + + /// + /// The maximum size of an item in the VM. + /// + public uint MaxItemSize { get; init; } = ushort.MaxValue * 2; + + /// + /// The largest comparable size. If a or exceeds this size, comparison operations on it cannot be performed in the VM. + /// + public uint MaxComparableSize { get; init; } = 65536; + + /// + /// The maximum number of frames in the invocation stack of the VM. + /// + public uint MaxInvocationStackSize { get; init; } = 1024; + + /// + /// The maximum nesting depth of -- blocks. + /// + public uint MaxTryNestingDepth { get; init; } = 16; + + /// + /// Allow to catch the ExecutionEngine Exceptions + /// + public bool CatchEngineExceptions { get; init; } = true; + + /// + /// Assert that the size of the item meets the limit. + /// + /// The size to be checked. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AssertMaxItemSize(int size) + { + if (size < 0 || size > MaxItemSize) + { + throw new InvalidOperationException($"MaxItemSize exceed: {size}"); + } + } + + /// + /// Assert that the number of bits shifted meets the limit. + /// + /// The number of bits shifted. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AssertShift(int shift) + { + if (shift > MaxShift || shift < 0) + { + throw new InvalidOperationException($"Invalid shift value: {shift}"); + } + } + } +} diff --git a/src/Neo.VM/GlobalSuppressions.cs b/src/Neo.VM/GlobalSuppressions.cs new file mode 100644 index 0000000000..12194f733e --- /dev/null +++ b/src/Neo.VM/GlobalSuppressions.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Usage", "CA1816")] diff --git a/src/Neo.VM/Instruction.cs b/src/Neo.VM/Instruction.cs new file mode 100644 index 0000000000..48b48c94a3 --- /dev/null +++ b/src/Neo.VM/Instruction.cs @@ -0,0 +1,234 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Buffers.Binary; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Neo.VM +{ + /// + /// Represents instructions in the VM script. + /// + [DebuggerDisplay("OpCode={OpCode}")] + public class Instruction + { + /// + /// Represents the instruction with . + /// + public static Instruction RET { get; } = new Instruction(OpCode.RET); + + /// + /// The of the instruction. + /// + public readonly OpCode OpCode; + + /// + /// The operand of the instruction. + /// + public readonly ReadOnlyMemory Operand; + + private static readonly int[] OperandSizePrefixTable = new int[256]; + private static readonly int[] OperandSizeTable = new int[256]; + + /// + /// Gets the size of the instruction. + /// + public int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + int prefixSize = OperandSizePrefixTable[(int)OpCode]; + return prefixSize > 0 + ? 1 + prefixSize + Operand.Length + : 1 + OperandSizeTable[(int)OpCode]; + } + } + + /// + /// Gets the first operand as . + /// + public short TokenI16 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadInt16LittleEndian(Operand.Span); + } + } + + /// + /// Gets the first operand as . + /// + public int TokenI32 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadInt32LittleEndian(Operand.Span); + } + } + + /// + /// Gets the second operand as . + /// + public int TokenI32_1 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadInt32LittleEndian(Operand.Span[4..]); + } + } + + /// + /// Gets the first operand as . + /// + public sbyte TokenI8 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return (sbyte)Operand.Span[0]; + } + } + + /// + /// Gets the second operand as . + /// + public sbyte TokenI8_1 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return (sbyte)Operand.Span[1]; + } + } + + /// + /// Gets the operand as . + /// + public string TokenString + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Encoding.ASCII.GetString(Operand.Span); + } + } + + /// + /// Gets the first operand as . + /// + public ushort TokenU16 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadUInt16LittleEndian(Operand.Span); + } + } + + /// + /// Gets the first operand as . + /// + public uint TokenU32 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadUInt32LittleEndian(Operand.Span); + } + } + + /// + /// Gets the first operand as . + /// + public byte TokenU8 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Operand.Span[0]; + } + } + + /// + /// Gets the second operand as . + /// + public byte TokenU8_1 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Operand.Span[1]; + } + } + + static Instruction() + { + foreach (FieldInfo field in typeof(OpCode).GetFields(BindingFlags.Public | BindingFlags.Static)) + { + OperandSizeAttribute? attribute = field.GetCustomAttribute(); + if (attribute == null) continue; + int index = (int)(OpCode)field.GetValue(null)!; + OperandSizePrefixTable[index] = attribute.SizePrefix; + OperandSizeTable[index] = attribute.Size; + } + } + + private Instruction(OpCode opcode) + { + this.OpCode = opcode; + if (!Enum.IsDefined(typeof(OpCode), opcode)) throw new BadScriptException(); + } + + internal Instruction(ReadOnlyMemory script, int ip) : this((OpCode)script.Span[ip++]) + { + ReadOnlySpan span = script.Span; + int operandSizePrefix = OperandSizePrefixTable[(int)OpCode]; + int operandSize = 0; + switch (operandSizePrefix) + { + case 0: + operandSize = OperandSizeTable[(int)OpCode]; + break; + case 1: + if (ip >= span.Length) + throw new BadScriptException($"Instruction out of bounds. InstructionPointer: {ip}"); + operandSize = span[ip]; + break; + case 2: + if (ip + 1 >= span.Length) + throw new BadScriptException($"Instruction out of bounds. InstructionPointer: {ip}"); + operandSize = BinaryPrimitives.ReadUInt16LittleEndian(span[ip..]); + break; + case 4: + if (ip + 3 >= span.Length) + throw new BadScriptException($"Instruction out of bounds. InstructionPointer: {ip}"); + operandSize = BinaryPrimitives.ReadInt32LittleEndian(span[ip..]); + if (operandSize < 0) + throw new BadScriptException($"Instruction out of bounds. InstructionPointer: {ip}, operandSize: {operandSize}"); + break; + } + ip += operandSizePrefix; + if (operandSize > 0) + { + if (ip + operandSize > script.Length) + throw new BadScriptException($"Instrucion out of bounds. InstructionPointer: {ip}, operandSize: {operandSize}, length: {script.Length}"); + Operand = script.Slice(ip, operandSize); + } + } + } +} diff --git a/src/Neo.VM/IsExternalInit.cs b/src/Neo.VM/IsExternalInit.cs new file mode 100644 index 0000000000..874f5f76ce --- /dev/null +++ b/src/Neo.VM/IsExternalInit.cs @@ -0,0 +1,17 @@ +#if !NET5_0_OR_GREATER + +using System.ComponentModel; + +namespace System.Runtime.CompilerServices +{ + /// + /// Reserved to be used by the compiler for tracking metadata. + /// This class should not be used by developers in source code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class IsExternalInit + { + } +} + +#endif diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj new file mode 100644 index 0000000000..5e7e071b22 --- /dev/null +++ b/src/Neo.VM/Neo.VM.csproj @@ -0,0 +1,9 @@ + + + + netstandard2.1;net7.0 + true + enable + + + diff --git a/src/Neo.VM/OpCode.cs b/src/Neo.VM/OpCode.cs new file mode 100644 index 0000000000..313e04a7d1 --- /dev/null +++ b/src/Neo.VM/OpCode.cs @@ -0,0 +1,905 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Types; + +namespace Neo.VM +{ + /// + /// Represents the opcode of an . + /// + public enum OpCode : byte + { + #region Constants + + /// + /// Pushes a 1-byte signed integer onto the stack. + /// + [OperandSize(Size = 1)] + PUSHINT8 = 0x00, + /// + /// Pushes a 2-bytes signed integer onto the stack. + /// + [OperandSize(Size = 2)] + PUSHINT16 = 0x01, + /// + /// Pushes a 4-bytes signed integer onto the stack. + /// + [OperandSize(Size = 4)] + PUSHINT32 = 0x02, + /// + /// Pushes a 8-bytes signed integer onto the stack. + /// + [OperandSize(Size = 8)] + PUSHINT64 = 0x03, + /// + /// Pushes a 16-bytes signed integer onto the stack. + /// + [OperandSize(Size = 16)] + PUSHINT128 = 0x04, + /// + /// Pushes a 32-bytes signed integer onto the stack. + /// + [OperandSize(Size = 32)] + PUSHINT256 = 0x05, + /// + /// Pushes the boolean value onto the stack. + /// + PUSHT = 0x08, + /// + /// Pushes the boolean value onto the stack. + /// + PUSHF = 0x09, + /// + /// Converts the 4-bytes offset to an , and pushes it onto the stack. + /// + [OperandSize(Size = 4)] + PUSHA = 0x0A, + /// + /// The item is pushed onto the stack. + /// + PUSHNULL = 0x0B, + /// + /// The next byte contains the number of bytes to be pushed onto the stack. + /// + [OperandSize(SizePrefix = 1)] + PUSHDATA1 = 0x0C, + /// + /// The next two bytes contain the number of bytes to be pushed onto the stack. + /// + [OperandSize(SizePrefix = 2)] + PUSHDATA2 = 0x0D, + /// + /// The next four bytes contain the number of bytes to be pushed onto the stack. + /// + [OperandSize(SizePrefix = 4)] + PUSHDATA4 = 0x0E, + /// + /// The number -1 is pushed onto the stack. + /// + PUSHM1 = 0x0F, + /// + /// The number 0 is pushed onto the stack. + /// + PUSH0 = 0x10, + /// + /// The number 1 is pushed onto the stack. + /// + PUSH1 = 0x11, + /// + /// The number 2 is pushed onto the stack. + /// + PUSH2 = 0x12, + /// + /// The number 3 is pushed onto the stack. + /// + PUSH3 = 0x13, + /// + /// The number 4 is pushed onto the stack. + /// + PUSH4 = 0x14, + /// + /// The number 5 is pushed onto the stack. + /// + PUSH5 = 0x15, + /// + /// The number 6 is pushed onto the stack. + /// + PUSH6 = 0x16, + /// + /// The number 7 is pushed onto the stack. + /// + PUSH7 = 0x17, + /// + /// The number 8 is pushed onto the stack. + /// + PUSH8 = 0x18, + /// + /// The number 9 is pushed onto the stack. + /// + PUSH9 = 0x19, + /// + /// The number 10 is pushed onto the stack. + /// + PUSH10 = 0x1A, + /// + /// The number 11 is pushed onto the stack. + /// + PUSH11 = 0x1B, + /// + /// The number 12 is pushed onto the stack. + /// + PUSH12 = 0x1C, + /// + /// The number 13 is pushed onto the stack. + /// + PUSH13 = 0x1D, + /// + /// The number 14 is pushed onto the stack. + /// + PUSH14 = 0x1E, + /// + /// The number 15 is pushed onto the stack. + /// + PUSH15 = 0x1F, + /// + /// The number 16 is pushed onto the stack. + /// + PUSH16 = 0x20, + + #endregion + + #region Flow control + + /// + /// The operation does nothing. It is intended to fill in space if opcodes are patched. + /// + NOP = 0x21, + /// + /// Unconditionally transfers control to a target instruction. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMP = 0x22, + /// + /// Unconditionally transfers control to a target instruction. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMP_L = 0x23, + /// + /// Transfers control to a target instruction if the value is , not , or non-zero. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMPIF = 0x24, + /// + /// Transfers control to a target instruction if the value is , not , or non-zero. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMPIF_L = 0x25, + /// + /// Transfers control to a target instruction if the value is , a reference, or zero. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMPIFNOT = 0x26, + /// + /// Transfers control to a target instruction if the value is , a reference, or zero. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMPIFNOT_L = 0x27, + /// + /// Transfers control to a target instruction if two values are equal. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMPEQ = 0x28, + /// + /// Transfers control to a target instruction if two values are equal. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMPEQ_L = 0x29, + /// + /// Transfers control to a target instruction when two values are not equal. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMPNE = 0x2A, + /// + /// Transfers control to a target instruction when two values are not equal. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMPNE_L = 0x2B, + /// + /// Transfers control to a target instruction if the first value is greater than the second value. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMPGT = 0x2C, + /// + /// Transfers control to a target instruction if the first value is greater than the second value. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMPGT_L = 0x2D, + /// + /// Transfers control to a target instruction if the first value is greater than or equal to the second value. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMPGE = 0x2E, + /// + /// Transfers control to a target instruction if the first value is greater than or equal to the second value. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMPGE_L = 0x2F, + /// + /// Transfers control to a target instruction if the first value is less than the second value. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMPLT = 0x30, + /// + /// Transfers control to a target instruction if the first value is less than the second value. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMPLT_L = 0x31, + /// + /// Transfers control to a target instruction if the first value is less than or equal to the second value. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + JMPLE = 0x32, + /// + /// Transfers control to a target instruction if the first value is less than or equal to the second value. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + JMPLE_L = 0x33, + /// + /// Calls the function at the target address which is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + CALL = 0x34, + /// + /// Calls the function at the target address which is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + CALL_L = 0x35, + /// + /// Pop the address of a function from the stack, and call the function. + /// + CALLA = 0x36, + /// + /// Calls the function which is described by the token. + /// + [OperandSize(Size = 2)] + CALLT = 0x37, + /// + /// It turns the vm state to FAULT immediately, and cannot be caught. + /// + ABORT = 0x38, + /// + /// Pop the top value of the stack. If it's false, exit vm execution and set vm state to FAULT. + /// + ASSERT = 0x39, + /// + /// Pop the top value of the stack, and throw it. + /// + THROW = 0x3A, + /// + /// TRY CatchOffset(sbyte) FinallyOffset(sbyte). If there's no catch body, set CatchOffset 0. If there's no finally body, set FinallyOffset 0. + /// + [OperandSize(Size = 2)] + TRY = 0x3B, + /// + /// TRY_L CatchOffset(int) FinallyOffset(int). If there's no catch body, set CatchOffset 0. If there's no finally body, set FinallyOffset 0. + /// + [OperandSize(Size = 8)] + TRY_L = 0x3C, + /// + /// Ensures that the appropriate surrounding finally blocks are executed. And then unconditionally transfers control to the specific target instruction, represented as a 1-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 1)] + ENDTRY = 0x3D, + /// + /// Ensures that the appropriate surrounding finally blocks are executed. And then unconditionally transfers control to the specific target instruction, represented as a 4-byte signed offset from the beginning of the current instruction. + /// + [OperandSize(Size = 4)] + ENDTRY_L = 0x3E, + /// + /// End finally, If no exception happen or be catched, vm will jump to the target instruction of ENDTRY/ENDTRY_L. Otherwise vm will rethrow the exception to upper layer. + /// + ENDFINALLY = 0x3F, + /// + /// Returns from the current method. + /// + RET = 0x40, + /// + /// Calls to an interop service. + /// + [OperandSize(Size = 4)] + SYSCALL = 0x41, + + #endregion + + #region Stack + + /// + /// Puts the number of stack items onto the stack. + /// + DEPTH = 0x43, + /// + /// Removes the top stack item. + /// + DROP = 0x45, + /// + /// Removes the second-to-top stack item. + /// + NIP = 0x46, + /// + /// The item n back in the main stack is removed. + /// + XDROP = 0x48, + /// + /// Clear the stack + /// + CLEAR = 0x49, + /// + /// Duplicates the top stack item. + /// + DUP = 0x4A, + /// + /// Copies the second-to-top stack item to the top. + /// + OVER = 0x4B, + /// + /// The item n back in the stack is copied to the top. + /// + PICK = 0x4D, + /// + /// The item at the top of the stack is copied and inserted before the second-to-top item. + /// + TUCK = 0x4E, + /// + /// The top two items on the stack are swapped. + /// + SWAP = 0x50, + /// + /// The top three items on the stack are rotated to the left. + /// + ROT = 0x51, + /// + /// The item n back in the stack is moved to the top. + /// + ROLL = 0x52, + /// + /// Reverse the order of the top 3 items on the stack. + /// + REVERSE3 = 0x53, + /// + /// Reverse the order of the top 4 items on the stack. + /// + REVERSE4 = 0x54, + /// + /// Pop the number N on the stack, and reverse the order of the top N items on the stack. + /// + REVERSEN = 0x55, + + #endregion + + #region Slot + + /// + /// Initialize the static field list for the current execution context. + /// + [OperandSize(Size = 1)] + INITSSLOT = 0x56, + /// + /// Initialize the argument slot and the local variable list for the current execution context. + /// + [OperandSize(Size = 2)] + INITSLOT = 0x57, + /// + /// Loads the static field at index 0 onto the evaluation stack. + /// + LDSFLD0 = 0x58, + /// + /// Loads the static field at index 1 onto the evaluation stack. + /// + LDSFLD1 = 0x59, + /// + /// Loads the static field at index 2 onto the evaluation stack. + /// + LDSFLD2 = 0x5A, + /// + /// Loads the static field at index 3 onto the evaluation stack. + /// + LDSFLD3 = 0x5B, + /// + /// Loads the static field at index 4 onto the evaluation stack. + /// + LDSFLD4 = 0x5C, + /// + /// Loads the static field at index 5 onto the evaluation stack. + /// + LDSFLD5 = 0x5D, + /// + /// Loads the static field at index 6 onto the evaluation stack. + /// + LDSFLD6 = 0x5E, + /// + /// Loads the static field at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + LDSFLD = 0x5F, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 0. + /// + STSFLD0 = 0x60, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 1. + /// + STSFLD1 = 0x61, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 2. + /// + STSFLD2 = 0x62, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 3. + /// + STSFLD3 = 0x63, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 4. + /// + STSFLD4 = 0x64, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 5. + /// + STSFLD5 = 0x65, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 6. + /// + STSFLD6 = 0x66, + /// + /// Stores the value on top of the evaluation stack in the static field list at a specified index. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + STSFLD = 0x67, + /// + /// Loads the local variable at index 0 onto the evaluation stack. + /// + LDLOC0 = 0x68, + /// + /// Loads the local variable at index 1 onto the evaluation stack. + /// + LDLOC1 = 0x69, + /// + /// Loads the local variable at index 2 onto the evaluation stack. + /// + LDLOC2 = 0x6A, + /// + /// Loads the local variable at index 3 onto the evaluation stack. + /// + LDLOC3 = 0x6B, + /// + /// Loads the local variable at index 4 onto the evaluation stack. + /// + LDLOC4 = 0x6C, + /// + /// Loads the local variable at index 5 onto the evaluation stack. + /// + LDLOC5 = 0x6D, + /// + /// Loads the local variable at index 6 onto the evaluation stack. + /// + LDLOC6 = 0x6E, + /// + /// Loads the local variable at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + LDLOC = 0x6F, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 0. + /// + STLOC0 = 0x70, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 1. + /// + STLOC1 = 0x71, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 2. + /// + STLOC2 = 0x72, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 3. + /// + STLOC3 = 0x73, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 4. + /// + STLOC4 = 0x74, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 5. + /// + STLOC5 = 0x75, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 6. + /// + STLOC6 = 0x76, + /// + /// Stores the value on top of the evaluation stack in the local variable list at a specified index. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + STLOC = 0x77, + /// + /// Loads the argument at index 0 onto the evaluation stack. + /// + LDARG0 = 0x78, + /// + /// Loads the argument at index 1 onto the evaluation stack. + /// + LDARG1 = 0x79, + /// + /// Loads the argument at index 2 onto the evaluation stack. + /// + LDARG2 = 0x7A, + /// + /// Loads the argument at index 3 onto the evaluation stack. + /// + LDARG3 = 0x7B, + /// + /// Loads the argument at index 4 onto the evaluation stack. + /// + LDARG4 = 0x7C, + /// + /// Loads the argument at index 5 onto the evaluation stack. + /// + LDARG5 = 0x7D, + /// + /// Loads the argument at index 6 onto the evaluation stack. + /// + LDARG6 = 0x7E, + /// + /// Loads the argument at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + LDARG = 0x7F, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 0. + /// + STARG0 = 0x80, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 1. + /// + STARG1 = 0x81, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 2. + /// + STARG2 = 0x82, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 3. + /// + STARG3 = 0x83, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 4. + /// + STARG4 = 0x84, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 5. + /// + STARG5 = 0x85, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 6. + /// + STARG6 = 0x86, + /// + /// Stores the value on top of the evaluation stack in the argument slot at a specified index. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + STARG = 0x87, + + #endregion + + #region Splice + + /// + /// Creates a new and pushes it onto the stack. + /// + NEWBUFFER = 0x88, + /// + /// Copies a range of bytes from one to another. + /// + MEMCPY = 0x89, + /// + /// Concatenates two strings. + /// + CAT = 0x8B, + /// + /// Returns a section of a string. + /// + SUBSTR = 0x8C, + /// + /// Keeps only characters left of the specified point in a string. + /// + LEFT = 0x8D, + /// + /// Keeps only characters right of the specified point in a string. + /// + RIGHT = 0x8E, + + #endregion + + #region Bitwise logic + + /// + /// Flips all of the bits in the input. + /// + INVERT = 0x90, + /// + /// Boolean and between each bit in the inputs. + /// + AND = 0x91, + /// + /// Boolean or between each bit in the inputs. + /// + OR = 0x92, + /// + /// Boolean exclusive or between each bit in the inputs. + /// + XOR = 0x93, + /// + /// Returns 1 if the inputs are exactly equal, 0 otherwise. + /// + EQUAL = 0x97, + /// + /// Returns 1 if the inputs are not equal, 0 otherwise. + /// + NOTEQUAL = 0x98, + + #endregion + + #region Arithmetic + + /// + /// Puts the sign of top stack item on top of the main stack. If value is negative, put -1; if positive, put 1; if value is zero, put 0. + /// + SIGN = 0x99, + /// + /// The input is made positive. + /// + ABS = 0x9A, + /// + /// The sign of the input is flipped. + /// + NEGATE = 0x9B, + /// + /// 1 is added to the input. + /// + INC = 0x9C, + /// + /// 1 is subtracted from the input. + /// + DEC = 0x9D, + /// + /// a is added to b. + /// + ADD = 0x9E, + /// + /// b is subtracted from a. + /// + SUB = 0x9F, + /// + /// a is multiplied by b. + /// + MUL = 0xA0, + /// + /// a is divided by b. + /// + DIV = 0xA1, + /// + /// Returns the remainder after dividing a by b. + /// + MOD = 0xA2, + /// + /// The result of raising value to the exponent power. + /// + POW = 0xA3, + /// + /// Returns the square root of a specified number. + /// + SQRT = 0xA4, + /// + /// Performs modulus division on a number multiplied by another number. + /// + MODMUL = 0xA5, + /// + /// Performs modulus division on a number raised to the power of another number. If the exponent is -1, it will have the calculation of the modular inverse. + /// + MODPOW = 0xA6, + /// + /// Shifts a left b bits, preserving sign. + /// + SHL = 0xA8, + /// + /// Shifts a right b bits, preserving sign. + /// + SHR = 0xA9, + /// + /// If the input is 0 or 1, it is flipped. Otherwise the output will be 0. + /// + NOT = 0xAA, + /// + /// If both a and b are not 0, the output is 1. Otherwise 0. + /// + BOOLAND = 0xAB, + /// + /// If a or b is not 0, the output is 1. Otherwise 0. + /// + BOOLOR = 0xAC, + /// + /// Returns 0 if the input is 0. 1 otherwise. + /// + NZ = 0xB1, + /// + /// Returns 1 if the numbers are equal, 0 otherwise. + /// + NUMEQUAL = 0xB3, + /// + /// Returns 1 if the numbers are not equal, 0 otherwise. + /// + NUMNOTEQUAL = 0xB4, + /// + /// Returns 1 if a is less than b, 0 otherwise. + /// + LT = 0xB5, + /// + /// Returns 1 if a is less than or equal to b, 0 otherwise. + /// + LE = 0xB6, + /// + /// Returns 1 if a is greater than b, 0 otherwise. + /// + GT = 0xB7, + /// + /// Returns 1 if a is greater than or equal to b, 0 otherwise. + /// + GE = 0xB8, + /// + /// Returns the smaller of a and b. + /// + MIN = 0xB9, + /// + /// Returns the larger of a and b. + /// + MAX = 0xBA, + /// + /// Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. + /// + WITHIN = 0xBB, + + #endregion + + #region Compound-type + + /// + /// A value n is taken from top of main stack. The next n*2 items on main stack are removed, put inside n-sized map and this map is put on top of the main stack. + /// + PACKMAP = 0xBE, + /// + /// A value n is taken from top of main stack. The next n items on main stack are removed, put inside n-sized struct and this struct is put on top of the main stack. + /// + PACKSTRUCT = 0xBF, + /// + /// A value n is taken from top of main stack. The next n items on main stack are removed, put inside n-sized array and this array is put on top of the main stack. + /// + PACK = 0xC0, + /// + /// A collection is removed from top of the main stack. Its elements are put on top of the main stack (in reverse order) and the collection size is also put on main stack. + /// + UNPACK = 0xC1, + /// + /// An empty array (with size 0) is put on top of the main stack. + /// + NEWARRAY0 = 0xC2, + /// + /// A value n is taken from top of main stack. A null-filled array with size n is put on top of the main stack. + /// + NEWARRAY = 0xC3, + /// + /// A value n is taken from top of main stack. An array of type T with size n is put on top of the main stack. + /// + [OperandSize(Size = 1)] + NEWARRAY_T = 0xC4, + /// + /// An empty struct (with size 0) is put on top of the main stack. + /// + NEWSTRUCT0 = 0xC5, + /// + /// A value n is taken from top of main stack. A zero-filled struct with size n is put on top of the main stack. + /// + NEWSTRUCT = 0xC6, + /// + /// A Map is created and put on top of the main stack. + /// + NEWMAP = 0xC8, + /// + /// An array is removed from top of the main stack. Its size is put on top of the main stack. + /// + SIZE = 0xCA, + /// + /// An input index n (or key) and an array (or map) are removed from the top of the main stack. Puts True on top of main stack if array[n] (or map[n]) exist, and False otherwise. + /// + HASKEY = 0xCB, + /// + /// A map is taken from top of the main stack. The keys of this map are put on top of the main stack. + /// + KEYS = 0xCC, + /// + /// A map is taken from top of the main stack. The values of this map are put on top of the main stack. + /// + VALUES = 0xCD, + /// + /// An input index n (or key) and an array (or map) are taken from main stack. Element array[n] (or map[n]) is put on top of the main stack. + /// + PICKITEM = 0xCE, + /// + /// The item on top of main stack is removed and appended to the second item on top of the main stack. + /// + APPEND = 0xCF, + /// + /// A value v, index n (or key) and an array (or map) are taken from main stack. Attribution array[n]=v (or map[n]=v) is performed. + /// + SETITEM = 0xD0, + /// + /// An array is removed from the top of the main stack and its elements are reversed. + /// + REVERSEITEMS = 0xD1, + /// + /// An input index n (or key) and an array (or map) are removed from the top of the main stack. Element array[n] (or map[n]) is removed. + /// + REMOVE = 0xD2, + /// + /// Remove all the items from the compound-type. + /// + CLEARITEMS = 0xD3, + /// + /// Remove the last element from an array, and push it onto the stack. + /// + POPITEM = 0xD4, + + #endregion + + #region Types + + /// + /// Returns if the input is ; + /// otherwise. + /// + ISNULL = 0xD8, + /// + /// Returns if the top item of the stack is of the specified type; + /// otherwise. + /// + [OperandSize(Size = 1)] + ISTYPE = 0xD9, + /// + /// Converts the top item of the stack to the specified type. + /// + [OperandSize(Size = 1)] + CONVERT = 0xDB, + + #endregion + + #region Extensions + + /// + /// Pops the top stack item. Then, turns the vm state to FAULT immediately, and cannot be caught. The top stack + /// value is used as reason. + /// + ABORTMSG = 0xE0, + /// + /// Pops the top two stack items. If the second-to-top stack value is false, exits the vm execution and sets the + /// vm state to FAULT. In this case, the top stack value is used as reason for the exit. Otherwise, it is ignored. + /// + ASSERTMSG = 0xE1 + + #endregion + } +} diff --git a/src/Neo.VM/OperandSizeAttribute.cs b/src/Neo.VM/OperandSizeAttribute.cs new file mode 100644 index 0000000000..1240989bb8 --- /dev/null +++ b/src/Neo.VM/OperandSizeAttribute.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; + +namespace Neo.VM +{ + /// + /// Indicates the operand length of an . + /// + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + public class OperandSizeAttribute : Attribute + { + /// + /// When it is greater than 0, indicates the size of the operand. + /// + public int Size { get; set; } + + /// + /// When it is greater than 0, indicates the size prefix of the operand. + /// + public int SizePrefix { get; set; } + } +} diff --git a/src/Neo.VM/Properties/AssemblyInfo.cs b/src/Neo.VM/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b25e1d9752 --- /dev/null +++ b/src/Neo.VM/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Neo.VM.Tests")] diff --git a/src/Neo.VM/ReferenceCounter.cs b/src/Neo.VM/ReferenceCounter.cs new file mode 100644 index 0000000000..63732646cd --- /dev/null +++ b/src/Neo.VM/ReferenceCounter.cs @@ -0,0 +1,154 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.StronglyConnectedComponents; +using Neo.VM.Types; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Used for reference counting of objects in the VM. + /// + public sealed class ReferenceCounter + { + private const bool TrackAllItems = false; + + private readonly HashSet tracked_items = new(ReferenceEqualityComparer.Instance); + private readonly HashSet zero_referred = new(ReferenceEqualityComparer.Instance); + private LinkedList>? cached_components; + private int references_count = 0; + + /// + /// Indicates the number of this counter. + /// + public int Count => references_count; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool NeedTrack(StackItem item) + { +#pragma warning disable CS0162 + if (TrackAllItems) return true; +#pragma warning restore CS0162 + if (item is CompoundType or Buffer) return true; + return false; + } + + internal void AddReference(StackItem item, CompoundType parent) + { + references_count++; + if (!NeedTrack(item)) return; + cached_components = null; + tracked_items.Add(item); + item.ObjectReferences ??= new(ReferenceEqualityComparer.Instance); + if (!item.ObjectReferences.TryGetValue(parent, out var pEntry)) + { + pEntry = new(parent); + item.ObjectReferences.Add(parent, pEntry); + } + pEntry.References++; + } + + internal void AddStackReference(StackItem item, int count = 1) + { + references_count += count; + if (!NeedTrack(item)) return; + if (tracked_items.Add(item)) + cached_components?.AddLast(new HashSet(ReferenceEqualityComparer.Instance) { item }); + item.StackReferences += count; + zero_referred.Remove(item); + } + + internal void AddZeroReferred(StackItem item) + { + zero_referred.Add(item); + if (!NeedTrack(item)) return; + cached_components?.AddLast(new HashSet(ReferenceEqualityComparer.Instance) { item }); + tracked_items.Add(item); + } + + internal int CheckZeroReferred() + { + if (zero_referred.Count > 0) + { + zero_referred.Clear(); + if (cached_components is null) + { + //Tarjan tarjan = new(tracked_items.Where(p => p.StackReferences == 0)); + Tarjan tarjan = new(tracked_items); + cached_components = tarjan.Invoke(); + } + foreach (StackItem item in tracked_items) + item.Reset(); + for (var node = cached_components.First; node != null;) + { + var component = node.Value; + bool on_stack = false; + foreach (StackItem item in component) + { + if (item.StackReferences > 0 || item.ObjectReferences?.Values.Any(p => p.References > 0 && p.Item.OnStack) == true) + { + on_stack = true; + break; + } + } + if (on_stack) + { + foreach (StackItem item in component) + item.OnStack = true; + node = node.Next; + } + else + { + foreach (StackItem item in component) + { + tracked_items.Remove(item); + if (item is CompoundType compound) + { + references_count -= compound.SubItemsCount; + foreach (StackItem subitem in compound.SubItems) + { + if (component.Contains(subitem)) continue; + if (!NeedTrack(subitem)) continue; + subitem.ObjectReferences!.Remove(compound); + } + } + item.Cleanup(); + } + var nodeToRemove = node; + node = node.Next; + cached_components.Remove(nodeToRemove); + } + } + } + return references_count; + } + + internal void RemoveReference(StackItem item, CompoundType parent) + { + references_count--; + if (!NeedTrack(item)) return; + cached_components = null; + item.ObjectReferences![parent].References--; + if (item.StackReferences == 0) + zero_referred.Add(item); + } + + internal void RemoveStackReference(StackItem item) + { + references_count--; + if (!NeedTrack(item)) return; + if (--item.StackReferences == 0) + zero_referred.Add(item); + } + } +} diff --git a/src/Neo.VM/ReferenceEqualityComparer.cs b/src/Neo.VM/ReferenceEqualityComparer.cs new file mode 100644 index 0000000000..7c9d68ad64 --- /dev/null +++ b/src/Neo.VM/ReferenceEqualityComparer.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ +#if !NET5_0_OR_GREATER + // https://github.dev/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ReferenceEqualityComparer.cs + public sealed class ReferenceEqualityComparer : IEqualityComparer, System.Collections.IEqualityComparer + { + private ReferenceEqualityComparer() { } + + public static ReferenceEqualityComparer Instance { get; } = new ReferenceEqualityComparer(); + + public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); + + public int GetHashCode(object? obj) => RuntimeHelpers.GetHashCode(obj!); + } +#endif +} diff --git a/src/Neo.VM/Script.cs b/src/Neo.VM/Script.cs new file mode 100644 index 0000000000..863fec9576 --- /dev/null +++ b/src/Neo.VM/Script.cs @@ -0,0 +1,160 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Types; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Represents the script executed in the VM. + /// + [DebuggerDisplay("Length={Length}")] + public class Script + { + private readonly ReadOnlyMemory _value; + private readonly bool strictMode; + private readonly Dictionary _instructions = new(); + + /// + /// The length of the script. + /// + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return _value.Length; + } + } + + /// + /// Gets the at the specified index. + /// + /// The index to locate. + /// The at the specified index. + public OpCode this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return (OpCode)_value.Span[index]; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The bytecodes of the script. + public Script(ReadOnlyMemory script) : this(script, false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The bytecodes of the script. + /// + /// Indicates whether strict mode is enabled. + /// In strict mode, the script will be checked, but the loading speed will be slower. + /// + /// In strict mode, the script was found to contain bad instructions. + public Script(ReadOnlyMemory script, bool strictMode) + { + this._value = script; + if (strictMode) + { + for (int ip = 0; ip < script.Length; ip += GetInstruction(ip).Size) { } + foreach (var (ip, instruction) in _instructions) + { + switch (instruction.OpCode) + { + case OpCode.JMP: + case OpCode.JMPIF: + case OpCode.JMPIFNOT: + case OpCode.JMPEQ: + case OpCode.JMPNE: + case OpCode.JMPGT: + case OpCode.JMPGE: + case OpCode.JMPLT: + case OpCode.JMPLE: + case OpCode.CALL: + case OpCode.ENDTRY: + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI8))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + case OpCode.PUSHA: + case OpCode.JMP_L: + case OpCode.JMPIF_L: + case OpCode.JMPIFNOT_L: + case OpCode.JMPEQ_L: + case OpCode.JMPNE_L: + case OpCode.JMPGT_L: + case OpCode.JMPGE_L: + case OpCode.JMPLT_L: + case OpCode.JMPLE_L: + case OpCode.CALL_L: + case OpCode.ENDTRY_L: + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI32))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + case OpCode.TRY: + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI8))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI8_1))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + case OpCode.TRY_L: + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI32))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI32_1))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + case OpCode.NEWARRAY_T: + case OpCode.ISTYPE: + case OpCode.CONVERT: + StackItemType type = (StackItemType)instruction.TokenU8; + if (!Enum.IsDefined(typeof(StackItemType), type)) + throw new BadScriptException(); + if (instruction.OpCode != OpCode.NEWARRAY_T && type == StackItemType.Any) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + } + } + } + this.strictMode = strictMode; + } + + /// + /// Get the at the specified position. + /// + /// The position to get the . + /// The at the specified position. + /// In strict mode, the was not found at the specified position. + public Instruction GetInstruction(int ip) + { + if (ip >= Length) throw new ArgumentOutOfRangeException(nameof(ip)); + if (!_instructions.TryGetValue(ip, out Instruction? instruction)) + { + if (strictMode) throw new ArgumentException($"ip not found with strict mode", nameof(ip)); + instruction = new Instruction(_value, ip); + _instructions.Add(ip, instruction); + } + return instruction; + } + + public static implicit operator ReadOnlyMemory(Script script) => script._value; + public static implicit operator Script(ReadOnlyMemory script) => new(script); + public static implicit operator Script(byte[] script) => new(script); + } +} diff --git a/src/Neo.VM/ScriptBuilder.cs b/src/Neo.VM/ScriptBuilder.cs new file mode 100644 index 0000000000..d2cb995532 --- /dev/null +++ b/src/Neo.VM/ScriptBuilder.cs @@ -0,0 +1,199 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.IO; +using System.Numerics; + +namespace Neo.VM +{ + /// + /// A helper class for building scripts. + /// + public class ScriptBuilder : IDisposable + { + private readonly MemoryStream ms = new(); + private readonly BinaryWriter writer; + + /// + /// The length of the script. + /// + public int Length => (int)ms.Position; + + /// + /// Initializes a new instance of the class. + /// + public ScriptBuilder() + { + writer = new BinaryWriter(ms); + } + + public void Dispose() + { + writer.Dispose(); + ms.Dispose(); + } + + /// + /// Emits an with the specified and operand. + /// + /// The to be emitted. + /// The operand to be emitted. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder Emit(OpCode opcode, ReadOnlySpan operand = default) + { + writer.Write((byte)opcode); + writer.Write(operand); + return this; + } + + /// + /// Emits a call with the specified offset. + /// + /// The offset to be called. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitCall(int offset) + { + if (offset < sbyte.MinValue || offset > sbyte.MaxValue) + return Emit(OpCode.CALL_L, BitConverter.GetBytes(offset)); + else + return Emit(OpCode.CALL, new[] { (byte)offset }); + } + + /// + /// Emits a jump with the specified offset. + /// + /// The to be emitted. It must be a jump + /// The offset to jump. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitJump(OpCode opcode, int offset) + { + if (opcode < OpCode.JMP || opcode > OpCode.JMPLE_L) + throw new ArgumentOutOfRangeException(nameof(opcode)); + if ((int)opcode % 2 == 0 && (offset < sbyte.MinValue || offset > sbyte.MaxValue)) + opcode += 1; + if ((int)opcode % 2 == 0) + return Emit(opcode, new[] { (byte)offset }); + else + return Emit(opcode, BitConverter.GetBytes(offset)); + } + + /// + /// Emits a push with the specified number. + /// + /// The number to be pushed. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitPush(BigInteger value) + { + if (value >= -1 && value <= 16) return Emit(OpCode.PUSH0 + (byte)(int)value); + Span buffer = stackalloc byte[32]; + if (!value.TryWriteBytes(buffer, out int bytesWritten, isUnsigned: false, isBigEndian: false)) + throw new ArgumentOutOfRangeException(nameof(value)); + return bytesWritten switch + { + 1 => Emit(OpCode.PUSHINT8, PadRight(buffer, bytesWritten, 1, value.Sign < 0)), + 2 => Emit(OpCode.PUSHINT16, PadRight(buffer, bytesWritten, 2, value.Sign < 0)), + <= 4 => Emit(OpCode.PUSHINT32, PadRight(buffer, bytesWritten, 4, value.Sign < 0)), + <= 8 => Emit(OpCode.PUSHINT64, PadRight(buffer, bytesWritten, 8, value.Sign < 0)), + <= 16 => Emit(OpCode.PUSHINT128, PadRight(buffer, bytesWritten, 16, value.Sign < 0)), + _ => Emit(OpCode.PUSHINT256, PadRight(buffer, bytesWritten, 32, value.Sign < 0)), + }; + } + + /// + /// Emits a push with the specified boolean value. + /// + /// The value to be pushed. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitPush(bool value) + { + return Emit(value ? OpCode.PUSHT : OpCode.PUSHF); + } + + /// + /// Emits a push with the specified data. + /// + /// The data to be pushed. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitPush(ReadOnlySpan data) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (data.Length < 0x100) + { + Emit(OpCode.PUSHDATA1); + writer.Write((byte)data.Length); + writer.Write(data); + } + else if (data.Length < 0x10000) + { + Emit(OpCode.PUSHDATA2); + writer.Write((ushort)data.Length); + writer.Write(data); + } + else// if (data.Length < 0x100000000L) + { + Emit(OpCode.PUSHDATA4); + writer.Write(data.Length); + writer.Write(data); + } + return this; + } + + /// + /// Emits a push with the specified . + /// + /// The to be pushed. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitPush(string data) + { + return EmitPush(Utility.StrictUTF8.GetBytes(data)); + } + + /// + /// Emits raw script. + /// + /// The raw script to be emitted. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitRaw(ReadOnlySpan script = default) + { + writer.Write(script); + return this; + } + + /// + /// Emits an with . + /// + /// The operand of . + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitSysCall(uint api) + { + return Emit(OpCode.SYSCALL, BitConverter.GetBytes(api)); + } + + /// + /// Converts the value of this instance to a byte array. + /// + /// A byte array contains the script. + public byte[] ToArray() + { + writer.Flush(); + return ms.ToArray(); + } + + private static ReadOnlySpan PadRight(Span buffer, int dataLength, int padLength, bool negative) + { + byte pad = negative ? (byte)0xff : (byte)0; + for (int x = dataLength; x < padLength; x++) + buffer[x] = pad; + return buffer[..padLength]; + } + } +} diff --git a/src/Neo.VM/Slot.cs b/src/Neo.VM/Slot.cs new file mode 100644 index 0000000000..9f4609f792 --- /dev/null +++ b/src/Neo.VM/Slot.cs @@ -0,0 +1,92 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Types; +using System.Collections; +using System.Collections.Generic; + +namespace Neo.VM +{ + /// + /// Used to store local variables, arguments and static fields in the VM. + /// + public class Slot : IReadOnlyList + { + private readonly ReferenceCounter referenceCounter; + private readonly StackItem[] items; + + /// + /// Gets the item at the specified index in the slot. + /// + /// The zero-based index of the item to get. + /// The item at the specified index in the slot. + public StackItem this[int index] + { + get + { + return items[index]; + } + internal set + { + ref var oldValue = ref items[index]; + referenceCounter.RemoveStackReference(oldValue); + oldValue = value; + referenceCounter.AddStackReference(value); + } + } + + /// + /// Gets the number of items in the slot. + /// + public int Count => items.Length; + + /// + /// Creates a slot containing the specified items. + /// + /// The items to be contained. + /// The reference counter to be used. + public Slot(StackItem[] items, ReferenceCounter referenceCounter) + { + this.referenceCounter = referenceCounter; + this.items = items; + foreach (StackItem item in items) + referenceCounter.AddStackReference(item); + } + + /// + /// Create a slot of the specified size. + /// + /// Indicates the number of items contained in the slot. + /// The reference counter to be used. + public Slot(int count, ReferenceCounter referenceCounter) + { + this.referenceCounter = referenceCounter; + this.items = new StackItem[count]; + System.Array.Fill(items, StackItem.Null); + referenceCounter.AddStackReference(StackItem.Null, count); + } + + internal void ClearReferences() + { + foreach (StackItem item in items) + referenceCounter.RemoveStackReference(item); + } + + IEnumerator IEnumerable.GetEnumerator() + { + foreach (StackItem item in items) yield return item; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return items.GetEnumerator(); + } + } +} diff --git a/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs b/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs new file mode 100644 index 0000000000..6fe867cd80 --- /dev/null +++ b/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs @@ -0,0 +1,124 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; +using T = Neo.VM.Types.StackItem; + +namespace Neo.VM.StronglyConnectedComponents +{ + class Tarjan + { + private readonly IEnumerable vertexs; + private readonly LinkedList> components = new(); + private readonly Stack stack = new(); + private int index = 0; + + public Tarjan(IEnumerable vertexs) + { + this.vertexs = vertexs; + } + + public LinkedList> Invoke() + { + foreach (var v in vertexs) + { + if (v.DFN < 0) + { + StrongConnectNonRecursive(v); + } + } + return components; + } + + private void StrongConnect(T v) + { + v.DFN = v.LowLink = ++index; + stack.Push(v); + v.OnStack = true; + + foreach (T w in v.Successors) + { + if (w.DFN < 0) + { + StrongConnect(w); + v.LowLink = Math.Min(v.LowLink, w.LowLink); + } + else if (w.OnStack) + { + v.LowLink = Math.Min(v.LowLink, w.DFN); + } + } + + if (v.LowLink == v.DFN) + { + HashSet scc = new(ReferenceEqualityComparer.Instance); + T w; + do + { + w = stack.Pop(); + w.OnStack = false; + scc.Add(w); + } while (v != w); + components.AddLast(scc); + } + } + + private void StrongConnectNonRecursive(T v) + { + Stack<(T node, T?, IEnumerator?, int)> sstack = new(); + sstack.Push((v, null, null, 0)); + while (sstack.TryPop(out var state)) + { + v = state.node; + var (_, w, s, n) = state; + switch (n) + { + case 0: + v.DFN = v.LowLink = ++index; + stack.Push(v); + v.OnStack = true; + s = v.Successors.GetEnumerator(); + goto case 2; + case 1: + v.LowLink = Math.Min(v.LowLink, w!.LowLink); + goto case 2; + case 2: + while (s!.MoveNext()) + { + w = s.Current; + if (w.DFN < 0) + { + sstack.Push((v, w, s, 1)); + v = w; + goto case 0; + } + else if (w.OnStack) + { + v.LowLink = Math.Min(v.LowLink, w.DFN); + } + } + if (v.LowLink == v.DFN) + { + HashSet scc = new(ReferenceEqualityComparer.Instance); + do + { + w = stack.Pop(); + w.OnStack = false; + scc.Add(w); + } while (v != w); + components.AddLast(scc); + } + break; + } + } + } + } +} diff --git a/src/Neo.VM/Types/Array.cs b/src/Neo.VM/Types/Array.cs new file mode 100644 index 0000000000..780521415b --- /dev/null +++ b/src/Neo.VM/Types/Array.cs @@ -0,0 +1,145 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Neo.VM.Types +{ + /// + /// Represents an array or a complex object in the VM. + /// + public class Array : CompoundType, IReadOnlyList + { + protected readonly List _array; + + /// + /// Get or set item in the array. + /// + /// The index of the item in the array. + /// The item at the specified index. + public StackItem this[int index] + { + get => _array[index]; + set + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + ReferenceCounter?.RemoveReference(_array[index], this); + _array[index] = value; + ReferenceCounter?.AddReference(value, this); + } + } + + /// + /// The number of items in the array. + /// + public override int Count => _array.Count; + public override IEnumerable SubItems => _array; + public override int SubItemsCount => _array.Count; + public override StackItemType Type => StackItemType.Array; + + /// + /// Create an array containing the specified items. + /// + /// The items to be included in the array. + public Array(IEnumerable? items = null) + : this(null, items) + { + } + + /// + /// Create an array containing the specified items. And make the array use the specified . + /// + /// The to be used by this array. + /// The items to be included in the array. + public Array(ReferenceCounter? referenceCounter, IEnumerable? items = null) + : base(referenceCounter) + { + _array = items switch + { + null => new List(), + List list => list, + _ => new List(items) + }; + if (referenceCounter != null) + foreach (StackItem item in _array) + referenceCounter.AddReference(item, this); + } + + /// + /// Add a new item at the end of the array. + /// + /// The item to be added. + public void Add(StackItem item) + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + _array.Add(item); + ReferenceCounter?.AddReference(item, this); + } + + public override void Clear() + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + if (ReferenceCounter != null) + foreach (StackItem item in _array) + ReferenceCounter.RemoveReference(item, this); + _array.Clear(); + } + + public override StackItem ConvertTo(StackItemType type) + { + if (Type == StackItemType.Array && type == StackItemType.Struct) + return new Struct(ReferenceCounter, new List(_array)); + return base.ConvertTo(type); + } + + internal sealed override StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + if (refMap.TryGetValue(this, out StackItem? mappedItem)) return mappedItem; + Array result = this is Struct ? new Struct(ReferenceCounter) : new Array(ReferenceCounter); + refMap.Add(this, result); + foreach (StackItem item in _array) + result.Add(item.DeepCopy(refMap, asImmutable)); + result.IsReadOnly = true; + return result; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return _array.GetEnumerator(); + } + + /// + /// Remove the item at the specified index. + /// + /// The index of the item to be removed. + public void RemoveAt(int index) + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + ReferenceCounter?.RemoveReference(_array[index], this); + _array.RemoveAt(index); + } + + /// + /// Reverse all items in the array. + /// + public void Reverse() + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + _array.Reverse(); + } + } +} diff --git a/src/Neo.VM/Types/Boolean.cs b/src/Neo.VM/Types/Boolean.cs new file mode 100644 index 0000000000..56f620438d --- /dev/null +++ b/src/Neo.VM/Types/Boolean.cs @@ -0,0 +1,70 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// Represents a boolean ( or ) value in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={value}")] + public class Boolean : PrimitiveType + { + private static readonly ReadOnlyMemory TRUE = new byte[] { 1 }; + private static readonly ReadOnlyMemory FALSE = new byte[] { 0 }; + + private readonly bool value; + + public override ReadOnlyMemory Memory => value ? TRUE : FALSE; + public override int Size => sizeof(bool); + public override StackItemType Type => StackItemType.Boolean; + + /// + /// Create a new VM object representing the boolean type. + /// + /// The initial value of the object. + internal Boolean(bool value) + { + this.value = value; + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is Boolean b) return value == b.value; + return false; + } + + public override bool GetBoolean() + { + return value; + } + + public override int GetHashCode() + { + return HashCode.Combine(value); + } + + public override BigInteger GetInteger() + { + return value ? BigInteger.One : BigInteger.Zero; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Boolean(bool value) + { + return value ? True : False; + } + } +} diff --git a/src/Neo.VM/Types/Buffer.cs b/src/Neo.VM/Types/Buffer.cs new file mode 100644 index 0000000000..d80eecd4f5 --- /dev/null +++ b/src/Neo.VM/Types/Buffer.cs @@ -0,0 +1,110 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Diagnostics; +using System.Numerics; + +namespace Neo.VM.Types +{ + /// + /// Represents a memory block that can be used for reading and writing in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={System.Convert.ToHexString(GetSpan())}")] + public class Buffer : StackItem + { + /// + /// The internal byte array used to store the actual data. + /// + public readonly Memory InnerBuffer; + + /// + /// The size of the buffer. + /// + public int Size => InnerBuffer.Length; + public override StackItemType Type => StackItemType.Buffer; + + private readonly byte[] _buffer; + private bool _keep_alive = false; + + /// + /// Create a buffer of the specified size. + /// + /// The size of this buffer. + /// Indicates whether the created buffer is zero-initialized. + public Buffer(int size, bool zeroInitialize = true) + { + _buffer = ArrayPool.Shared.Rent(size); + InnerBuffer = new Memory(_buffer, 0, size); + if (zeroInitialize) InnerBuffer.Span.Clear(); + } + + /// + /// Create a buffer with the specified data. + /// + /// The data to be contained in this buffer. + public Buffer(ReadOnlySpan data) : this(data.Length, false) + { + data.CopyTo(InnerBuffer.Span); + } + + internal override void Cleanup() + { + if (!_keep_alive) + ArrayPool.Shared.Return(_buffer, clearArray: false); + } + + public void KeepAlive() + { + _keep_alive = true; + } + + public override StackItem ConvertTo(StackItemType type) + { + switch (type) + { + case StackItemType.Integer: + if (InnerBuffer.Length > Integer.MaxSize) + throw new InvalidCastException(); + return new BigInteger(InnerBuffer.Span); + case StackItemType.ByteString: +#if NET5_0_OR_GREATER + byte[] clone = GC.AllocateUninitializedArray(InnerBuffer.Length); +#else + byte[] clone = new byte[InnerBuffer.Length]; +#endif + InnerBuffer.CopyTo(clone); + return clone; + default: + return base.ConvertTo(type); + } + } + + internal override StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + if (refMap.TryGetValue(this, out StackItem? mappedItem)) return mappedItem; + StackItem result = asImmutable ? new ByteString(InnerBuffer.ToArray()) : new Buffer(InnerBuffer.Span); + refMap.Add(this, result); + return result; + } + + public override bool GetBoolean() + { + return true; + } + + public override ReadOnlySpan GetSpan() + { + return InnerBuffer.Span; + } + } +} diff --git a/src/Neo.VM/Types/ByteString.cs b/src/Neo.VM/Types/ByteString.cs new file mode 100644 index 0000000000..ddfe062210 --- /dev/null +++ b/src/Neo.VM/Types/ByteString.cs @@ -0,0 +1,136 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Cryptography; +using System; +using System.Buffers.Binary; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// Represents an immutable memory block in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={System.Convert.ToHexString(GetSpan())}")] + public class ByteString : PrimitiveType + { + /// + /// An empty . + /// + public static readonly ByteString Empty = ReadOnlyMemory.Empty; + + private static readonly uint s_seed = unchecked((uint)new Random().Next()); + private int _hashCode = 0; + + public override ReadOnlyMemory Memory { get; } + public override StackItemType Type => StackItemType.ByteString; + + /// + /// Create a new with the specified data. + /// + /// The data to be contained in this . + public ByteString(ReadOnlyMemory data) + { + this.Memory = data; + } + + private bool Equals(ByteString other) + { + return GetSpan().SequenceEqual(other.GetSpan()); + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is not ByteString b) return false; + return Equals(b); + } + + internal override bool Equals(StackItem? other, ExecutionEngineLimits limits) + { + uint maxComparableSize = limits.MaxComparableSize; + return Equals(other, ref maxComparableSize); + } + + internal bool Equals(StackItem? other, ref uint limits) + { + if (Size > limits || limits == 0) + throw new InvalidOperationException("The operand exceeds the maximum comparable size."); + uint comparedSize = 1; + try + { + if (other is not ByteString b) return false; + comparedSize = Math.Max((uint)Math.Max(Size, b.Size), comparedSize); + if (ReferenceEquals(this, b)) return true; + if (b.Size > limits) + throw new InvalidOperationException("The operand exceeds the maximum comparable size."); + return Equals(b); + } + finally + { + limits -= comparedSize; + } + } + + public override bool GetBoolean() + { + if (Size > Integer.MaxSize) throw new InvalidCastException(); + return Unsafe.NotZero(GetSpan()); + } + + public override int GetHashCode() + { + if (_hashCode == 0) + { + using Murmur32 murmur = new(s_seed); + _hashCode = BinaryPrimitives.ReadInt32LittleEndian(murmur.ComputeHash(GetSpan().ToArray())); + } + return _hashCode; + } + + public override BigInteger GetInteger() + { + if (Size > Integer.MaxSize) throw new InvalidCastException($"MaxSize exceed: {Size}"); + return new BigInteger(GetSpan()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlyMemory(ByteString value) + { + return value.Memory; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(ByteString value) + { + return value.Memory.Span; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ByteString(byte[] value) + { + return new ByteString(value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ByteString(ReadOnlyMemory value) + { + return new ByteString(value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ByteString(string value) + { + return new ByteString(Utility.StrictUTF8.GetBytes(value)); + } + } +} diff --git a/src/Neo.VM/Types/CompoundType.cs b/src/Neo.VM/Types/CompoundType.cs new file mode 100644 index 0000000000..b3592a1e8b --- /dev/null +++ b/src/Neo.VM/Types/CompoundType.cs @@ -0,0 +1,70 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Neo.VM.Types +{ + /// + /// The base class for complex types in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Count={Count}, Id={System.Collections.Generic.ReferenceEqualityComparer.Instance.GetHashCode(this)}")] + public abstract class CompoundType : StackItem + { + /// + /// The reference counter used to count the items in the VM object. + /// + protected readonly ReferenceCounter? ReferenceCounter; + + /// + /// Create a new with the specified reference counter. + /// + /// The reference counter to be used. + protected CompoundType(ReferenceCounter? referenceCounter) + { + this.ReferenceCounter = referenceCounter; + referenceCounter?.AddZeroReferred(this); + } + + /// + /// The number of items in this VM object. + /// + public abstract int Count { get; } + + public abstract IEnumerable SubItems { get; } + + public abstract int SubItemsCount { get; } + + public bool IsReadOnly { get; protected set; } + + /// + /// Remove all items from the VM object. + /// + public abstract void Clear(); + + internal abstract override StackItem DeepCopy(Dictionary refMap, bool asImmutable); + + public sealed override bool GetBoolean() + { + return true; + } + + /// + /// The operation is not supported. Always throw . + /// + /// This method always throws the exception. + public override int GetHashCode() + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Neo.VM/Types/Integer.cs b/src/Neo.VM/Types/Integer.cs new file mode 100644 index 0000000000..04489fc54f --- /dev/null +++ b/src/Neo.VM/Types/Integer.cs @@ -0,0 +1,133 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// Represents an integer value in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={value}")] + public class Integer : PrimitiveType + { + /// + /// The maximum size of an integer in bytes. + /// + public const int MaxSize = 32; + + /// + /// Represents the number 0. + /// + public static readonly Integer Zero = 0; + private readonly BigInteger value; + + public override ReadOnlyMemory Memory => value.IsZero ? ReadOnlyMemory.Empty : value.ToByteArray(); + public override int Size { get; } + public override StackItemType Type => StackItemType.Integer; + + /// + /// Create an integer with the specified value. + /// + /// The value of the integer. + public Integer(BigInteger value) + { + if (value.IsZero) + { + Size = 0; + } + else + { + Size = value.GetByteCount(); + if (Size > MaxSize) throw new ArgumentException($"MaxSize exceed: {Size}"); + } + this.value = value; + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is Integer i) return value == i.value; + return false; + } + + public override bool GetBoolean() + { + return !value.IsZero; + } + + public override int GetHashCode() + { + return HashCode.Combine(value); + } + + public override BigInteger GetInteger() + { + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(sbyte value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(byte value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(short value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(ushort value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(int value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(uint value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(long value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(ulong value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(BigInteger value) + { + return new Integer(value); + } + } +} diff --git a/src/Neo.VM/Types/InteropInterface.cs b/src/Neo.VM/Types/InteropInterface.cs new file mode 100644 index 0000000000..44edf11b0f --- /dev/null +++ b/src/Neo.VM/Types/InteropInterface.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Diagnostics; + +namespace Neo.VM.Types +{ + /// + /// Represents an interface used to interoperate with the outside of the the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={_object}")] + public class InteropInterface : StackItem + { + private readonly object _object; + + public override StackItemType Type => StackItemType.InteropInterface; + + /// + /// Create an interoperability interface that wraps the specified . + /// + /// The wrapped . + public InteropInterface(object value) + { + _object = value ?? throw new ArgumentNullException(nameof(value)); + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is InteropInterface i) return _object.Equals(i._object); + return false; + } + + public override bool GetBoolean() + { + return true; + } + + public override int GetHashCode() + { + return HashCode.Combine(_object); + } + + public override T GetInterface() + { + if (_object is T t) return t; + throw new InvalidCastException($"The item can't be casted to type {typeof(T)}"); + } + } +} diff --git a/src/Neo.VM/Types/Map.cs b/src/Neo.VM/Types/Map.cs new file mode 100644 index 0000000000..6be029614b --- /dev/null +++ b/src/Neo.VM/Types/Map.cs @@ -0,0 +1,180 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Collections; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Neo.VM.Types +{ + /// + /// Represents an ordered collection of key-value pairs in the VM. + /// + public class Map : CompoundType, IReadOnlyDictionary + { + /// + /// Indicates the maximum size of keys in bytes. + /// + public const int MaxKeySize = 64; + + private readonly OrderedDictionary dictionary = new(); + + /// + /// Gets or sets the element that has the specified key in the map. + /// + /// The key to locate. + /// The element that has the specified key in the map. + public StackItem this[PrimitiveType key] + { + get + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + return dictionary[key]; + } + set + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + if (ReferenceCounter != null) + { + if (dictionary.TryGetValue(key, out StackItem? old_value)) + ReferenceCounter.RemoveReference(old_value, this); + else + ReferenceCounter.AddReference(key, this); + ReferenceCounter.AddReference(value, this); + } + dictionary[key] = value; + } + } + + public override int Count => dictionary.Count; + + /// + /// Gets an enumerable collection that contains the keys in the map. + /// + public IEnumerable Keys => dictionary.Keys; + + public override IEnumerable SubItems => Keys.Concat(Values); + + public override int SubItemsCount => dictionary.Count * 2; + + public override StackItemType Type => StackItemType.Map; + + /// + /// Gets an enumerable collection that contains the values in the map. + /// + public IEnumerable Values => dictionary.Values; + + /// + /// Create a new map with the specified reference counter. + /// + /// The reference counter to be used. + public Map(ReferenceCounter? referenceCounter = null) + : base(referenceCounter) + { + } + + public override void Clear() + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + if (ReferenceCounter != null) + foreach (var pair in dictionary) + { + ReferenceCounter.RemoveReference(pair.Key, this); + ReferenceCounter.RemoveReference(pair.Value, this); + } + dictionary.Clear(); + } + + /// + /// Determines whether the map contains an element that has the specified key. + /// + /// The key to locate. + /// + /// if the map contains an element that has the specified key; + /// otherwise, . + /// + public bool ContainsKey(PrimitiveType key) + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + return dictionary.ContainsKey(key); + } + + internal override StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + if (refMap.TryGetValue(this, out StackItem? mappedItem)) return mappedItem; + Map result = new(ReferenceCounter); + refMap.Add(this, result); + foreach (var (k, v) in dictionary) + result[k] = v.DeepCopy(refMap, asImmutable); + result.IsReadOnly = true; + return result; + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return ((IDictionary)dictionary).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IDictionary)dictionary).GetEnumerator(); + } + + /// + /// Removes the element with the specified key from the map. + /// + /// The key of the element to remove. + /// + /// if the element is successfully removed; + /// otherwise, . + /// This method also returns if was not found in the original map. + /// + public bool Remove(PrimitiveType key) + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + if (!dictionary.Remove(key, out StackItem? old_value)) + return false; + ReferenceCounter?.RemoveReference(key, this); + ReferenceCounter?.RemoveReference(old_value, this); + return true; + } + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, . + /// + /// + /// if the map contains an element that has the specified key; + /// otherwise, . + /// +// supress warning of value parameter nullability mismatch +#pragma warning disable CS8767 + public bool TryGetValue(PrimitiveType key, [MaybeNullWhen(false)] out StackItem value) +#pragma warning restore CS8767 + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + return dictionary.TryGetValue(key, out value); + } + } +} diff --git a/src/Neo.VM/Types/Null.cs b/src/Neo.VM/Types/Null.cs new file mode 100644 index 0000000000..d342f422e3 --- /dev/null +++ b/src/Neo.VM/Types/Null.cs @@ -0,0 +1,59 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Neo.VM.Types +{ + /// + /// Represents in the VM. + /// + public class Null : StackItem + { + public override StackItemType Type => StackItemType.Any; + + internal Null() { } + + public override StackItem ConvertTo(StackItemType type) + { + if (type == StackItemType.Any || !Enum.IsDefined(typeof(StackItemType), type)) + throw new InvalidCastException($"Type can't be converted to StackItemType: {type}"); + return this; + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + return other is Null; + } + + public override bool GetBoolean() + { + return false; + } + + public override int GetHashCode() + { + return 0; + } + + [return: MaybeNull] + public override T GetInterface() + { + return default; + } + + public override string? GetString() + { + return null; + } + } +} diff --git a/src/Neo.VM/Types/Pointer.cs b/src/Neo.VM/Types/Pointer.cs new file mode 100644 index 0000000000..5af77ed414 --- /dev/null +++ b/src/Neo.VM/Types/Pointer.cs @@ -0,0 +1,62 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Diagnostics; + +namespace Neo.VM.Types +{ + /// + /// Represents the instruction pointer in the VM, used as the target of jump instructions. + /// + [DebuggerDisplay("Type={GetType().Name}, Position={Position}")] + public class Pointer : StackItem + { + /// + /// The object containing this pointer. + /// + public Script Script { get; } + + /// + /// The position of the pointer in the script. + /// + public int Position { get; } + + public override StackItemType Type => StackItemType.Pointer; + + /// + /// Create a code pointer with the specified script and position. + /// + /// The object containing this pointer. + /// The position of the pointer in the script. + public Pointer(Script script, int position) + { + this.Script = script; + this.Position = position; + } + + public override bool Equals(StackItem? other) + { + if (other == this) return true; + if (other is Pointer p) return Position == p.Position && Script == p.Script; + return false; + } + + public override bool GetBoolean() + { + return true; + } + + public override int GetHashCode() + { + return HashCode.Combine(Script, Position); + } + } +} diff --git a/src/Neo.VM/Types/PrimitiveType.cs b/src/Neo.VM/Types/PrimitiveType.cs new file mode 100644 index 0000000000..794804dcc9 --- /dev/null +++ b/src/Neo.VM/Types/PrimitiveType.cs @@ -0,0 +1,138 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// The base class for primitive types in the VM. + /// + public abstract class PrimitiveType : StackItem + { + public abstract ReadOnlyMemory Memory { get; } + + /// + /// The size of the VM object in bytes. + /// + public virtual int Size => Memory.Length; + + public override StackItem ConvertTo(StackItemType type) + { + if (type == Type) return this; + return type switch + { + StackItemType.Integer => GetInteger(), + StackItemType.ByteString => Memory, + StackItemType.Buffer => new Buffer(GetSpan()), + _ => base.ConvertTo(type) + }; + } + + internal sealed override StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + return this; + } + + public abstract override bool Equals(StackItem? other); + + /// + /// Get the hash code of the VM object, which is used for key comparison in the . + /// + /// The hash code of this VM object. + public abstract override int GetHashCode(); + + public sealed override ReadOnlySpan GetSpan() + { + return Memory.Span; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(sbyte value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(byte value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(short value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(ushort value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(int value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(uint value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(long value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(ulong value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(BigInteger value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(bool value) + { + return (Boolean)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(byte[] value) + { + return (ByteString)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(ReadOnlyMemory value) + { + return (ByteString)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(string value) + { + return (ByteString)value; + } + } +} diff --git a/src/Neo.VM/Types/StackItem.Vertex.cs b/src/Neo.VM/Types/StackItem.Vertex.cs new file mode 100644 index 0000000000..6458a568d8 --- /dev/null +++ b/src/Neo.VM/Types/StackItem.Vertex.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Collections.Generic; +using System.Linq; + +namespace Neo.VM.Types +{ + partial class StackItem + { + internal class ObjectReferenceEntry + { + public StackItem Item; + public int References; + public ObjectReferenceEntry(StackItem item) => Item = item; + } + + internal int StackReferences = 0; + internal Dictionary? ObjectReferences; + internal int DFN = -1; + internal int LowLink = 0; + internal bool OnStack = false; + + internal IEnumerable Successors => ObjectReferences?.Values.Where(p => p.References > 0).Select(p => p.Item) ?? System.Array.Empty(); + + internal void Reset() => (DFN, LowLink, OnStack) = (-1, 0, false); + } +} diff --git a/src/Neo.VM/Types/StackItem.cs b/src/Neo.VM/Types/StackItem.cs new file mode 100644 index 0000000000..94c39aee40 --- /dev/null +++ b/src/Neo.VM/Types/StackItem.cs @@ -0,0 +1,261 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +#pragma warning disable CS0659 + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// The base class for all types in the VM. + /// + public abstract partial class StackItem : IEquatable + { + [ThreadStatic] + private static Boolean? tls_true = null; + + /// + /// Represents in the VM. + /// + public static Boolean True + { + get + { + tls_true ??= new(true); + return tls_true; + } + } + + [ThreadStatic] + private static Boolean? tls_false = null; + + /// + /// Represents in the VM. + /// + public static Boolean False + { + get + { + tls_false ??= new(false); + return tls_false; + } + } + + [ThreadStatic] + private static Null? tls_null = null; + + /// + /// Represents in the VM. + /// + public static StackItem Null + { + get + { + tls_null ??= new(); + return tls_null; + } + } + + /// + /// Indicates whether the object is . + /// + public bool IsNull => this is Null; + + /// + /// The type of this VM object. + /// + public abstract StackItemType Type { get; } + + /// + /// Convert the VM object to the specified type. + /// + /// The type to be converted to. + /// The converted object. + public virtual StackItem ConvertTo(StackItemType type) + { + if (type == Type) return this; + if (type == StackItemType.Boolean) return GetBoolean(); + throw new InvalidCastException(); + } + + internal virtual void Cleanup() + { + } + + /// + /// Copy the object and all its children. + /// + /// The copied object. + public StackItem DeepCopy(bool asImmutable = false) + { + return DeepCopy(new(ReferenceEqualityComparer.Instance), asImmutable); + } + + internal virtual StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + return this; + } + + public sealed override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) return true; + if (obj is StackItem item) return Equals(item); + return false; + } + + public virtual bool Equals(StackItem? other) + { + return ReferenceEquals(this, other); + } + + internal virtual bool Equals(StackItem? other, ExecutionEngineLimits limits) + { + return Equals(other); + } + + /// + /// Wrap the specified and return an containing the . + /// + /// The wrapped . + /// + public static StackItem FromInterface(object? value) + { + if (value is null) return Null; + return new InteropInterface(value); + } + + /// + /// Get the boolean value represented by the VM object. + /// + /// The boolean value represented by the VM object. + public abstract bool GetBoolean(); + + /// + /// Get the integer value represented by the VM object. + /// + /// The integer value represented by the VM object. + public virtual BigInteger GetInteger() + { + throw new InvalidCastException(); + } + + /// + /// Get the wrapped by this interface and convert it to the specified type. + /// + /// The type to convert to. + /// The wrapped . + [return: MaybeNull] + public virtual T GetInterface() where T : notnull + { + throw new InvalidCastException(); + } + + /// + /// Get the readonly span used to read the VM object data. + /// + /// + public virtual ReadOnlySpan GetSpan() + { + throw new InvalidCastException(); + } + + /// + /// Get the value represented by the VM object. + /// + /// The value represented by the VM object. + public virtual string? GetString() + { + return Utility.StrictUTF8.GetString(GetSpan()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(sbyte value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(byte value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(short value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(ushort value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(int value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(uint value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(long value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(ulong value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(BigInteger value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(bool value) + { + return value ? True : False; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(byte[] value) + { + return (ByteString)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(ReadOnlyMemory value) + { + return (ByteString)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(string value) + { + return (ByteString)value; + } + } +} diff --git a/src/Neo.VM/Types/StackItemType.cs b/src/Neo.VM/Types/StackItemType.cs new file mode 100644 index 0000000000..47a8407a83 --- /dev/null +++ b/src/Neo.VM/Types/StackItemType.cs @@ -0,0 +1,68 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.VM.Types +{ + /// + /// An enumeration representing the types in the VM. + /// + public enum StackItemType : byte + { + /// + /// Represents any type. + /// + Any = 0x00, + + /// + /// Represents a code pointer. + /// + Pointer = 0x10, + + /// + /// Represents the boolean ( or ) type. + /// + Boolean = 0x20, + + /// + /// Represents an integer. + /// + Integer = 0x21, + + /// + /// Represents an immutable memory block. + /// + ByteString = 0x28, + + /// + /// Represents a memory block that can be used for reading and writing. + /// + Buffer = 0x30, + + /// + /// Represents an array or a complex object. + /// + Array = 0x40, + + /// + /// Represents a structure. + /// + Struct = 0x41, + + /// + /// Represents an ordered collection of key-value pairs. + /// + Map = 0x48, + + /// + /// Represents an interface used to interoperate with the outside of the the VM. + /// + InteropInterface = 0x60, + } +} diff --git a/src/Neo.VM/Types/Struct.cs b/src/Neo.VM/Types/Struct.cs new file mode 100644 index 0000000000..07b21ba540 --- /dev/null +++ b/src/Neo.VM/Types/Struct.cs @@ -0,0 +1,133 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; + +namespace Neo.VM.Types +{ + /// + /// Represents a structure in the VM. + /// + public class Struct : Array + { + public override StackItemType Type => StackItemType.Struct; + + /// + /// Create a structure with the specified fields. + /// + /// The fields to be included in the structure. + public Struct(IEnumerable? fields = null) + : this(null, fields) + { + } + + /// + /// Create a structure with the specified fields. And make the structure use the specified . + /// + /// The to be used by this structure. + /// The fields to be included in the structure. + public Struct(ReferenceCounter? referenceCounter, IEnumerable? fields = null) + : base(referenceCounter, fields) + { + } + + /// + /// Create a new structure with the same content as this structure. All nested structures will be copied by value. + /// + /// Execution engine limits + /// The copied structure. + public Struct Clone(ExecutionEngineLimits limits) + { + int count = (int)(limits.MaxStackSize - 1); + Struct result = new(ReferenceCounter); + Queue queue = new(); + queue.Enqueue(result); + queue.Enqueue(this); + while (queue.Count > 0) + { + Struct a = queue.Dequeue(); + Struct b = queue.Dequeue(); + foreach (StackItem item in b) + { + count--; + if (count < 0) throw new InvalidOperationException("Beyond clone limits!"); + if (item is Struct sb) + { + Struct sa = new(ReferenceCounter); + a.Add(sa); + queue.Enqueue(sa); + queue.Enqueue(sb); + } + else + { + a.Add(item); + } + } + } + return result; + } + + public override StackItem ConvertTo(StackItemType type) + { + if (type == StackItemType.Array) + return new Array(ReferenceCounter, new List(_array)); + return base.ConvertTo(type); + } + + public override bool Equals(StackItem? other) + { + throw new NotSupportedException(); + } + + internal override bool Equals(StackItem? other, ExecutionEngineLimits limits) + { + if (other is not Struct s) return false; + Stack stack1 = new(); + Stack stack2 = new(); + stack1.Push(this); + stack2.Push(s); + uint count = limits.MaxStackSize; + uint maxComparableSize = limits.MaxComparableSize; + while (stack1.Count > 0) + { + if (count-- == 0) + throw new InvalidOperationException("Too many struct items to compare."); + StackItem a = stack1.Pop(); + StackItem b = stack2.Pop(); + if (a is ByteString byteString) + { + if (!byteString.Equals(b, ref maxComparableSize)) return false; + } + else + { + if (maxComparableSize == 0) + throw new InvalidOperationException("The operand exceeds the maximum comparable size."); + maxComparableSize -= 1; + if (a is Struct sa) + { + if (ReferenceEquals(a, b)) continue; + if (b is not Struct sb) return false; + if (sa.Count != sb.Count) return false; + foreach (StackItem item in sa) + stack1.Push(item); + foreach (StackItem item in sb) + stack2.Push(item); + } + else + { + if (!a.Equals(b)) return false; + } + } + } + return true; + } + } +} diff --git a/src/Neo.VM/Unsafe.cs b/src/Neo.VM/Unsafe.cs new file mode 100644 index 0000000000..71d31311ae --- /dev/null +++ b/src/Neo.VM/Unsafe.cs @@ -0,0 +1,41 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + unsafe internal static class Unsafe + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool NotZero(ReadOnlySpan x) + { + int len = x.Length; + if (len == 0) return false; + fixed (byte* xp = x) + { + long* xlp = (long*)xp; + for (; len >= 8; len -= 8) + { + if (*xlp != 0) return true; + xlp++; + } + byte* xbp = (byte*)xlp; + for (; len > 0; len--) + { + if (*xbp != 0) return true; + xbp++; + } + } + return false; + } + } +} diff --git a/src/Neo.VM/Utility.cs b/src/Neo.VM/Utility.cs new file mode 100644 index 0000000000..6601df9400 --- /dev/null +++ b/src/Neo.VM/Utility.cs @@ -0,0 +1,89 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Neo.VM +{ + internal static class Utility + { + public static Encoding StrictUTF8 { get; } + + static Utility() + { + StrictUTF8 = (Encoding)Encoding.UTF8.Clone(); + StrictUTF8.DecoderFallback = DecoderFallback.ExceptionFallback; + StrictUTF8.EncoderFallback = EncoderFallback.ExceptionFallback; + } + + public static BigInteger ModInverse(this BigInteger value, BigInteger modulus) + { + if (value <= 0) throw new ArgumentOutOfRangeException(nameof(value)); + if (modulus < 2) throw new ArgumentOutOfRangeException(nameof(modulus)); + BigInteger r = value, old_r = modulus, s = 1, old_s = 0; + while (r > 0) + { + BigInteger q = old_r / r; + (old_r, r) = (r, old_r % r); + (old_s, s) = (s, old_s - q * s); + } + BigInteger result = old_s % modulus; + if (result < 0) result += modulus; + if (!(value * result % modulus).IsOne) throw new InvalidOperationException(); + return result; + } + + public static BigInteger Sqrt(this BigInteger value) + { + if (value < 0) throw new InvalidOperationException("value can not be negative"); + if (value.IsZero) return BigInteger.Zero; + if (value < 4) return BigInteger.One; + + var z = value; + var x = BigInteger.One << (int)(((value - 1).GetBitLength() + 1) >> 1); + while (x < z) + { + z = x; + x = (value / x + x) / 2; + } + + return z; + } + +#if !NET5_0_OR_GREATER + static int GetBitLength(this BigInteger i) + { + byte[] b = i.ToByteArray(); + return (b.Length - 1) * 8 + BitLen(i.Sign > 0 ? b[b.Length - 1] : 255 - b[b.Length - 1]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static int BitLen(int w) + { + return (w < 1 << 15 ? (w < 1 << 7 + ? (w < 1 << 3 ? (w < 1 << 1 + ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1) + : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5 + ? (w < 1 << 4 ? 4 : 5) + : (w < 1 << 6 ? 6 : 7))) + : (w < 1 << 11 + ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11)) + : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19 + ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19)) + : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27 + ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27)) + : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))))); + } +#endif + } +} diff --git a/src/Neo.VM/VMState.cs b/src/Neo.VM/VMState.cs new file mode 100644 index 0000000000..6d441120bb --- /dev/null +++ b/src/Neo.VM/VMState.cs @@ -0,0 +1,38 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.VM +{ + /// + /// Indicates the status of the VM. + /// + public enum VMState : byte + { + /// + /// Indicates that the execution is in progress or has not yet begun. + /// + NONE = 0, + + /// + /// Indicates that the execution has been completed successfully. + /// + HALT = 1 << 0, + + /// + /// Indicates that the execution has ended, and an exception that cannot be caught is thrown. + /// + FAULT = 1 << 1, + + /// + /// Indicates that a breakpoint is currently being hit. + /// + BREAK = 1 << 2, + } +} diff --git a/src/Neo.VM/VMUnhandledException.cs b/src/Neo.VM/VMUnhandledException.cs new file mode 100644 index 0000000000..7d3da757c5 --- /dev/null +++ b/src/Neo.VM/VMUnhandledException.cs @@ -0,0 +1,52 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Types; +using System; +using System.Text; +using Array = Neo.VM.Types.Array; + +namespace Neo.VM +{ + /// + /// Represents an unhandled exception in the VM. + /// Thrown when there is an exception in the VM that is not caught by any script. + /// + public class VMUnhandledException : Exception + { + /// + /// The unhandled exception in the VM. + /// + public StackItem ExceptionObject { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The unhandled exception in the VM. + public VMUnhandledException(StackItem ex) : base(GetExceptionMessage(ex)) + { + ExceptionObject = ex; + } + + private static string GetExceptionMessage(StackItem e) + { + StringBuilder sb = new("An unhandled exception was thrown."); + ByteString? s = e as ByteString; + if (s is null && e is Array array && array.Count > 0) + s = array[0] as ByteString; + if (s != null) + { + sb.Append(' '); + sb.Append(Encoding.UTF8.GetString(s.GetSpan())); + } + return sb.ToString(); + } + } +} diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 31026ce74f..2d3a8a04cc 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -13,12 +13,12 @@ - + diff --git a/tests/Neo.VM.Tests/Converters/ScriptConverter.cs b/tests/Neo.VM.Tests/Converters/ScriptConverter.cs new file mode 100644 index 0000000000..c0610a573c --- /dev/null +++ b/tests/Neo.VM.Tests/Converters/ScriptConverter.cs @@ -0,0 +1,152 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.VM; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Neo.Test.Converters +{ + internal class ScriptConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(byte[]) || objectType == typeof(string); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch (reader.TokenType) + { + case JsonToken.String: + { + if (reader.Value is string str) + { + Assert.IsTrue(str.StartsWith("0x"), $"'0x' prefix required for value: '{str}'"); + return str.FromHexString(); + } + break; + } + case JsonToken.Bytes: + { + if (reader.Value is byte[] data) return data; + break; + } + case JsonToken.StartArray: + { + using var script = new ScriptBuilder(); + + foreach (var entry in JArray.Load(reader)) + { + var mul = 1; + var value = entry.Value(); + + if (Enum.IsDefined(typeof(OpCode), value) && Enum.TryParse(value, out var opCode)) + { + for (int x = 0; x < mul; x++) + { + script.Emit(opCode); + } + } + else + { + for (int x = 0; x < mul; x++) + { + Assert.IsTrue(value.StartsWith("0x"), $"'0x' prefix required for value: '{value}'"); + script.EmitRaw(value.FromHexString()); + } + } + } + + return script.ToArray(); + } + } + + throw new FormatException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value is byte[] data) + { + int ip = 0; + var array = new JArray(); + + try + { + for (ip = 0; ip < data.Length;) + { + var instruction = new Instruction(data, ip); + + array.Add(instruction.OpCode.ToString().ToUpperInvariant()); + + // Operand Size + + if (instruction.Size - 1 - instruction.Operand.Length > 0) + { + array.Add(data.Skip(ip + 1).Take(instruction.Size - 1 - instruction.Operand.Length).ToArray().ToHexString()); + } + + if (!instruction.Operand.IsEmpty) + { + // Data + + array.Add(instruction.Operand.ToArray().ToHexString()); + } + + ip += instruction.Size; + } + } + catch + { + // Something was wrong, but maybe it's intentioned + + if (Enum.IsDefined(typeof(OpCode), data[ip])) + { + // Check if it was the content and not the opcode + + array.Add(((OpCode)data[ip]).ToString().ToUpperInvariant()); + array.Add(data[(ip + 1)..].ToHexString()); + } + else + { + array.Add(data[ip..].ToHexString()); + } + } + + // Write the script + + writer.WriteStartArray(); + foreach (var entry in array) writer.WriteValue(entry.Value()); + writer.WriteEndArray(); + + // Double check - Ensure that the format is exactly the same + + using var script = new ScriptBuilder(); + + foreach (var entry in array) + { + if (Enum.TryParse(entry.Value(), out var opCode)) + { + script.Emit(opCode); + } + else + { + script.EmitRaw(entry.Value().FromHexString()); + } + } + + if (script.ToArray().ToHexString() != data.ToHexString()) + { + throw new FormatException(); + } + } + else + { + throw new FormatException(); + } + } + } +} diff --git a/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs b/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs new file mode 100644 index 0000000000..b1b168a3be --- /dev/null +++ b/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using System; + +namespace Neo.Test.Converters +{ + internal class UppercaseEnum : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType.IsEnum; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return Enum.Parse(objectType, reader.Value.ToString(), true); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString().ToUpperInvariant()); + } + } +} diff --git a/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs b/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs new file mode 100644 index 0000000000..6f0c4d73d5 --- /dev/null +++ b/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs @@ -0,0 +1,47 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; + +namespace Neo.Test.Extensions +{ + public static class JsonExtensions + { + private static readonly JsonSerializerSettings _settings; + + /// + /// Static constructor + /// + static JsonExtensions() + { + _settings = new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore, + }; + + _settings.Converters.Add(new StringEnumConverter(new CamelCaseNamingStrategy())); + } + + /// + /// Deserialize json to object + /// + /// Type + /// Json + /// Unit test + public static T DeserializeJson(this string input) + { + return JsonConvert.DeserializeObject(input, _settings); + } + + /// + /// Serialize UT to json + /// + /// Unit test + /// Json + public static string ToJson(this object ut) + { + return JsonConvert.SerializeObject(ut, _settings); + } + } +} diff --git a/tests/Neo.VM.Tests/Extensions/StringExtensions.cs b/tests/Neo.VM.Tests/Extensions/StringExtensions.cs new file mode 100644 index 0000000000..cab595568b --- /dev/null +++ b/tests/Neo.VM.Tests/Extensions/StringExtensions.cs @@ -0,0 +1,57 @@ +using System; +using System.Globalization; + +namespace Neo.Test.Extensions +{ + internal static class StringExtensions + { + /// + /// Convert buffer to hex string + /// + /// Data + /// Return hex string + public static string ToHexString(this byte[] data) + { + if (data == null) return ""; + + var m = data.Length; + if (m == 0) return ""; + + var sb = new char[(m * 2) + 2]; + + sb[0] = '0'; + sb[1] = 'x'; + + for (int x = 0, y = 2; x < m; x++, y += 2) + { + var hex = data[x].ToString("x2"); + + sb[y] = hex[0]; + sb[y + 1] = hex[1]; + } + + return new string(sb); + } + + /// + /// Convert string in Hex format to byte array + /// + /// Hexadecimal string + /// Return byte array + public static byte[] FromHexString(this string value) + { + if (string.IsNullOrEmpty(value)) + return Array.Empty(); + if (value.StartsWith("0x")) + value = value[2..]; + if (value.Length % 2 == 1) + throw new FormatException(); + + var result = new byte[value.Length / 2]; + for (var i = 0; i < result.Length; i++) + result[i] = byte.Parse(value.Substring(i * 2, 2), NumberStyles.AllowHexSpecifier); + + return result; + } + } +} diff --git a/tests/Neo.VM.Tests/Helpers/RandomHelper.cs b/tests/Neo.VM.Tests/Helpers/RandomHelper.cs new file mode 100644 index 0000000000..53085b44d5 --- /dev/null +++ b/tests/Neo.VM.Tests/Helpers/RandomHelper.cs @@ -0,0 +1,39 @@ +using System; + +namespace Neo.Test.Helpers +{ + public class RandomHelper + { + private const string _randchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static readonly Random _rand = new(); + + /// + /// Get random buffer + /// + /// Length + /// Buffer + public static byte[] RandBuffer(int length) + { + var buffer = new byte[length]; + _rand.NextBytes(buffer); + return buffer; + } + + /// + /// Get random string + /// + /// Length + /// Buffer + public static string RandString(int length) + { + var stringChars = new char[length]; + + for (int i = 0; i < stringChars.Length; i++) + { + stringChars[i] = _randchars[_rand.Next(_randchars.Length)]; + } + + return new string(stringChars); + } + } +} diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj new file mode 100644 index 0000000000..b86f27296a --- /dev/null +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -0,0 +1,21 @@ + + + + net7.0 + 9.0 + Neo.Test + true + false + + + + + + + + + PreserveNewest + + + + diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GE.json new file mode 100644 index 0000000000..d70ebf3be6 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GE.json @@ -0,0 +1,443 @@ +{ + "category": "Numeric", + "name": "GE same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [0,0]", + "script": [ + "PUSH0", + "PUSH0", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [1,0]", + "script": [ + "PUSH1", + "PUSH0", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [0,1]", + "script": [ + "PUSH0", + "PUSH1", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [null,1]", + "script": [ + "PUSHNULL", + "PUSH1", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,null]", + "script": [ + "PUSH1", + "PUSHNULL", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "null" + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "FAULT test [1,array]", + "script": [ + "PUSH1", + "NEWARRAY0", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GT.json new file mode 100644 index 0000000000..edc0767b3c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GT.json @@ -0,0 +1,443 @@ +{ + "category": "Numeric", + "name": "GT same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [0,0]", + "script": [ + "PUSH0", + "PUSH0", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,0]", + "script": [ + "PUSH1", + "PUSH0", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [0,1]", + "script": [ + "PUSH0", + "PUSH1", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [null,1]", + "script": [ + "PUSHNULL", + "PUSH1", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,null]", + "script": [ + "PUSH1", + "PUSHNULL", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "null" + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "FAULT test [1,array]", + "script": [ + "PUSH1", + "NEWARRAY0", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LE.json new file mode 100644 index 0000000000..eb85215322 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LE.json @@ -0,0 +1,443 @@ +{ + "category": "Numeric", + "name": "LE same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [0,0]", + "script": [ + "PUSH0", + "PUSH0", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [1,0]", + "script": [ + "PUSH1", + "PUSH0", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [0,1]", + "script": [ + "PUSH0", + "PUSH1", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [null,1]", + "script": [ + "PUSHNULL", + "PUSH1", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,null]", + "script": [ + "PUSH1", + "PUSHNULL", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "null" + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "FAULT test [1,array]", + "script": [ + "PUSH1", + "NEWARRAY0", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LT.json new file mode 100644 index 0000000000..ed2b6fac01 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LT.json @@ -0,0 +1,443 @@ +{ + "category": "Numeric", + "name": "LT same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [0,0]", + "script": [ + "PUSH0", + "PUSH0", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,0]", + "script": [ + "PUSH1", + "PUSH0", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [0,1]", + "script": [ + "PUSH0", + "PUSH1", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [null,1]", + "script": [ + "PUSHNULL", + "PUSH1", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,null]", + "script": [ + "PUSH1", + "PUSHNULL", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "null" + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "FAULT test [1,array]", + "script": [ + "PUSH1", + "NEWARRAY0", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODMUL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODMUL.json new file mode 100644 index 0000000000..e3b93bfb56 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODMUL.json @@ -0,0 +1,141 @@ +{ + "category": "Numeric", + "name": "MODMUL", + "tests": [ + { + "name": "Exception - Without items", + "script": [ + "MODMUL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "MODMUL", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Real test (8 * 2 % 3)", + "script": [ + "PUSH8", + "PUSH2", + "PUSH3", + "MODMUL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "MODMUL", + "evaluationStack": [ + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 8 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test (16 * 2 % 4)", + "script": [ + "PUSH16", + "PUSH2", + "PUSH4", + "MODMUL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "MODMUL", + "evaluationStack": [ + { + "type": "Integer", + "value": 4 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 16 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODPOW.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODPOW.json new file mode 100644 index 0000000000..68efa97efa --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODPOW.json @@ -0,0 +1,145 @@ +{ + "category": "Numeric", + "name": "MODPOW", + "tests": [ + { + "name": "Exception - Without items", + "script": [ + "MODPOW" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "MODPOW", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Real test (19 ModInverse 141 = 52)", + "script": [ + "PUSHINT8", + "0x13", + "PUSHM1", + "PUSHINT16", + "0x8d00", + "MODPOW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "MODPOW", + "evaluationStack": [ + { + "type": "Integer", + "value": 141 + }, + { + "type": "Integer", + "value": -1 + }, + { + "type": "Integer", + "value": 19 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 52 + } + ] + } + } + ] + }, + { + "name": "Real test (ModPow 19, 2, 141 = 79)", + "script": [ + "PUSHINT8", + "0x13", + "PUSH2", + "PUSHINT16", + "0x8d00", + "MODPOW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "MODPOW", + "evaluationStack": [ + { + "type": "Integer", + "value": 141 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 19 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 79 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NOT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NOT.json new file mode 100644 index 0000000000..72d36c6fc7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NOT.json @@ -0,0 +1,537 @@ +{ + "category": "Numeric", + "name": "NOT", + "tests": [ + { + "name": "Without push", + "script": [ + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With bool", + "script": [ + "PUSH1", + "NOT", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "With integer 0x03", + "script": [ + "PUSH3", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With map", + "script": [ + "NEWMAP", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With array", + "script": [ + "PUSH0", + "NEWARRAY", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With struct", + "script": [ + "PUSH0", + "NEWSTRUCT", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With byte array 0x0000", + "script": [ + "PUSHDATA1", + "0x02", + "0x0000", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "With byte array 0x0001", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With interop", + "script": [ + "SYSCALL", + "0x77777777", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMEQUAL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMEQUAL.json new file mode 100644 index 0000000000..613a2bd31d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMEQUAL.json @@ -0,0 +1,1058 @@ +{ + "category": "Numeric", + "name": "NUMEQUAL same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=true", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=false", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=true", + "script": [ + "PUSH1", + "PUSH1", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=false", + "script": [ + "PUSH2", + "PUSH1", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=Fault", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array,Array]=fault", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSH0", + "NEWARRAY", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault with clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault without clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH0", + "NEWSTRUCT", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH1", + "NEWSTRUCT", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=Fault", + "script": [ + "NEWMAP", + "DUP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=Fault", + "script": [ + "NEWMAP", + "NEWMAP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false same length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=fault", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Interop,Interop]=fault", + "script": [ + "SYSCALL", + "0x77777777", + "SYSCALL", + "0x77777777", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMNOTEQUAL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMNOTEQUAL.json new file mode 100644 index 0000000000..386212cfed --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMNOTEQUAL.json @@ -0,0 +1,1058 @@ +{ + "category": "Numeric", + "name": "NUMNOTEQUAL same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=false", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=true", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=false", + "script": [ + "PUSH1", + "PUSH1", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=true", + "script": [ + "PUSH2", + "PUSH1", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=Fault", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array,Array]=fault", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSH0", + "NEWARRAY", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault with clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault without clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH0", + "NEWSTRUCT", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH1", + "NEWSTRUCT", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=Fault", + "script": [ + "NEWMAP", + "DUP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=Fault", + "script": [ + "NEWMAP", + "NEWMAP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true same length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=fault", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Interop,Interop]=fault", + "script": [ + "SYSCALL", + "0x77777777", + "SYSCALL", + "0x77777777", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/POW.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/POW.json new file mode 100644 index 0000000000..c9a100e2e4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/POW.json @@ -0,0 +1,195 @@ +{ + "category": "Numeric", + "name": "POW", + "tests": [ + { + "name": "Exception - Without items", + "script": [ + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "POW", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Exception - With only one item", + "script": [ + "PUSH1", + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "POW", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Real test 1", + "script": [ + "PUSH1", + "PUSH1", + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test 1", + "script": [ + "PUSH9", + "PUSH2", + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 81 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 81 + } + ] + } + } + ] + }, + { + "name": "Real test 1", + "script": [ + "PUSH2", + "PUSH9", + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 512 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 512 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHL.json new file mode 100644 index 0000000000..7e660f6c92 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHL.json @@ -0,0 +1,245 @@ +{ + "category": "Numeric", + "name": "SHL", + "tests": [ + { + "name": "Exception - Above the limit 0 << 257", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0x0101", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0101" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Exception - Below the limit 0 << -257", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0xfffe", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0xFFFE" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test 0 << 256", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0x0001", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0001" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test 16 << 4", + "script": [ + "PUSH16", + "PUSH4", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 16 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 256 + } + ] + } + } + ] + }, + { + "name": "Real test 16 << 0", + "script": [ + "PUSH16", + "PUSH0", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 16 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 16 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHR.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHR.json new file mode 100644 index 0000000000..818364e92a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHR.json @@ -0,0 +1,247 @@ +{ + "category": "Numeric", + "name": "SHR", + "tests": [ + { + "name": "Exception - Above the limit 0 >> 257", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0x0101", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0101" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Exception - Below the limit 0 >> -257", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0xfffe", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0xFFFE" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test 0 >> 256", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0x0001", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0001" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test 256 >> 0", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "PUSH0", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + } + ] + }, + { + "name": "Real test 4 >> 16", + "script": [ + "PUSH4", + "PUSH16", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "integer", + "value": 16 + }, + { + "type": "integer", + "value": 4 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SIGN.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SIGN.json new file mode 100644 index 0000000000..24111873f9 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SIGN.json @@ -0,0 +1,496 @@ +{ + "category": "Numeric", + "name": "SIGN", + "tests": [ + { + "name": "Without push", + "script": [ + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With bool", + "script": [ + "PUSH1", + "NOT", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "With integer 0x03", + "script": [ + "PUSH3", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "With integer -1", + "script": [ + "PUSHM1", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": -1 + } + ] + } + } + ] + }, + { + "name": "With map", + "script": [ + "NEWMAP", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With array", + "script": [ + "PUSH0", + "NEWARRAY", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With struct", + "script": [ + "PUSH0", + "NEWSTRUCT", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With byte array 0x0000", + "script": [ + "PUSHDATA1", + "0x02", + "0x0000", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "With byte array 0x0001", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "With interop", + "script": [ + "SYSCALL", + "0x77777777", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SQRT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SQRT.json new file mode 100644 index 0000000000..8b63674edd --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SQRT.json @@ -0,0 +1,216 @@ +{ + "category": "Numeric", + "name": "SQRT", + "tests": [ + { + "name": "Exception - Without items", + "script": [ + "SQRT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SQRT", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Real test 1", + "script": [ + "PUSH1", + "SQRT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test with 81", + "script": [ + "PUSHINT8", + "0x51", + "SQRT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 9 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 9 + } + ] + } + } + ] + }, + { + "name": "Real test with 15625", + "script": [ + "PUSHINT16", + "0x093d", + "SQRT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 125 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 125 + } + ] + } + } + ] + }, + { + "name": "Real test with 4", + "script": [ + "PUSHINT8", + "0x04", + "SQRT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 2 + } + ] + } + } + ] + }, + { + "name": "Real test with 2", + "script": [ + "PUSHINT8", + "0x02", + "SQRT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/APPEND.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/APPEND.json new file mode 100644 index 0000000000..61593452e7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/APPEND.json @@ -0,0 +1,679 @@ +{ + "category": "Arrays", + "name": "APPEND", + "tests": [ + { + "name": "Without push", + "script": [ + "PUSH1", + "APPEND" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without array", + "script": [ + "PUSH1", + "PUSH2", + "APPEND" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Clone test [Array]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH0", + "NEWARRAY", + "DUP", + "PUSH5", + "APPEND", + "STSFLD0", + "PUSH0", + "NEWARRAY", + "DUP", + "LDSFLD0", + "APPEND", + "LDSFLD0", + "PUSH6", + "APPEND", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "PUSH0", + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "array", + "value": [] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "LDSFLD0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 17, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone test [Struct]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH0", + "NEWSTRUCT", + "DUP", + "PUSH5", + "APPEND", + "STSFLD0", + "PUSH0", + "NEWSTRUCT", + "DUP", + "LDSFLD0", + "APPEND", + "LDSFLD0", + "PUSH6", + "APPEND", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "PUSH0", + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "struct", + "value": [] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "LDSFLD0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 17, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "PUSH5", + "APPEND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "APPEND", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "PUSH5", + "APPEND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "APPEND", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/CLEARITEMS.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/CLEARITEMS.json new file mode 100644 index 0000000000..20f82d0a34 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/CLEARITEMS.json @@ -0,0 +1,126 @@ +{ + "category": "Arrays", + "name": "CLEARITEMS", + "tests": [ + { + "name": "Without push", + "script": [ + "CLEARITEMS" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type", + "script": [ + "PUSH2", + "CLEARITEMS" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH0", + "PUSH1", + "PUSH2", + "PACK", + "DUP", + "CLEARITEMS" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [] + } + ] + } + } + ] + }, + { + "name": "Real test [Map]", + "script": [ + "NEWMAP", + "DUP", + "PUSH0", + "PUSH0", + "SETITEM", + "DUP", + "CLEARITEMS" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Map", + "value": {} + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/HASKEY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/HASKEY.json new file mode 100644 index 0000000000..213087bd29 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/HASKEY.json @@ -0,0 +1,276 @@ +{ + "category": "Arrays", + "name": "HASKEY", + "tests": [ + { + "name": "Without push", + "script": [ + "HASKEY" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong key type", + "script": [ + "PUSH1", + "NEWARRAY", + "NEWMAP", + "HASKEY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "HASKEY", + "evaluationStack": [ + { + "type": "Map", + "value": {} + }, + { + "type": "Array", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSH2", + "NEWBUFFER", + "PUSH0", + "HASKEY" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Map]", + "script": [ + "INITSSLOT", + "0x01", + "NEWMAP", + "DUP", + "STSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "PUSH3", + "HASKEY", + "DROP", + "LDSFLD0", + "PUSH1", + "HASKEY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "HASKEY", + "evaluationStack": [ + { + "type": "Integer", + "value": 3 + }, + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ], + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "DROP", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ], + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Check key size [Map]", + "script": [ + "NEWMAP", + "PUSHINT8", + "0x41", + "NEWBUFFER", + "CONVERT", + "0x28", + "HASKEY" + ], + "steps": [ + { + "actions": [ + "stepinto", + "stepinto", + "stepinto", + "stepinto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "HASKEY", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepinto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "HASKEY", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/KEYS.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/KEYS.json new file mode 100644 index 0000000000..fb6a9d985c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/KEYS.json @@ -0,0 +1,63 @@ +{ + "category": "Arrays", + "name": "KEYS", + "tests": [ + { + "name": "Keys in map", + "script": [ + "NEWMAP", + "DUP", + "DUP", + "PUSH0", + "PUSH0", + "SETITEM", + "PUSH1", + "PUSH1", + "SETITEM", + "KEYS" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 0 + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + } + ] + }, + { + "name": "Invalid StackItem [Integer!=Map]", + "script": [ + "PUSH0", + "KEYS" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY.json new file mode 100644 index 0000000000..5244c72f4e --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY.json @@ -0,0 +1,168 @@ +{ + "category": "Arrays", + "name": "NEWARRAY", + "tests": [ + { + "name": "Without push", + "script": [ + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With wrong type", + "script": [ + "NEWMAP", + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With negative push", + "script": [ + "PUSHM1", + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH2", + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone Struct to Array", + "script": [ + "PUSH1", + "NEWSTRUCT", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NEWARRAY", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY0.json new file mode 100644 index 0000000000..21cd6436e2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY0.json @@ -0,0 +1,28 @@ +{ + "category": "Arrays", + "name": "NEWARRAY0", + "tests": [ + { + "name": "Real test", + "script": [ + "NEWARRAY0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY_T.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY_T.json new file mode 100644 index 0000000000..d1cea504ad --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY_T.json @@ -0,0 +1,289 @@ +{ + "category": "Arrays", + "name": "NEWARRAY_T", + "tests": [ + { + "name": "Real test [Any]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Pointer]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x10" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Integer]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": 0 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x28" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "0x" + }, + { + "type": "ByteString", + "value": "0x" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x30" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x40" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x41" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Map]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x48" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [InteropInterface]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x60" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWMAP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWMAP.json new file mode 100644 index 0000000000..a7000735d5 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWMAP.json @@ -0,0 +1,48 @@ +{ + "category": "Arrays", + "name": "NEWMAP", + "tests": [ + { + "name": "Real test", + "script": [ + "NEWMAP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "map", + "value": {} + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT.json new file mode 100644 index 0000000000..dbe9547dde --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT.json @@ -0,0 +1,168 @@ +{ + "category": "Arrays", + "name": "NEWSTRUCT", + "tests": [ + { + "name": "Without push", + "script": [ + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With wrong type", + "script": [ + "NEWMAP", + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With negative push", + "script": [ + "PUSHM1", + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH2", + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone Array to Struct", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NEWSTRUCT", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT0.json new file mode 100644 index 0000000000..62d5a595d3 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT0.json @@ -0,0 +1,28 @@ +{ + "category": "Arrays", + "name": "NEWSTRUCT0", + "tests": [ + { + "name": "Real test", + "script": [ + "NEWSTRUCT0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Struct", + "value": [] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACK.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACK.json new file mode 100644 index 0000000000..e4cc0f40ee --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACK.json @@ -0,0 +1,127 @@ +{ + "category": "Arrays", + "name": "PACK", + "tests": [ + { + "name": "Real test", + "script": [ + "PUSH5", + "PUSH6", + "PUSH2", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Not enough size", + "script": [ + "PUSH5", + "PUSH2", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "NEWMAP", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH1", + "NEWARRAY", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Struct]", + "script": [ + "PUSH1", + "NEWSTRUCT", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without items", + "script": [ + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKMAP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKMAP.json new file mode 100644 index 0000000000..dd68bd19c1 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKMAP.json @@ -0,0 +1,127 @@ +{ + "category": "Arrays", + "name": "PACKMAP", + "tests": [ + { + "name": "Real test", + "script": [ + "PUSH5", + "PUSH6", + "PUSH1", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Map", + "value": { + "0x06": { + "type": "Integer", + "value": "5" + } + } + } + ] + } + } + ] + }, + { + "name": "Not enough size", + "script": [ + "PUSH5", + "PUSH1", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "PUSH1", + "PUSH1", + "NEWMAP", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH1", + "PUSH1", + "NEWARRAY", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Struct]", + "script": [ + "PUSH1", + "PUSH1", + "NEWSTRUCT", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without items", + "script": [ + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKSTRUCT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKSTRUCT.json new file mode 100644 index 0000000000..e0517d27b9 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKSTRUCT.json @@ -0,0 +1,127 @@ +{ + "category": "Arrays", + "name": "PACK", + "tests": [ + { + "name": "Real test", + "script": [ + "PUSH5", + "PUSH6", + "PUSH2", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Not enough size", + "script": [ + "PUSH5", + "PUSH2", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "NEWMAP", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH1", + "NEWARRAY", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Struct]", + "script": [ + "PUSH1", + "NEWSTRUCT", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without items", + "script": [ + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PICKITEM.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PICKITEM.json new file mode 100644 index 0000000000..19a6f54a8c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PICKITEM.json @@ -0,0 +1,714 @@ +{ + "category": "Arrays", + "name": "PICKITEM", + "tests": [ + { + "name": "Wrong array", + "script": [ + "PUSH0", + "PUSH0", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong key type", + "script": [ + "PUSH1", + "NEWARRAY", + "NEWMAP", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds [Array]", + "script": [ + "PUSH2", + "NEWARRAY", + "PUSH3", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds [Struct]", + "script": [ + "PUSH2", + "NEWSTRUCT", + "PUSH3", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH3", + "NEWARRAY", + "STSFLD0", + "LDSFLD0", + "PUSH0", + "PUSH1", + "SETITEM", + "LDSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "PUSH2", + "PUSH3", + "SETITEM", + "LDSFLD0", + "PUSH2", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 20, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH3", + "NEWSTRUCT", + "STSFLD0", + "LDSFLD0", + "PUSH0", + "PUSH1", + "SETITEM", + "LDSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "PUSH2", + "PUSH3", + "SETITEM", + "LDSFLD0", + "PUSH2", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 20, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "OutOfBounds with -1 [ByteString]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "PUSHM1", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "ByteString", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "OutOfBounds with more than length [ByteString]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "PUSH4", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "ByteString", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "PUSH0", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "PUSH0", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + }, + { + "type": "Buffer", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REMOVE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REMOVE.json new file mode 100644 index 0000000000..cba3a4d0a7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REMOVE.json @@ -0,0 +1,299 @@ +{ + "category": "Arrays", + "name": "REMOVE", + "tests": [ + { + "name": "Without push", + "script": [ + "PUSH1", + "REMOVE" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without array", + "script": [ + "PUSH1", + "PUSH2", + "REMOVE" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong key", + "script": [ + "PUSH2", + "NEWMAP", + "REMOVE" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds", + "script": [ + "PUSH6", + "PUSH5", + "PUSH2", + "PACK", + "PUSH2", + "REMOVE" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH6", + "PUSH5", + "PUSH2", + "PACK", + "STSFLD0", + "LDSFLD0", + "PUSH0", + "REMOVE", + "LDSFLD0", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "REMOVE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 6 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 6 + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH0", + "NEWSTRUCT", + "DUP", + "PUSH5", + "APPEND", + "STSFLD0", + "LDSFLD0", + "PUSH0", + "REMOVE", + "LDSFLD0", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "REMOVE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REVERSEITEMS.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REVERSEITEMS.json new file mode 100644 index 0000000000..b4dec58eaf --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REVERSEITEMS.json @@ -0,0 +1,138 @@ +{ + "category": "Arrays", + "name": "REVERSEITEMS", + "tests": [ + { + "name": "Without push", + "script": [ + "REVERSEITEMS" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without Array", + "script": [ + "PUSH9", + "REVERSEITEMS" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH9", + "PUSH8", + "PUSH2", + "PACK", + "DUP", + "REVERSEITEMS" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 9 + }, + { + "type": "Integer", + "value": 8 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 9 + }, + { + "type": "Integer", + "value": 8 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "CONVERT", + "0x30", + "DUP", + "REVERSEITEMS" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x030201" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SETITEM.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SETITEM.json new file mode 100644 index 0000000000..0ed33f2968 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SETITEM.json @@ -0,0 +1,1226 @@ +{ + "category": "Arrays", + "name": "SETITEM", + "tests": [ + { + "name": "Map in key", + "script": [ + "PUSH1", + "NEWMAP", + "PUSH0", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without array", + "script": [ + "PUSH0", + "PUSH0", + "PUSH0", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds [Array]", + "script": [ + "PUSH1", + "NEWARRAY", + "PUSH1", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds [Struct]", + "script": [ + "PUSH1", + "NEWSTRUCT", + "PUSH1", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map]", + "script": [ + "INITSSLOT", + "0x01", + "NEWMAP", + "DUP", + "STSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "PUSH3", + "PUSH4", + "SETITEM", + "LDSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ], + "staticFields": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "map", + "value": {} + } + ], + "staticFields": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ], + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + }, + "0x03": { + "type": "Integer", + "value": 4 + } + } + } + ], + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + }, + "0x03": { + "type": "Integer", + "value": 4 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + }, + "0x03": { + "type": "Integer", + "value": 4 + } + } + } + ] + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "PUSH1", + "NEWSTRUCT", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone test [Array]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "STSFLD0", + "LDSFLD0", + "DUP", + "PUSH0", + "PUSH4", + "SETITEM", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + } + ], + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "STSFLD0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "LDSFLD0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone test [Struct]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "NEWSTRUCT", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "STSFLD0", + "LDSFLD0", + "DUP", + "PUSH0", + "PUSH4", + "SETITEM", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + } + ], + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "STSFLD0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "LDSFLD0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "Buffer", + "value": "0x0102" + }, + { + "type": "Buffer", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x0502" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SIZE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SIZE.json new file mode 100644 index 0000000000..fa2907411d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SIZE.json @@ -0,0 +1,266 @@ +{ + "category": "Arrays", + "name": "SIZE", + "tests": [ + { + "name": "Wrong type SYSCALL[0x77777777]+SIZE", + "script": [ + "SYSCALL", + "0x77777777", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SIZE", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without PUSH+SIZE", + "script": [ + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test with ByteString", + "script": [ + "PUSHDATA1", + "0x01", + "0x00", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test with Buffer", + "script": [ + "PUSH10", + "NEWBUFFER", + "SIZE" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 10 + } + ] + } + } + ] + }, + { + "name": "Real test with array", + "script": [ + "PUSH3", + "NEWARRAY", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test with struct", + "script": [ + "PUSH3", + "NEWSTRUCT", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test with map", + "script": [ + "NEWMAP", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/UNPACK.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/UNPACK.json new file mode 100644 index 0000000000..63c92aad3a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/UNPACK.json @@ -0,0 +1,168 @@ +{ + "category": "Arrays", + "name": "UNPACK", + "tests": [ + { + "name": "Without array", + "script": [ + "PUSH10", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "PUSH5", + "PUSH6", + "PUSH2", + "PACK", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "UNPACK", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 6 + }, + { + "type": "integer", + "value": 5 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 6 + }, + { + "type": "integer", + "value": 5 + } + ] + } + } + ] + }, + { + "name": "With map", + "script": [ + "PUSH5", + "PUSH6", + "PUSH1", + "PACKMAP", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 5 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/VALUES.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/VALUES.json new file mode 100644 index 0000000000..4cf832eb59 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/VALUES.json @@ -0,0 +1,194 @@ +{ + "category": "Arrays", + "name": "VALUES", + "tests": [ + { + "name": "No StackItem", + "script": [ + "KEYS" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Invalid StackItem [Integer != (Map|Array|Struct)]", + "script": [ + "PUSH0", + "KEYS" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Values in map", + "script": [ + "NEWMAP", + "DUP", + "DUP", + "PUSH0", + "PUSH2", + "SETITEM", + "PUSH1", + "PUSH4", + "SETITEM", + "VALUES" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + } + ] + }, + { + "name": "Simple values in array", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x00", + "VALUES" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Compound value in array [inner struct]", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH2", + "NEWSTRUCT", + "SETITEM", + "VALUES" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + } + ] + }, + { + "name": "Compound value in array [inner map]", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "NEWMAP", + "DUP", + "PUSH0", + "PUSH1", + "SETITEM", + "SETITEM", + "VALUES" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "map", + "value": { + "": { + "type": "Integer", + "value": 1 + } + } + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/AND.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/AND.json new file mode 100644 index 0000000000..f1e1cc7d14 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/AND.json @@ -0,0 +1,811 @@ +{ + "category": "Bitwise Logic", + "name": "AND", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [true,true]=1", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [false,true]=0", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [1,1]=1", + "script": [ + "PUSH1", + "PUSH1", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [1,2]=0", + "script": [ + "PUSH2", + "PUSH1", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=FAULT", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=FAULT", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=FAULT", + "script": [ + "NEWMAP", + "DUP", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=11911212070228631137091015067172167745536", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "11911212070228631137091015067172167745536" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "11911212070228631137091015067172167745536" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=10890364969465815746700891244876863111168", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "10890364969465815746700891244876863111168" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "10890364969465815746700891244876863111168" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=0", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=FAULT", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=FAULT", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/EQUAL.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/EQUAL.json new file mode 100644 index 0000000000..75a484d0db --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/EQUAL.json @@ -0,0 +1,1447 @@ +{ + "category": "Bitwise Logic", + "name": "EQUAL same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=true", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=false", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=true", + "script": [ + "PUSH1", + "PUSH1", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=false", + "script": [ + "PUSH2", + "PUSH1", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=true", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=false", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSH0", + "NEWARRAY", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=true with clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=true without clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH0", + "NEWSTRUCT", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=false", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH1", + "NEWSTRUCT", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Map,Map]=true", + "script": [ + "NEWMAP", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Map,Map]=false", + "script": [ + "NEWMAP", + "NEWMAP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false same length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=true", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Interop,Interop]=false", + "script": [ + "SYSCALL", + "0x77777777", + "SYSCALL", + "0x77777777", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=false", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=false", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAA" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=true", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAA" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/INVERT.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/INVERT.json new file mode 100644 index 0000000000..636e08628b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/INVERT.json @@ -0,0 +1,657 @@ +{ + "category": "Bitwise Logic", + "name": "INVERT", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With 0", + "script": [ + "PUSH0", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": -1 + } + ] + } + } + ] + }, + { + "name": "Real test [true]=-2", + "script": [ + "PUSH0", + "NOT", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": -2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": -2 + } + ] + } + } + ] + }, + { + "name": "Real test [false]=-1", + "script": [ + "PUSH0", + "NOT", + "NOT", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": -1 + } + ] + } + } + ] + }, + { + "name": "Real test [1]=-2", + "script": [ + "PUSH1", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": -2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": -2 + } + ] + } + } + ] + }, + { + "name": "Real test [2]=-3", + "script": [ + "PUSH2", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": -3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": -3 + } + ] + } + } + ] + }, + { + "name": "Real test [Array]=FAULT", + "script": [ + "PUSH0", + "NEWARRAY", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct]=FAULT", + "script": [ + "PUSH0", + "NEWSTRUCT", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map]=FAULT", + "script": [ + "NEWMAP", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString]=-11911212070228631137091015067172167745537", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 20, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "-11911212070228631137091015067172167745537" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "-11911212070228631137091015067172167745537" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString]=-12251494437149569600554389674603935956993", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 20, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "-12251494437149569600554389674603935956993" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "-12251494437149569600554389674603935956993" + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop]=FAULT", + "script": [ + "SYSCALL", + "0x77777777", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=FAULT", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/NOTEQUAL.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/NOTEQUAL.json new file mode 100644 index 0000000000..95acf9509d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/NOTEQUAL.json @@ -0,0 +1,1299 @@ +{ + "category": "Bitwise Logic", + "name": "NOTEQUAL", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "StepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=false", + "script": [ + "PUSH1", + "PUSH1", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=true", + "script": [ + "PUSH2", + "PUSH1", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=false", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=true", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSH0", + "NEWARRAY", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=false with clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=false without clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH0", + "NEWSTRUCT", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=true", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH1", + "NEWSTRUCT", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Map,Map]=false", + "script": [ + "NEWMAP", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Map,Map]=true", + "script": [ + "NEWMAP", + "NEWMAP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true same length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=false", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Interop,Interop]=true", + "script": [ + "SYSCALL", + "0x77777777", + "SYSCALL", + "0x77777777", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=true", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=true", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAA" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=false", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAA" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/OR.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/OR.json new file mode 100644 index 0000000000..fb52b32b71 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/OR.json @@ -0,0 +1,811 @@ +{ + "category": "Bitwise Logic", + "name": "OR", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [true,true]=1", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [false,true]=1", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [1,1]=1", + "script": [ + "PUSH1", + "PUSH1", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [1,2]=3", + "script": [ + "PUSH2", + "PUSH1", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=FAULT", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=FAULT", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=FAULT", + "script": [ + "NEWMAP", + "DUP", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=11911212070228631137091015067172167745536", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "11911212070228631137091015067172167745536" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "11911212070228631137091015067172167745536" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=13272341537912384990944513496899240591360", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "13272341537912384990944513496899240591360" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "13272341537912384990944513496899240591360" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=11959069470373746643343180651838589370368", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "11959069470373746643343180651838589370368" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "11959069470373746643343180651838589370368" + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=FAULT", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=FAULT", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/XOR.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/XOR.json new file mode 100644 index 0000000000..bae4cf557b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/XOR.json @@ -0,0 +1,811 @@ +{ + "category": "Bitwise Logic", + "name": "XOR", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [true,true]=0", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [false,true]=1", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [1,1]=0", + "script": [ + "PUSH1", + "PUSH1", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [1,2]=3", + "script": [ + "PUSH2", + "PUSH1", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=FAULT", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=FAULT", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=FAULT", + "script": [ + "NEWMAP", + "DUP", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=0", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=2381976568446569244243622252022377480192", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "2381976568446569244243622252022377480192" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "2381976568446569244243622252022377480192" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=11959069470373746643343180651838589370368", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "11959069470373746643343180651838589370368" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "11959069470373746643343180651838589370368" + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=FAULT", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=FAULT", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORT.json new file mode 100644 index 0000000000..17c3a35e2e --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORT.json @@ -0,0 +1,22 @@ +{ + "category": "Control", + "name": "ABORT", + "tests": [ + { + "name": "Basic Test", + "script": [ + "ABORT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORTMSG.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORTMSG.json new file mode 100644 index 0000000000..a7e795eb2c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORTMSG.json @@ -0,0 +1,26 @@ +{ + "category": "Control", + "name": "ABORTMSG", + "tests": [ + { + "name": "Basic Test", + "script": [ + "PUSHDATA1", + "0x03", + "0x4e454f", + "ABORTMSG" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT", + "exceptionMessage": "ABORTMSG is executed. Reason: NEO" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERT.json new file mode 100644 index 0000000000..bb7d14c5e8 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERT.json @@ -0,0 +1,42 @@ +{ + "category": "Control", + "name": "ASSERT", + "tests": [ + { + "name": "Fault Test", + "script": [ + "PUSH0", + "ASSERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Halt Test", + "script": [ + "PUSH1", + "ASSERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERTMSG.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERTMSG.json new file mode 100644 index 0000000000..fc4c572ec3 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERTMSG.json @@ -0,0 +1,47 @@ +{ + "category": "Control", + "name": "ASSERTMSG", + "tests": [ + { + "name": "Fault Test", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x04", + "0x4641494c", + "ASSERTMSG" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT", + "exceptionMessage": "ASSERTMSG is executed with false result. Reason: FAIL" + } + } + ] + }, + { + "name": "Halt Test", + "script": [ + "PUSH1", + "PUSHDATA1", + "0x04", + "0x50415353", + "ASSERTMSG" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL.json new file mode 100644 index 0000000000..1b717c3a66 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL.json @@ -0,0 +1,134 @@ +{ + "category": "Control", + "name": "CALL", + "tests": [ + { + "name": "Error negative", + "script": [ + "CALL", + "0xFF00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Error out of bounds", + "script": [ + "CALL", + "0x0A" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "CALL", + "0x03", + "RET", + "PUSH0", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PUSH0" + }, + { + "instructionPointer": 2, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + }, + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALLA.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALLA.json new file mode 100644 index 0000000000..627442a5f1 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALLA.json @@ -0,0 +1,158 @@ +{ + "category": "Control", + "name": "CALLA", + "tests": [ + { + "name": "Wrong type", + "script": [ + "PUSH2", + "CALLA" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CALLA", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHA", + "0x07000000", + "CALLA", + "RET", + "PUSH0", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "CALLA", + "evaluationStack": [ + { + "type": "pointer", + "value": 7 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "PUSH0" + }, + { + "instructionPointer": 6, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + }, + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL_L.json new file mode 100644 index 0000000000..5f60bda0ca --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL_L.json @@ -0,0 +1,134 @@ +{ + "category": "Control", + "name": "CALL_L", + "tests": [ + { + "name": "Error negative", + "script": [ + "CALL_L", + "0x000000FF" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Error out of bounds", + "script": [ + "CALL_L", + "0x0A000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "CALL_L", + "0x06000000", + "RET", + "PUSH0", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "PUSH0" + }, + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + }, + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP.json new file mode 100644 index 0000000000..172e50b956 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP.json @@ -0,0 +1,74 @@ +{ + "category": "Control", + "name": "JMP", + "tests": [ + { + "name": "Out of range [<0]", + "script": [ + "JMP", + "0xff", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of range [>length]", + "script": [ + "JMP", + "0x7f", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "JMP", + "0x02", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ.json new file mode 100644 index 0000000000..3e7a3144ba --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPEQ", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPEQ", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPEQ", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPEQ", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPEQ", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPEQ", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ_L.json new file mode 100644 index 0000000000..78ed4a0e70 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ_L.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPEQ_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPEQ_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPEQ_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPEQ_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPEQ_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPEQ_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE.json new file mode 100644 index 0000000000..84f7d00c59 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPGE", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPGE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPGE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPGE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPGE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPGE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE_L.json new file mode 100644 index 0000000000..2fa99ff25d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE_L.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPGE_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPGE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPGE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPGE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPGE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPGE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT.json new file mode 100644 index 0000000000..c4ca491cca --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPGT", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPGT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPGT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPGT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPGT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPGT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT_L.json new file mode 100644 index 0000000000..5523aa87c9 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT_L.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPGT_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPGT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPGT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPGT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPGT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPGT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF.json new file mode 100644 index 0000000000..121c8b76c7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF.json @@ -0,0 +1,145 @@ +{ + "category": "Control", + "name": "JMPIF", + "tests": [ + { + "name": "Without items", + "script": [ + "JMPIF", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [1]", + "script": [ + "PUSH1", + "JMPIF", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIF", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [0]", + "script": [ + "PUSH0", + "JMPIF", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIF", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT.json new file mode 100644 index 0000000000..e11227ce40 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT.json @@ -0,0 +1,145 @@ +{ + "category": "Control", + "name": "JMPIFNOT", + "tests": [ + { + "name": "Without items", + "script": [ + "JMPIFNOT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [1]", + "script": [ + "PUSH1", + "JMPIFNOT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIFNOT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [0]", + "script": [ + "PUSH0", + "JMPIFNOT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIFNOT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT_L.json new file mode 100644 index 0000000000..90e37bee74 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT_L.json @@ -0,0 +1,145 @@ +{ + "category": "Control", + "name": "JMPIFNOT_L", + "tests": [ + { + "name": "Without items", + "script": [ + "JMPIFNOT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [1]", + "script": [ + "PUSH1", + "JMPIFNOT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIFNOT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [0]", + "script": [ + "PUSH0", + "JMPIFNOT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIFNOT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF_L.json new file mode 100644 index 0000000000..a9d0e1e352 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF_L.json @@ -0,0 +1,145 @@ +{ + "category": "Control", + "name": "JMPIF_L", + "tests": [ + { + "name": "Without items", + "script": [ + "JMPIF_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [1]", + "script": [ + "PUSH1", + "JMPIF_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIF_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [0]", + "script": [ + "PUSH0", + "JMPIF_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIF_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE.json new file mode 100644 index 0000000000..5325d60cf2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPLE", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPLE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPLE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPLE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPLE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPLE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE_L.json new file mode 100644 index 0000000000..3ccc3c06e8 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE_L.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPLE_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPLE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPLE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPLE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPLE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPLE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT.json new file mode 100644 index 0000000000..72946b6c6a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPLT", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPLT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPLT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPLT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPLT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPLT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT_L.json new file mode 100644 index 0000000000..196b455d0a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT_L.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPLT_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPLT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPLT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPLT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPLT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPLT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE.json new file mode 100644 index 0000000000..53498bc05b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPNE", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPNE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPNE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPNE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPNE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPNE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE_L.json new file mode 100644 index 0000000000..a1adb96021 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE_L.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPNE_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPNE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPNE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPNE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPNE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPNE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP_L.json new file mode 100644 index 0000000000..4f6157d1de --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP_L.json @@ -0,0 +1,74 @@ +{ + "category": "Control", + "name": "JMP_L", + "tests": [ + { + "name": "Out of range [<0]", + "script": [ + "JMP_L", + "0xffffffff", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of range [>length]", + "script": [ + "JMP_L", + "0xffffff7f", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "JMP_L", + "0x05000000", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/NOP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/NOP.json new file mode 100644 index 0000000000..3564f8afa2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/NOP.json @@ -0,0 +1,96 @@ +{ + "category": "Control", + "name": "NOP", + "tests": [ + { + "name": "Real test", + "script": [ + "NOP", + "NOP", + "NOP", + "NOP", + "NOP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/RET.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/RET.json new file mode 100644 index 0000000000..993f8af213 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/RET.json @@ -0,0 +1,22 @@ +{ + "category": "Control", + "name": "RET", + "tests": [ + { + "name": "Real test", + "script": [ + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/SYSCALL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/SYSCALL.json new file mode 100644 index 0000000000..c99da78b24 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/SYSCALL.json @@ -0,0 +1,143 @@ +{ + "category": "Control", + "name": "SYSCALL", + "tests": [ + { + "name": "Syscall that does not exist", + "script": [ + "SYSCALL", + "0x00" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong script", + "script": [ + "SYSCALL", + "0x2a537973", + "DEPTH", + "CALL_L", + "0x6d2e0000", + "PUSHDATA1", + "0x457865637574696f6e456e67696e652e476574536372697074436f6e7461696e6572" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [IMessageProvider]", + "script": [ + "SYSCALL", + "0x77777777" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + } + ] + }, + { + "name": "Wrong script", + "script": [ + "SYSCALL", + "0xfdffff00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong script", + "script": [ + "SYSCALL", + "0xfeffffff", + "0xff", + "PUSH0" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong script", + "script": [ + "SYSCALL", + "0xffffffff", + "0xffffffffff", + "PUSH0" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/THROW.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/THROW.json new file mode 100644 index 0000000000..a382516154 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/THROW.json @@ -0,0 +1,24 @@ +{ + "category": "Control", + "name": "THROW", + "tests": [ + { + "name": "Fault Test", + "script": [ + "PUSH0", + "THROW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH.json new file mode 100644 index 0000000000..d08f084d95 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH.json @@ -0,0 +1,175 @@ +{ + "category": "Control", + "name": "TRY_CATCH", + "tests": [ + { + "name": "try catch with syscall exception", + "script": [ + "TRY", + "0x0a00", + "SYSCALL", + "0xdeaddead", + "ENDTRY", + "0x05", + "PUSH1", + "ENDTRY", + "0x02", + "PUSH2" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "ENDTRY", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "ByteString", + "value": "0x6572726f72" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "ByteString", + "value": "0x6572726f72" + } + ] + } + } + ] + }, + { + "name": "try catch without exception", + "script": [ + "TRY", + "0x0600", + "PUSH0", + "ENDTRY", + "0x05", + "PUSH3", + "ENDTRY", + "0x02", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "try catch with exception", + "script": [ + "TRY", + "0x0700", + "PUSH0", + "THROW", + "ENDTRY", + "0x05", + "PUSH1", + "ENDTRY", + "0x02", + "PUSH2" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY.json new file mode 100644 index 0000000000..769829fc3d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY.json @@ -0,0 +1,72 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try catch finally without exception", + "script": [ + "TRY", + "0x080a", + "PUSH0", + "ENDTRY", + "0x08", + "RET", + "PUSH2", + "ENDTRY", + "0x04", + "PUSH3", + "ENDFINALLY", + "PUSH4" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 12, + "nextInstruction": "PUSH4", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY10.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY10.json new file mode 100644 index 0000000000..fae60b985f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY10.json @@ -0,0 +1,25 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try + finally without ENDTRY", + "script": [ + "TRY", + "0x0003", + "ENDFINALLY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY2.json new file mode 100644 index 0000000000..37299f2423 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY2.json @@ -0,0 +1,103 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try catch finally with exception", + "script": [ + "TRY", + "0x080C", + "PUSH0", + "THROW", + "ENDTRY", + "0x06", + "RET", + "PUSH1", + "ENDTRY", + "0x02", + "RET", + "PUSH2", + "ENDFINALLY", + "PUSH3" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 12, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY3.json new file mode 100644 index 0000000000..b6cd601ff2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY3.json @@ -0,0 +1,111 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ try{ throw }catch{ }}catch{ }finally{ }", + "script": [ + "TRY", + "0x0e13", + "TRY", + "0x0700", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "PUSH1", + "ENDTRY", + "0x02", + "ENDTRY", + "0x02", + "RET", + "PUSH2", + "ENDTRY", + "0x04", + "PUSH3", + "ENDFINALLY", + "PUSH4" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "ENDTRY", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY4.json new file mode 100644 index 0000000000..710cadb12c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY4.json @@ -0,0 +1,117 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ try{ throw }catch{ throw } }catch{ }finally{ }", + "script": [ + "TRY", + "0x1014", + "TRY", + "0x0700", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "PUSH1", + "THROW", + "ENDTRY", + "0x04", + "ENDTRY", + "0x01", + "PUSH2", + "ENDTRY", + "0x02", + "RET", + "PUSH3", + "ENDFINALLY", + "PUSH4" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 16, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY5.json new file mode 100644 index 0000000000..6cb08caa3c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY5.json @@ -0,0 +1,35 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ assert false }catch{ push2 }finally{ push3 }", + "script": [ + "TRY", + "0x0608", + "PUSH0", + "ASSERT", + "ENDTRY", + "0x01", + "PUSH2", + "ENDTRY", + "0x01", + "PUSH3", + "ENDFINALLY", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY6.json new file mode 100644 index 0000000000..40b5bf2667 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY6.json @@ -0,0 +1,33 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ abort }catch{ push2 }finally{ push3 }", + "script": [ + "TRY", + "0x0507", + "ABORT", + "ENDTRY", + "0x01", + "PUSH2", + "ENDTRY", + "0x01", + "PUSH3", + "ENDFINALLY", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY7.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY7.json new file mode 100644 index 0000000000..766e88f839 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY7.json @@ -0,0 +1,55 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ throw }catch{ abort }finally{ push3 }", + "script": [ + "TRY", + "0x070a", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "ABORT", + "ENDTRY", + "0x01", + "PUSH3", + "ENDFINALLY", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer":7, + "nextInstruction": "ABORT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY8.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY8.json new file mode 100644 index 0000000000..93f2f84c26 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY8.json @@ -0,0 +1,101 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ throw }catch{ throw }finally{ push3 }", + "script": [ + "TRY", + "0x070b", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "PUSH2", + "THROW", + "ENDTRY", + "0x01", + "PUSH3", + "ENDFINALLY", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 12, + "nextInstruction": "ENDFINALLY", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY9.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY9.json new file mode 100644 index 0000000000..fe766a025a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY9.json @@ -0,0 +1,98 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ PUSH0, call A: PUSH1 { call B: PUSH2 throw an exception } }catch{ PUSH3 }", + "script": [ + "TRY", + "0x0f00", + "PUSH0", + "CALL", + "0x03", + "RET", + "PUSH1", + "CALL", + "0x02", + "PUSH2", + "THROW", + "RET", + "ENDTRY", + "0x01", + "PUSH3", + "ENDTRY", + "0x02", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 18, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_FINALLY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_FINALLY.json new file mode 100644 index 0000000000..abb4788a32 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_FINALLY.json @@ -0,0 +1,49 @@ +{ + "category": "Control", + "name": "TRY_FINALLY", + "tests": [ + { + "name": "try finally with exception", + "script": [ + "TRY", + "0x0009", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "JMP", + "0x03", + "PUSH1", + "ENDFINALLY", + "PUSH2" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHA.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHA.json new file mode 100644 index 0000000000..c6a0bf4c4f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHA.json @@ -0,0 +1,86 @@ +{ + "category": "Push", + "name": "PUSHA", + "tests": [ + { + "name": "Out of range [-1]", + "script": [ + "PUSHA", + "0xffffffff" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of range [>length]", + "script": [ + "PUSHA", + "0xffffff7f" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHA", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "pointer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [=length]", + "script": [ + "PUSHA", + "0x05000000" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "pointer", + "value": 5 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA1.json new file mode 100644 index 0000000000..5831718b95 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA1.json @@ -0,0 +1,47 @@ +{ + "category": "Push", + "name": "PUSHDATA1", + "tests": [ + { + "name": "Good definition", + "script": [ + "PUSHDATA1", + "0x04", + "0x01020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x01020304" + } + ] + } + } + ] + }, + { + "name": "Without enough length", + "script": [ + "PUSHDATA1", + "0x0501020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA2.json new file mode 100644 index 0000000000..b31e47fb74 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA2.json @@ -0,0 +1,47 @@ +{ + "category": "Push", + "name": "PUSHDATA2", + "tests": [ + { + "name": "Good definition", + "script": [ + "PUSHDATA2", + "0x0400", + "0x01020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x01020304" + } + ] + } + } + ] + }, + { + "name": "Without enough length", + "script": [ + "PUSHDATA2", + "0x050001020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA4.json new file mode 100644 index 0000000000..d61a42b3a4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA4.json @@ -0,0 +1,99 @@ +{ + "category": "Push", + "name": "PUSHDATA4", + "tests": [ + { + "name": "More length than script", + "script": [ + "PUSHDATA4", + "0x00080000" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative length", + "script": [ + "PUSHDATA4", + "0xffffffff" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Good definition", + "script": [ + "PUSHDATA4", + "0x04000000", + "0x01020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x01020304" + } + ] + } + } + ] + }, + { + "name": "Without enough length", + "script": [ + "PUSHDATA4", + "0x0500000001020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Max length (Parse Instruction Error)", + "script": [ + "PUSHDATA4", + "0x01001000", + "0xFF" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHINT8_to_PUSHINT256.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHINT8_to_PUSHINT256.json new file mode 100644 index 0000000000..72cca284bb --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHINT8_to_PUSHINT256.json @@ -0,0 +1,59 @@ +{ + "category": "Push", + "name": "PUSHINT8 to PUSHINT256", + "tests": [ + { + "name": "Basic Test", + "script": [ + "PUSHINT8", + "0xff", + "PUSHINT16", + "0xfeff", + "PUSHINT32", + "0xfdffffff", + "PUSHINT64", + "0xfcffffffffffffff", + "PUSHINT128", + "0xfbffffffffffffffffffffffffffffff", + "PUSHINT256", + "0xfaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": -6 + }, + { + "type": "integer", + "value": -5 + }, + { + "type": "integer", + "value": -4 + }, + { + "type": "integer", + "value": -3 + }, + { + "type": "integer", + "value": -2 + }, + { + "type": "integer", + "value": -1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHM1_to_PUSH16.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHM1_to_PUSH16.json new file mode 100644 index 0000000000..3b7f06ed6b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHM1_to_PUSH16.json @@ -0,0 +1,219 @@ +{ + "category": "Push", + "name": "From PUSHM1 to PUSH16 [-1 to 16]", + "tests": [ + { + "name": "Basic Test", + "script": [ + "PUSHM1", + "PUSH0", + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "PUSH7", + "PUSH8", + "PUSH9", + "PUSH10", + "PUSH11", + "PUSH12", + "PUSH13", + "PUSH14", + "PUSH15", + "PUSH16", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 18, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 16 + }, + { + "type": "integer", + "value": 15 + }, + { + "type": "integer", + "value": 14 + }, + { + "type": "integer", + "value": 13 + }, + { + "type": "integer", + "value": 12 + }, + { + "type": "integer", + "value": 11 + }, + { + "type": "integer", + "value": 10 + }, + { + "type": "integer", + "value": 9 + }, + { + "type": "integer", + "value": 8 + }, + { + "type": "integer", + "value": 7 + }, + { + "type": "integer", + "value": 6 + }, + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 16 + }, + { + "type": "integer", + "value": 15 + }, + { + "type": "integer", + "value": 14 + }, + { + "type": "integer", + "value": 13 + }, + { + "type": "integer", + "value": 12 + }, + { + "type": "integer", + "value": 11 + }, + { + "type": "integer", + "value": 10 + }, + { + "type": "integer", + "value": 9 + }, + { + "type": "integer", + "value": 8 + }, + { + "type": "integer", + "value": 7 + }, + { + "type": "integer", + "value": 6 + }, + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": -1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHNULL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHNULL.json new file mode 100644 index 0000000000..5b5247edb1 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHNULL.json @@ -0,0 +1,46 @@ +{ + "category": "Push", + "name": "PUSHNULL", + "tests": [ + { + "name": "Good definition", + "script": [ + "PUSHNULL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "null" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSLOT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSLOT.json new file mode 100644 index 0000000000..458463ea55 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSLOT.json @@ -0,0 +1,206 @@ +{ + "category": "Slot", + "name": "INITSLOT", + "tests": [ + { + "name": "Without enough items", + "script": [ + "INITSLOT", + "0x0101" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without 0 items", + "script": [ + "INITSLOT", + "0x0000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [LocalVariables]", + "script": [ + "INITSLOT", + "0x0100" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "localVariables": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [Arguments]", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "arguments": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [LocalVariables + Arguments]", + "script": [ + "PUSH1", + "INITSLOT", + "0x0101" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "localVariables": [ + { + "type": "Null" + } + ], + "arguments": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Initialize twice", + "script": [ + "PUSH0", + "INITSLOT", + "0x0101", + "PUSH0", + "INITSLOT", + "0x0101" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PUSH0", + "localVariables": [ + { + "type": "Null" + } + ], + "arguments": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSSLOT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSSLOT.json new file mode 100644 index 0000000000..e3a3e149f4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSSLOT.json @@ -0,0 +1,97 @@ +{ + "category": "Slot", + "name": "INITSSLOT", + "tests": [ + { + "name": "Without 0 items", + "script": [ + "INITSSLOT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Initialize twice", + "script": [ + "INITSSLOT", + "0x01", + "INITSSLOT", + "0x02" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "INITSSLOT", + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG.json new file mode 100644 index 0000000000..e3be41d38c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG.json @@ -0,0 +1,69 @@ +{ + "category": "Slot", + "name": "LDARG", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG0.json new file mode 100644 index 0000000000..038e8db3a6 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG0.json @@ -0,0 +1,47 @@ +{ + "category": "Slot", + "name": "LDARG0", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG1.json new file mode 100644 index 0000000000..522b1e68ac --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG1.json @@ -0,0 +1,67 @@ +{ + "category": "Slot", + "name": "LDARG1", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "INITSLOT", + "0x0002", + "LDARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG2.json new file mode 100644 index 0000000000..16ec5d743d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG2.json @@ -0,0 +1,68 @@ +{ + "category": "Slot", + "name": "LDARG2", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "INITSLOT", + "0x0003", + "LDARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG3.json new file mode 100644 index 0000000000..5a4a844a1b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG3.json @@ -0,0 +1,69 @@ +{ + "category": "Slot", + "name": "LDARG3", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "INITSLOT", + "0x0004", + "LDARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG4.json new file mode 100644 index 0000000000..4a091e5ff2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG4.json @@ -0,0 +1,70 @@ +{ + "category": "Slot", + "name": "LDARG4", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "INITSLOT", + "0x0005", + "LDARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG5.json new file mode 100644 index 0000000000..1d0d706266 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG5.json @@ -0,0 +1,71 @@ +{ + "category": "Slot", + "name": "LDARG5", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "INITSLOT", + "0x0006", + "LDARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG6.json new file mode 100644 index 0000000000..56da5d948b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG6.json @@ -0,0 +1,72 @@ +{ + "category": "Slot", + "name": "LDARG6", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "PUSH7", + "INITSLOT", + "0x0007", + "LDARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC.json new file mode 100644 index 0000000000..87f165dbdf --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC.json @@ -0,0 +1,70 @@ +{ + "category": "Slot", + "name": "LDLOC", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0100", + "PUSH1", + "STLOC", + "0x00", + "LDLOC", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC0.json new file mode 100644 index 0000000000..294a7b8df0 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC0.json @@ -0,0 +1,48 @@ +{ + "category": "Slot", + "name": "LDLOC0", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0100", + "PUSH1", + "STLOC0", + "LDLOC0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC1.json new file mode 100644 index 0000000000..f9e648200a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC1.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC1", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0200", + "PUSH1", + "STLOC1", + "LDLOC1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC2.json new file mode 100644 index 0000000000..075f338683 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC2.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC2", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0300", + "PUSH1", + "STLOC2", + "LDLOC2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC3.json new file mode 100644 index 0000000000..5463edaebc --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC3.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC3", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0400", + "PUSH1", + "STLOC3", + "LDLOC3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC4.json new file mode 100644 index 0000000000..23a616975d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC4.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC4", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0500", + "PUSH1", + "STLOC4", + "LDLOC4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC5.json new file mode 100644 index 0000000000..9bde0a550a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC5.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC5", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0600", + "PUSH1", + "STLOC5", + "LDLOC5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC6.json new file mode 100644 index 0000000000..edf7963263 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC6.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC6", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0700", + "PUSH1", + "STLOC6", + "LDLOC6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD.json new file mode 100644 index 0000000000..311c0a5964 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD.json @@ -0,0 +1,70 @@ +{ + "category": "Slot", + "name": "LDSFLD", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "STSFLD", + "0x00", + "LDSFLD", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD0.json new file mode 100644 index 0000000000..8a750b04f2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD0.json @@ -0,0 +1,48 @@ +{ + "category": "Slot", + "name": "LDSFLD0", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "STSFLD0", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD1.json new file mode 100644 index 0000000000..4289e1aa91 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD1.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD1", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x02", + "PUSH1", + "STSFLD1", + "LDSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD2.json new file mode 100644 index 0000000000..e03ab04d48 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD2.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD2", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x03", + "PUSH1", + "STSFLD2", + "LDSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD3.json new file mode 100644 index 0000000000..d10624f5a7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD3.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD3", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x04", + "PUSH1", + "STSFLD3", + "LDSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD4.json new file mode 100644 index 0000000000..b405defe0f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD4.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD4", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x05", + "PUSH1", + "STSFLD4", + "LDSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD5.json new file mode 100644 index 0000000000..c6b3ee058f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD5.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD5", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x06", + "PUSH1", + "STSFLD5", + "LDSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD6.json new file mode 100644 index 0000000000..cd7ae9b500 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD6.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD6", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x07", + "PUSH1", + "STSFLD6", + "LDSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG.json new file mode 100644 index 0000000000..bdf9f2f5c5 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG.json @@ -0,0 +1,72 @@ +{ + "category": "Slot", + "name": "STARG", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "PUSH0", + "STARG", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG0.json new file mode 100644 index 0000000000..b5666c3754 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG0.json @@ -0,0 +1,49 @@ +{ + "category": "Slot", + "name": "STARG0", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG1.json new file mode 100644 index 0000000000..da52006943 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG1.json @@ -0,0 +1,74 @@ +{ + "category": "Slot", + "name": "STARG1", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "INITSLOT", + "0x0002", + "PUSH0", + "STARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG2.json new file mode 100644 index 0000000000..8c6952eedd --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG2.json @@ -0,0 +1,79 @@ +{ + "category": "Slot", + "name": "STARG2", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "INITSLOT", + "0x0003", + "PUSH0", + "STARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG3.json new file mode 100644 index 0000000000..e8ed64b00d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG3.json @@ -0,0 +1,84 @@ +{ + "category": "Slot", + "name": "STARG3", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "INITSLOT", + "0x0004", + "PUSH0", + "STARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG4.json new file mode 100644 index 0000000000..7b32e0e09a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG4.json @@ -0,0 +1,89 @@ +{ + "category": "Slot", + "name": "STARG4", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "INITSLOT", + "0x0005", + "PUSH0", + "STARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 4 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG5.json new file mode 100644 index 0000000000..9bcef878b4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG5.json @@ -0,0 +1,94 @@ +{ + "category": "Slot", + "name": "STARG5", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "INITSLOT", + "0x0006", + "PUSH0", + "STARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 4 + }, + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG6.json new file mode 100644 index 0000000000..e8c0f09b9f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG6.json @@ -0,0 +1,99 @@ +{ + "category": "Slot", + "name": "STARG6", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "PUSH7", + "INITSLOT", + "0x0007", + "PUSH0", + "STARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 4 + }, + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STLOC.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STLOC.json new file mode 100644 index 0000000000..aae5bbb9ea --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STLOC.json @@ -0,0 +1,92 @@ +{ + "category": "Slot", + "name": "STLOC", + "tests": [ + { + "name": "Without slot", + "script": [ + "STLOC", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without enough items", + "script": [ + "INITSLOT", + "0x0100", + "PUSH2", + "STLOC" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0100", + "PUSH1", + "STLOC", + "0x00", + "LDLOC", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "LDLOC", + "localVariables": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD.json new file mode 100644 index 0000000000..149244cbbd --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD.json @@ -0,0 +1,84 @@ +{ + "category": "Slot", + "name": "STSFLD", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "STSFLD", + "0x00" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD0.json new file mode 100644 index 0000000000..d2ee516f22 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD0.json @@ -0,0 +1,63 @@ +{ + "category": "Slot", + "name": "STSFLD0", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "STSFLD0" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD1.json new file mode 100644 index 0000000000..5ba84602c1 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD1.json @@ -0,0 +1,84 @@ +{ + "category": "Slot", + "name": "STSFLD1", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x02", + "PUSH1", + "STSFLD1" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD2.json new file mode 100644 index 0000000000..d5c42ba76c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD2.json @@ -0,0 +1,87 @@ +{ + "category": "Slot", + "name": "STSFLD2", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x03", + "PUSH1", + "STSFLD2" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD3.json new file mode 100644 index 0000000000..f4ba41a606 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD3.json @@ -0,0 +1,90 @@ +{ + "category": "Slot", + "name": "STSFLD3", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x04", + "PUSH1", + "STSFLD3" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD4.json new file mode 100644 index 0000000000..48f4d09aa9 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD4.json @@ -0,0 +1,93 @@ +{ + "category": "Slot", + "name": "STSFLD4", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x05", + "PUSH1", + "STSFLD4" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD5.json new file mode 100644 index 0000000000..f3d2573d63 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD5.json @@ -0,0 +1,96 @@ +{ + "category": "Slot", + "name": "STSFLD5", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x06", + "PUSH1", + "STSFLD5" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD6.json new file mode 100644 index 0000000000..2d89c71887 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD6.json @@ -0,0 +1,99 @@ +{ + "category": "Slot", + "name": "STSFLD6", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x07", + "PUSH1", + "STSFLD6" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/CAT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/CAT.json new file mode 100644 index 0000000000..f7b6cf3430 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/CAT.json @@ -0,0 +1,436 @@ +{ + "category": "Splice", + "name": "CAT", + "tests": [ + { + "name": "Max Item Length", + "script": [ + "INITSLOT", + "0x0200", + "PUSHINT32", + "0x00000100", + "STLOC0", + "PUSH1", + "STLOC1", + "PUSHDATA2", + "0x1000", + "0x000102030405060708090A0B0C0D0E0F", + "PUSHDATA2", + "0x1000", + "0x000102030405060708090A0B0C0D0E0F", + "CAT", + "LDLOC1", + "INC", + "STLOC1", + "LDLOC1", + "LDLOC0", + "LT", + "JMPIF_L", + "0xE6FFFFFF", + "PUSHDATA1", + "0x01", + "0x00", + "CAT" + ], + "steps": [ + { + "actions": ["execute"], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map,ByteString]", + "script": [ + "PUSH0", + "NEWMAP", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [ByteString,Map]", + "script": [ + "NEWMAP", + "PUSH0", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong push", + "script": [ + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHDATA1", + "0x01", + "0x01", + "PUSHDATA1", + "0x02", + "0x0203", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x010203" + } + ] + } + } + ] + }, + { + "name": "CAT int(0) with empty ByteString", + "script": [ + "PUSH1", + "DEC", + "PUSH0", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "CAT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "" + } + ] + } + } + ] + }, + { + "name": "CAT 0x01 with empty ByteString", + "script": [ + "PUSH1", + "PUSH0", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "CAT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x01" + } + ] + } + } + ] + }, + { + "name": "CAT empty ByteString with 0x01", + "script": [ + "PUSH0", + "PUSH1", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "CAT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x01" + } + ] + } + } + ] + }, + { + "name": "CAT Buffers", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "INITSLOT", + "0x0002", + "LDARG1", + "LDARG0", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "INITSLOT", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "LDARG1", + "arguments": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "CAT", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ], + "arguments": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 16, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAABB" + } + ], + "arguments": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/LEFT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/LEFT.json new file mode 100644 index 0000000000..02c0dbc0ce --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/LEFT.json @@ -0,0 +1,228 @@ +{ + "category": "Splice", + "name": "LEFT", + "tests": [ + { + "name": "Without push", + "script": [ + "PUSH11", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "PUSH4", + "NEWMAP", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LEFT", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 4 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative value", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSHM1", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "LEFT", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow string", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH4", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "LEFT", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH2", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "LEFT", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x0102" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/MEMCPY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/MEMCPY.json new file mode 100644 index 0000000000..fcff55af20 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/MEMCPY.json @@ -0,0 +1,382 @@ +{ + "category": "Splice", + "name": "MEMCPY", + "tests": [ + { + "name": "Max Item Length", + "script": [ + "PUSH4", + "NEWBUFFER", + "PUSHINT32", + "0x00001000", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": 1048576 + }, + { + "type": "Buffer", + "value": "0x00000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative di", + "script": [ + "PUSH4", + "NEWBUFFER", + "PUSHM1", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": -1 + }, + { + "type": "Buffer", + "value": "0x00000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative si", + "script": [ + "PUSH4", + "NEWBUFFER", + "PUSHINT32", + "0x00001000", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSHM1", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": -1 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": 1048576 + }, + { + "type": "Buffer", + "value": "0x00000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative n", + "script": [ + "PUSH4", + "NEWBUFFER", + "PUSHINT32", + "0x00001000", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSHM1", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": -1 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": 1048576 + }, + { + "type": "Buffer", + "value": "0x00000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSHINT32", + "0x00001000", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": 1048576 + }, + { + "type": "Array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "No push", + "script": [ + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH4", + "NEWBUFFER", + "DUP", + "PUSH1", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x00111100" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/NEWBUFFER.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/NEWBUFFER.json new file mode 100644 index 0000000000..f3c60bb802 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/NEWBUFFER.json @@ -0,0 +1,159 @@ +{ + "category": "Splice", + "name": "NEWBUFFER", + "tests": [ + { + "name": "Max Item Length", + "script": [ + "PUSHINT256", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 33, + "nextInstruction": "NEWBUFFER", + "evaluationStack": [ + { + "type": "Integer", + "value": "57896044618658097711785492504343953926634992332820282019728792003956564819967" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "-1 Length", + "script": [ + "PUSHM1", + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NEWBUFFER", + "evaluationStack": [ + { + "type": "Integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH0", + "NEWARRAY", + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NEWBUFFER", + "evaluationStack": [ + { + "type": "Array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "No push", + "script": [ + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Integer]", + "script": [ + "PUSH10", + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x00000000000000000000" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/RIGHT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/RIGHT.json new file mode 100644 index 0000000000..6c30ea8c91 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/RIGHT.json @@ -0,0 +1,299 @@ +{ + "category": "Splice", + "name": "RIGHT", + "tests": [ + { + "name": "Without push", + "script": [ + "PUSH11", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "PUSH4", + "NEWMAP", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 4 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative value", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSHM1", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow string", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH4", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH2", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0x0203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x0203" + } + ] + } + } + ] + }, + { + "name": "Real test [whole input]", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH3", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x010203" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/SUBSTR.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/SUBSTR.json new file mode 100644 index 0000000000..7b78d7e053 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/SUBSTR.json @@ -0,0 +1,478 @@ +{ + "category": "Splice", + "name": "SUBSTR", + "tests": [ + { + "name": "Without 3 items", + "script": [ + "PUSH2", + "PUSH3", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With negative count", + "script": [ + "PUSH0", + "PUSH0", + "PUSHM1", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With map as string", + "script": [ + "NEWMAP", + "PUSH0", + "PUSH0", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With map as count", + "script": [ + "PUSH0", + "PUSH0", + "NEWMAP", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With map as index", + "script": [ + "PUSH0", + "NEWMAP", + "PUSH0", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With negative index", + "script": [ + "PUSH0", + "PUSHM1", + "PUSH0", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": -1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow string index", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "PUSH9", + "PUSH2", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 9 + }, + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow string count", + "script": [ + "PUSHDATA1", + "0x0a", + "0x00010203040506070809", + "PUSH2", + "PUSH9", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 9 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "ByteString", + "value": "0x00010203040506070809" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHDATA1", + "0x0a", + "0x00010203040506070809", + "PUSH2", + "PUSH1", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "ByteString", + "value": "0x00010203040506070809" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x02" + } + ] + } + } + ] + }, + { + "name": "Integer overflow Test", + "script": [ + "PUSHDATA1", + "0xff", + "0x414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141", + "PUSHDATA1", + "0x04", + "0xfd000000", + "PUSHDATA1", + "0x04", + "0x03ffff7f", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/CLEAR.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/CLEAR.json new file mode 100644 index 0000000000..36e9fcdd09 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/CLEAR.json @@ -0,0 +1,59 @@ +{ + "category": "Stack", + "name": "CLEAR", + "tests": [ + { + "name": "Without push", + "script": [ + "CLEAR" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "With push", + "script": [ + "PUSH2", + "CLEAR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CLEAR", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DEPTH.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DEPTH.json new file mode 100644 index 0000000000..9a2ed2f774 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DEPTH.json @@ -0,0 +1,223 @@ +{ + "category": "Stack", + "name": "DEPTH", + "tests": [ + { + "name": "Without push", + "script": [ + "DEPTH" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "With push", + "script": [ + "PUSH2", + "DEPTH" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "DEPTH", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + } + ] + }, + { + "name": "3xDEPTH", + "script": [ + "DEPTH", + "DEPTH", + "DEPTH" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "DEPTH", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "DEPTH", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DROP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DROP.json new file mode 100644 index 0000000000..804a710958 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DROP.json @@ -0,0 +1,73 @@ +{ + "category": "Stack", + "name": "DROP", + "tests": [ + { + "name": "Without push", + "script": [ + "DROP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "PUSH5", + "DROP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "DROP", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/NIP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/NIP.json new file mode 100644 index 0000000000..e363d56444 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/NIP.json @@ -0,0 +1,132 @@ +{ + "category": "Stack", + "name": "NIP", + "tests": [ + { + "name": "Without push", + "script": [ + "NIP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without two stack items", + "script": [ + "PUSH5", + "NIP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NIP", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x09", + "0x000000000000000000", + "NOT", + "NIP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "NIP", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/OVER.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/OVER.json new file mode 100644 index 0000000000..03ec0d16ee --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/OVER.json @@ -0,0 +1,243 @@ +{ + "category": "Stack", + "name": "OVER", + "tests": [ + { + "name": "Without push", + "script": [ + "OVER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With one push", + "script": [ + "PUSH0", + "OVER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "OVER", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test with 2 items", + "script": [ + "PUSH1", + "PUSH2", + "OVER" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "OVER", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test with 3 items", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "OVER" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "OVER", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/PICK.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/PICK.json new file mode 100644 index 0000000000..5791acec70 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/PICK.json @@ -0,0 +1,397 @@ +{ + "category": "Stack", + "name": "PICK", + "tests": [ + { + "name": "Without push", + "script": [ + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Pick outside", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Less than 0", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSHM1", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "NEWMAP", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH2", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test with 0", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH0", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE3.json new file mode 100644 index 0000000000..1260a70d68 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE3.json @@ -0,0 +1,85 @@ +{ + "category": "Stack", + "name": "REVERSE3", + "tests": [ + { + "name": "Without push", + "script": [ + "REVERSE3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With push", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "REVERSE3" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "REVERSE3", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE4.json new file mode 100644 index 0000000000..d3e04e437e --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE4.json @@ -0,0 +1,95 @@ +{ + "category": "Stack", + "name": "REVERSE4", + "tests": [ + { + "name": "Without push", + "script": [ + "REVERSE4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With push", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "REVERSE4" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "REVERSE4", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 4 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSEN.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSEN.json new file mode 100644 index 0000000000..e9a1518826 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSEN.json @@ -0,0 +1,201 @@ +{ + "category": "Stack", + "name": "REVERSEN", + "tests": [ + { + "name": "Without push", + "script": [ + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "N = -1", + "script": [ + "PUSH1", + "PUSHM1", + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "N < DEPTH", + "script": [ + "PUSH1", + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Reverse 0 item", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH0", + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "REVERSEN", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Reverse 3 items", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH3", + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "REVERSEN", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROLL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROLL.json new file mode 100644 index 0000000000..882c577d4a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROLL.json @@ -0,0 +1,398 @@ +{ + "category": "Stack", + "name": "ROLL", + "tests": [ + { + "name": "Without push", + "script": [ + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With -1", + "script": [ + "PUSHM1", + "ROLL" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Pick outside", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Less than 0", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSHM1", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With 0", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH0", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Wrong type", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "NEWMAP", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH2", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROT.json new file mode 100644 index 0000000000..48c8771af3 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROT.json @@ -0,0 +1,193 @@ +{ + "category": "Stack", + "name": "ROT", + "tests": [ + { + "name": "Without push", + "script": [ + "ROT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With one push", + "script": [ + "PUSH0", + "ROT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "ROT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With 2 items", + "script": [ + "PUSH1", + "PUSH2", + "ROT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "ROT", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test with 3 items", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "ROT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "ROT", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/SWAP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/SWAP.json new file mode 100644 index 0000000000..c5e93a9b59 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/SWAP.json @@ -0,0 +1,209 @@ +{ + "category": "Stack", + "name": "SWAP", + "tests": [ + { + "name": "Without push", + "script": [ + "SWAP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With one push", + "script": [ + "PUSH0", + "SWAP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SWAP", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test with 2 items", + "script": [ + "PUSH1", + "PUSH2", + "SWAP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SWAP", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test with 3 items", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "SWAP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SWAP", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/TUCK.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/TUCK.json new file mode 100644 index 0000000000..031855f31f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/TUCK.json @@ -0,0 +1,243 @@ +{ + "category": "Stack", + "name": "TUCK", + "tests": [ + { + "name": "Without push", + "script": [ + "TUCK" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Outside", + "script": [ + "PUSH0", + "TUCK" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "TUCK", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test - Last item", + "script": [ + "PUSH1", + "PUSH2", + "TUCK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "TUCK", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "TUCK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "TUCK", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/XDROP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/XDROP.json new file mode 100644 index 0000000000..8666fed600 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/XDROP.json @@ -0,0 +1,238 @@ +{ + "category": "Stack", + "name": "XDROP", + "tests": [ + { + "name": "Without push", + "script": [ + "XDROP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With -1", + "script": [ + "PUSHM1", + "XDROP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow drop", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH3", + "XDROP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "XDROP", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong index type [Map]", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "NEWMAP", + "XDROP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "XDROP", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH1", + "XDROP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "XDROP", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Types/CONVERT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Types/CONVERT.json new file mode 100644 index 0000000000..473ed8bba4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Types/CONVERT.json @@ -0,0 +1,898 @@ +{ + "category": "Types", + "name": "CONVERT", + "tests": [ + { + "name": "Null to Buffer", + "script": [ + "PUSHNULL", + "CONVERT", + "0x30" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "null" + } + ] + } + } + ] + }, + { + "name": "Null to Boolean", + "script": [ + "PUSHNULL", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "null" + } + ] + } + } + ] + }, + { + "name": "Struct to Array", + "script": [ + "PUSH1", + "NEWSTRUCT", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "CONVERT", + "0x40" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Struct to Boolean", + "script": [ + "PUSH0", + "NEWSTRUCT", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "struct", + "value": [ + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Array to Boolean", + "script": [ + "PUSH0", + "NEWARRAY", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "array", + "value": [ + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Array to Struct", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "CONVERT", + "0x41" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Array to Integer", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH4", + "SETITEM", + "CONVERT", + "0x21" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Integer to ByteString", + "script": [ + "PUSHINT8", + "0x0A", + "CONVERT", + "0x28" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x0A" + } + ] + } + } + ] + }, + { + "name": "Integer to Boolean", + "script": [ + "PUSHINT8", + "0x0A", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Integer to Boolean", + "script": [ + "PUSHINT8", + "0x00", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Integer to Boolean", + "script": [ + "PUSHINT8", + "0x01", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Integer to Buffer", + "script": [ + "PUSHINT8", + "0x0A", + "CONVERT", + "0x30" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x0A" + } + ] + } + } + ] + }, + { + "name": "ByteString to Buffer", + "script": [ + "PUSHDATA1", + "0x0A", + "0x00000000000000000000", + "CONVERT", + "0x30" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x00000000000000000000" + } + ] + } + } + ] + }, + { + "name": "ByteString to Integer", + "script": [ + "PUSHDATA1", + "0x02", + "0x0A0B", + "CONVERT", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 2826 + } + ] + } + } + ] + }, + { + "name": "ByteString to Boolean", + "script": [ + "PUSHDATA1", + "0x02", + "0x0A0B", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "ByteString to Boolean", + "script": [ + "PUSHDATA1", + "0x02", + "0x0000", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "ByteString to Boolean", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "ByteString to Boolean", + "script": [ + "PUSHDATA1", + "0x01", + "0x01", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Buffer to ByteString", + "script": [ + "PUSHDATA1", + "0x0A", + "0x00000000000000000000", + "CONVERT", + "0x30", + "CONVERT", + "0x28" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000" + } + ] + } + } + ] + }, + { + "name": "Buffer to Boolean", + "script": [ + "PUSHDATA1", + "0x01", + "0x00", + "CONVERT", + "0x30", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Buffer to Boolean", + "script": [ + "PUSHDATA1", + "0x01", + "0x02", + "CONVERT", + "0x30", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Buffer to Integer", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "CONVERT", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 513 + } + ] + } + } + ] + }, + { + "name": "Buffer to Integer (Exceed)", + "script": [ + "PUSHDATA1", + "0x21", + "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "CONVERT", + "0x30", + "CONVERT", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Buffer to Any", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "CONVERT", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Buffer to Interop", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "CONVERT", + "0x60" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "ByteString to non-defined", + "script": [ + "PUSHDATA1", + "0x01", + "0xAA", + "CONVERT", + "0xFF" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Array to non-defined", + "script": [ + "NEWARRAY0", + "CONVERT", + "0xFF" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Struct to non-defined", + "script": [ + "NEWSTRUCT0", + "CONVERT", + "0xFF" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Null to non-defined", + "script": [ + "PUSHNULL", + "CONVERT", + "0xFF" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISNULL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISNULL.json new file mode 100644 index 0000000000..b87fa84726 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISNULL.json @@ -0,0 +1,147 @@ +{ + "category": "Types", + "name": "ISNULL", + "tests": [ + { + "name": "Without push", + "script": [ + "ISNULL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Good definition", + "script": [ + "PUSHNULL", + "ISNULL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "ISNULL", + "evaluationStack": [ + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "With empty ByteString", + "script": [ + "PUSH0", + "ISNULL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "ISNULL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISTYPE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISTYPE.json new file mode 100644 index 0000000000..6bdbd7495c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISTYPE.json @@ -0,0 +1,226 @@ +{ + "category": "Types", + "name": "ISTYPE", + "tests": [ + { + "name": "Array", + "script": [ + "NEWARRAY0", + "ISTYPE", + "0x40" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Buffer", + "script": [ + "PUSH0", + "NEWBUFFER", + "ISTYPE", + "0x30" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "ByteString", + "script": [ + "PUSHDATA1", + "0x00", + "ISTYPE", + "0x28" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Integer", + "script": [ + "PUSH0", + "ISTYPE", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "InteropInterface", + "script": [ + "SYSCALL", + "0x77777777", + "ISTYPE", + "0x60" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Map", + "script": [ + "NEWMAP", + "ISTYPE", + "0x48" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Null", + "script": [ + "PUSHNULL", + "ISTYPE", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Pointer", + "script": [ + "PUSHA", + "0x00000000", + "ISTYPE", + "0x10" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Struct", + "script": [ + "NEWSTRUCT0", + "ISTYPE", + "0x41" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/Debugger.json b/tests/Neo.VM.Tests/Tests/Others/Debugger.json new file mode 100644 index 0000000000..7dd1096d55 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/Debugger.json @@ -0,0 +1,426 @@ +{ + "category": "Others", + "name": "Debugger", + "tests": [ + { + "name": "Step Into", + "script": [ + "PUSH1", + "CALL", + "0x04", + "PUSH3", + "RET", + "PUSH2", + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CALL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + }, + { + "instructionPointer": 3, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + }, + { + "instructionPointer": 3, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Step Out", + "script": [ + "PUSH1", + "CALL", + "0x04", + "PUSH3", + "RET", + "PUSH2", + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CALL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepOut" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Step Over", + "script": [ + "PUSH1", + "CALL", + "0x04", + "PUSH3", + "RET", + "PUSH2", + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CALL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepOver" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepOver" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepOver" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Execute", + "script": [ + "PUSH1", + "CALL", + "0x04", + "PUSH3", + "RET", + "PUSH2", + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/Init.json b/tests/Neo.VM.Tests/Tests/Others/Init.json new file mode 100644 index 0000000000..ab95168cde --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/Init.json @@ -0,0 +1,41 @@ +{ + "category": "Others", + "name": "Init", + "tests": [ + { + "name": "Init script", + "script": [ + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "RET" + } + ] + } + } + ] + }, + { + "name": "Init script", + "script": [ + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/InvocationLimits.json b/tests/Neo.VM.Tests/Tests/Others/InvocationLimits.json new file mode 100644 index 0000000000..5939dabf80 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/InvocationLimits.json @@ -0,0 +1,120 @@ +{ + "category": "Limits", + "name": "Invocation limits", + "tests": [ + { + "name": "More than 1024 ExecutionContext", + "script": [ + "INITSSLOT", + "0x01", + "PUSHDATA1", + "0x02", + "0x0004", + "INC", + "STSFLD0", + "LDSFLD0", + "DEC", + "DUP", + "STSFLD0", + "JMPIFNOT", + "0x04", + "CALL", + "0xfa", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "integer", + "value": 1025 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 12, + "nextInstruction": "JMPIFNOT", + "evaluationStack": [ + { + "type": "integer", + "value": 1024 + } + ], + "staticFields": [ + { + "type": "integer", + "value": 1024 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "integer", + "value": 1024 + } + ] + }, + { + "instructionPointer": 16, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "integer", + "value": 1024 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/OtherCases.json b/tests/Neo.VM.Tests/Tests/Others/OtherCases.json new file mode 100644 index 0000000000..693bf7cba7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/OtherCases.json @@ -0,0 +1,36 @@ +{ + "category": "Limits", + "name": "OtherCases", + "tests": [ + { + "name": "Wrong script", + "script": [ + "0xff" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without script", + "script": [], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/ScriptLogic.json b/tests/Neo.VM.Tests/Tests/Others/ScriptLogic.json new file mode 100644 index 0000000000..a49be7a8bf --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/ScriptLogic.json @@ -0,0 +1,99 @@ +{ + "category": "Others", + "name": "ScriptLogic", + "tests": [ + { + "name": "Script logic", + "script": [ + "PUSH0", + "NOT", + "NOT", + "DROP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "DROP", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/StackItemLimits.json b/tests/Neo.VM.Tests/Tests/Others/StackItemLimits.json new file mode 100644 index 0000000000..77293f9f89 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/StackItemLimits.json @@ -0,0 +1,71 @@ +{ + "category": "Limits", + "name": "Stack item limits [StackItemLimits] [StackItemLimits] [StackItemLimits]", + "tests": [ + { + "name": "Max boolean ByteString", + "script": [ + "PUSHDATA1", + "0x21", + "0x000000000000000000000000000000000000000000000000000000000000000000", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 35, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x000000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Max items with PUSHDATA (2048+1)", + "script": [ + "PUSHINT16", + "0x0004", + "NEWARRAY", + "UNPACK", + "PUSHINT16", + "0xfe03", + "NEWARRAY", + "UNPACK", + "PUSHDATA1", + "0x01", + "0x01" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/StackLimits.json b/tests/Neo.VM.Tests/Tests/Others/StackLimits.json new file mode 100644 index 0000000000..8191112a26 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/StackLimits.json @@ -0,0 +1,6181 @@ +{ + "category": "Limits", + "name": "Stack limits [StackLimits] [StackLimits] [StackLimits]", + "tests": [ + { + "name": "Good: 2048 PUSH1 + 2048 DROP", + "script": [ + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Bad: 2049 PUSH1", + "script": [ + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Types/TestEngine.cs b/tests/Neo.VM.Tests/Types/TestEngine.cs new file mode 100644 index 0000000000..832e9a7fb4 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/TestEngine.cs @@ -0,0 +1,34 @@ +using System; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.Test.Types +{ + class TestEngine : ExecutionEngine + { + public Exception FaultException { get; private set; } + + protected override void OnSysCall(uint method) + { + if (method == 0x77777777) + { + CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new object())); + return; + } + + if (method == 0xaddeadde) + { + ExecuteThrow("error"); + return; + } + + throw new System.Exception(); + } + + protected override void OnFault(Exception ex) + { + FaultException = ex; + base.OnFault(ex); + } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUT.cs b/tests/Neo.VM.Tests/Types/VMUT.cs new file mode 100644 index 0000000000..a018d05c29 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUT.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUT + { + [JsonProperty] + public string Category { get; set; } + + [JsonProperty] + public string Name { get; set; } + + [JsonProperty] + public VMUTEntry[] Tests { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTActionType.cs b/tests/Neo.VM.Tests/Types/VMUTActionType.cs new file mode 100644 index 0000000000..a90691a6ad --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTActionType.cs @@ -0,0 +1,13 @@ +namespace Neo.Test.Types +{ + public enum VMUTActionType + { + Execute, + + // Steps + + StepInto, + StepOut, + StepOver, + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTEntry.cs b/tests/Neo.VM.Tests/Types/VMUTEntry.cs new file mode 100644 index 0000000000..64c1e76d94 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTEntry.cs @@ -0,0 +1,17 @@ +using Neo.Test.Converters; +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUTEntry + { + [JsonProperty(Order = 1)] + public string Name { get; set; } + + [JsonProperty(Order = 2), JsonConverter(typeof(ScriptConverter))] + public byte[] Script { get; set; } + + [JsonProperty(Order = 3)] + public VMUTStep[] Steps { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs b/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs new file mode 100644 index 0000000000..b0d20ae2f9 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs @@ -0,0 +1,31 @@ +using Neo.Test.Converters; +using Neo.VM; +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUTExecutionContextState + { + [JsonProperty] + public int InstructionPointer { get; set; } + + [JsonProperty, JsonConverter(typeof(UppercaseEnum))] + public OpCode NextInstruction { get; set; } + + // Stacks + + [JsonProperty] + public VMUTStackItem[] EvaluationStack { get; set; } + + // Slots + + [JsonProperty] + public VMUTStackItem[] StaticFields { get; set; } + + [JsonProperty] + public VMUTStackItem[] Arguments { get; set; } + + [JsonProperty] + public VMUTStackItem[] LocalVariables { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs b/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs new file mode 100644 index 0000000000..235654b0a4 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs @@ -0,0 +1,21 @@ +using Neo.Test.Converters; +using Neo.VM; +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUTExecutionEngineState + { + [JsonProperty, JsonConverter(typeof(UppercaseEnum))] + public VMState State { get; set; } + + [JsonProperty] + public VMUTStackItem[] ResultStack { get; set; } + + [JsonProperty] + public VMUTExecutionContextState[] InvocationStack { get; set; } + + [JsonProperty] + public string ExceptionMessage { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTStackItem.cs b/tests/Neo.VM.Tests/Types/VMUTStackItem.cs new file mode 100644 index 0000000000..5bbca0ff9f --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTStackItem.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Neo.Test.Types +{ + public class VMUTStackItem + { + [JsonProperty] + public VMUTStackItemType Type { get; set; } + + [JsonProperty] + public JToken Value { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs b/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs new file mode 100644 index 0000000000..c11c5c86b9 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs @@ -0,0 +1,60 @@ +namespace Neo.Test.Types +{ + public enum VMUTStackItemType + { + /// + /// Null + /// + Null, + + /// + /// An address of function + /// + Pointer, + + /// + /// Boolean (true,false) + /// + Boolean, + + /// + /// ByteString + /// + ByteString, + + /// + /// ByteString as UTF8 string + /// + String, + + /// + /// Mutable byte array + /// + Buffer, + + /// + /// InteropInterface + /// + Interop, + + /// + /// BigInteger + /// + Integer, + + /// + /// Array + /// + Array, + + /// + /// Struct + /// + Struct, + + /// + /// Map + /// + Map + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTStep.cs b/tests/Neo.VM.Tests/Types/VMUTStep.cs new file mode 100644 index 0000000000..d0d88e0ca4 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTStep.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUTStep + { + [JsonProperty] + public string Name { get; set; } + + [JsonProperty] + public VMUTActionType[] Actions { get; set; } + + [JsonProperty] + public VMUTExecutionEngineState Result { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/UtDebugger.cs b/tests/Neo.VM.Tests/UtDebugger.cs new file mode 100644 index 0000000000..7b7f582416 --- /dev/null +++ b/tests/Neo.VM.Tests/UtDebugger.cs @@ -0,0 +1,207 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; + +namespace Neo.Test +{ + [TestClass] + public class UtDebugger + { + [TestMethod] + public void TestBreakPoint() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + Assert.IsFalse(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 3)); + + Assert.AreEqual(OpCode.NOP, engine.CurrentContext.NextInstruction.OpCode); + + debugger.AddBreakPoint(engine.CurrentContext.Script, 2); + debugger.AddBreakPoint(engine.CurrentContext.Script, 3); + debugger.Execute(); + Assert.AreEqual(OpCode.NOP, engine.CurrentContext.NextInstruction.OpCode); + Assert.AreEqual(2, engine.CurrentContext.InstructionPointer); + Assert.AreEqual(VMState.BREAK, engine.State); + + Assert.IsTrue(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 2)); + Assert.IsFalse(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 2)); + Assert.IsTrue(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 3)); + Assert.IsFalse(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 3)); + debugger.Execute(); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestWithoutBreakPoints() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + Assert.AreEqual(OpCode.NOP, engine.CurrentContext.NextInstruction.OpCode); + + debugger.Execute(); + + Assert.IsNull(engine.CurrentContext); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestWithoutDebugger() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + + engine.LoadScript(script.ToArray()); + + Assert.AreEqual(OpCode.NOP, engine.CurrentContext.NextInstruction.OpCode); + + engine.Execute(); + + Assert.IsNull(engine.CurrentContext); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestStepOver() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + /* ┌ CALL + │ ┌> NOT + │ │ RET + └> │ PUSH0 + └─┘ RET */ + script.EmitCall(4); + script.Emit(OpCode.NOT); + script.Emit(OpCode.RET); + script.Emit(OpCode.PUSH0); + script.Emit(OpCode.RET); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); + Assert.AreEqual(VMState.BREAK, debugger.StepOver()); + Assert.AreEqual(2, engine.CurrentContext.InstructionPointer); + Assert.AreEqual(VMState.BREAK, engine.State); + Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); + + debugger.Execute(); + + Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); + Assert.AreEqual(VMState.HALT, engine.State); + + // Test step over again + + Assert.AreEqual(VMState.HALT, debugger.StepOver()); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestStepInto() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + /* ┌ CALL + │ ┌> NOT + │ │ RET + └> │ PUSH0 + └─┘ RET */ + script.EmitCall(4); + script.Emit(OpCode.NOT); + script.Emit(OpCode.RET); + script.Emit(OpCode.PUSH0); + script.Emit(OpCode.RET); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + var context = engine.CurrentContext; + + Assert.AreEqual(context, engine.CurrentContext); + Assert.AreEqual(context, engine.EntryContext); + Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); + + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + + Assert.AreNotEqual(context, engine.CurrentContext); + Assert.AreEqual(context, engine.EntryContext); + Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); + + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + + Assert.AreEqual(context, engine.CurrentContext); + Assert.AreEqual(context, engine.EntryContext); + Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); + + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(VMState.HALT, debugger.StepInto()); + + Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); + Assert.AreEqual(VMState.HALT, engine.State); + + // Test step into again + + Assert.AreEqual(VMState.HALT, debugger.StepInto()); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestBreakPointStepOver() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + /* ┌ CALL + │ ┌> NOT + │ │ RET + └>X│ PUSH0 + └┘ RET */ + script.EmitCall(4); + script.Emit(OpCode.NOT); + script.Emit(OpCode.RET); + script.Emit(OpCode.PUSH0); + script.Emit(OpCode.RET); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); + + debugger.AddBreakPoint(engine.CurrentContext.Script, 5); + Assert.AreEqual(VMState.BREAK, debugger.StepOver()); + + Assert.IsNull(engine.CurrentContext.NextInstruction); + Assert.AreEqual(5, engine.CurrentContext.InstructionPointer); + Assert.AreEqual(VMState.BREAK, engine.State); + + debugger.Execute(); + + Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); + Assert.AreEqual(VMState.HALT, engine.State); + } + } +} diff --git a/tests/Neo.VM.Tests/UtEvaluationStack.cs b/tests/Neo.VM.Tests/UtEvaluationStack.cs new file mode 100644 index 0000000000..b8853b39ec --- /dev/null +++ b/tests/Neo.VM.Tests/UtEvaluationStack.cs @@ -0,0 +1,191 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections; +using System.Linq; + +namespace Neo.Test +{ + [TestClass] + public class UtEvaluationStack + { + private static EvaluationStack CreateOrderedStack(int count) + { + var check = new Integer[count]; + var stack = new EvaluationStack(new ReferenceCounter()); + + for (int x = 1; x <= count; x++) + { + stack.Push(x); + check[x - 1] = x; + } + + Assert.AreEqual(count, stack.Count); + CollectionAssert.AreEqual(check, stack.ToArray()); + + return stack; + } + + public static IEnumerable GetEnumerable(IEnumerator enumerator) + { + while (enumerator.MoveNext()) yield return enumerator.Current; + } + + [TestMethod] + public void TestClear() + { + var stack = CreateOrderedStack(3); + stack.Clear(); + Assert.AreEqual(0, stack.Count); + } + + [TestMethod] + public void TestCopyTo() + { + var stack = CreateOrderedStack(3); + var copy = new EvaluationStack(new ReferenceCounter()); + + Assert.ThrowsException(() => stack.CopyTo(copy, -2)); + Assert.ThrowsException(() => stack.CopyTo(copy, 4)); + + stack.CopyTo(copy, 0); + + Assert.AreEqual(3, stack.Count); + Assert.AreEqual(0, copy.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray()); + + stack.CopyTo(copy, -1); + + Assert.AreEqual(3, stack.Count); + Assert.AreEqual(3, copy.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray()); + + // Test IEnumerable + + var enumerable = (IEnumerable)copy; + var enumerator = enumerable.GetEnumerator(); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, GetEnumerable(enumerator).Cast().ToArray()); + + copy.CopyTo(stack, 2); + + Assert.AreEqual(5, stack.Count); + Assert.AreEqual(3, copy.Count); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3, 2, 3 }, stack.ToArray()); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, copy.ToArray()); + } + + [TestMethod] + public void TestMoveTo() + { + var stack = CreateOrderedStack(3); + var other = new EvaluationStack(new ReferenceCounter()); + + stack.MoveTo(other, 0); + + Assert.AreEqual(3, stack.Count); + Assert.AreEqual(0, other.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray()); + + stack.MoveTo(other, -1); + + Assert.AreEqual(0, stack.Count); + Assert.AreEqual(3, other.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, other.ToArray()); + + // Test IEnumerable + + var enumerable = (IEnumerable)other; + var enumerator = enumerable.GetEnumerator(); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, GetEnumerable(enumerator).Cast().ToArray()); + + other.MoveTo(stack, 2); + + Assert.AreEqual(2, stack.Count); + Assert.AreEqual(1, other.Count); + + CollectionAssert.AreEqual(new Integer[] { 2, 3 }, stack.ToArray()); + CollectionAssert.AreEqual(new Integer[] { 1 }, other.ToArray()); + } + + [TestMethod] + public void TestInsertPeek() + { + var stack = new EvaluationStack(new ReferenceCounter()); + + stack.Insert(0, 3); + stack.Insert(1, 1); + stack.Insert(1, 2); + + Assert.ThrowsException(() => stack.Insert(4, 2)); + + Assert.AreEqual(3, stack.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray()); + + Assert.AreEqual(3, stack.Peek(0)); + Assert.AreEqual(2, stack.Peek(1)); + Assert.AreEqual(1, stack.Peek(-1)); + + Assert.ThrowsException(() => stack.Peek(-4)); + } + + [TestMethod] + public void TestPopPush() + { + var stack = CreateOrderedStack(3); + + Assert.AreEqual(3, stack.Pop()); + Assert.AreEqual(2, stack.Pop()); + Assert.AreEqual(1, stack.Pop()); + + Assert.ThrowsException(() => stack.Pop()); + + stack = CreateOrderedStack(3); + + Assert.IsTrue(stack.Pop().Equals(3)); + Assert.IsTrue(stack.Pop().Equals(2)); + Assert.IsTrue(stack.Pop().Equals(1)); + + Assert.ThrowsException(() => stack.Pop()); + } + + [TestMethod] + public void TestRemove() + { + var stack = CreateOrderedStack(3); + + Assert.IsTrue(stack.Remove(0).Equals(3)); + Assert.IsTrue(stack.Remove(0).Equals(2)); + Assert.IsTrue(stack.Remove(-1).Equals(1)); + + Assert.ThrowsException(() => stack.Remove(0)); + Assert.ThrowsException(() => stack.Remove(-1)); + } + + [TestMethod] + public void TestReverse() + { + var stack = CreateOrderedStack(3); + + stack.Reverse(3); + Assert.IsTrue(stack.Pop().Equals(1)); + Assert.IsTrue(stack.Pop().Equals(2)); + Assert.IsTrue(stack.Pop().Equals(3)); + Assert.ThrowsException(() => stack.Pop().Equals(0)); + + stack = CreateOrderedStack(3); + + Assert.ThrowsException(() => stack.Reverse(-1)); + Assert.ThrowsException(() => stack.Reverse(4)); + + stack.Reverse(1); + Assert.IsTrue(stack.Pop().Equals(3)); + Assert.IsTrue(stack.Pop().Equals(2)); + Assert.IsTrue(stack.Pop().Equals(1)); + Assert.ThrowsException(() => stack.Pop().Equals(0)); + } + } +} diff --git a/tests/Neo.VM.Tests/UtExecutionContext.cs b/tests/Neo.VM.Tests/UtExecutionContext.cs new file mode 100644 index 0000000000..cad2bc0f3e --- /dev/null +++ b/tests/Neo.VM.Tests/UtExecutionContext.cs @@ -0,0 +1,55 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using System; +using System.Collections.Generic; + +namespace Neo.Test +{ + [TestClass] + public class UtExecutionContext + { + class TestState + { + public bool Flag = false; + } + + [TestMethod] + public void StateTest() + { + var context = new ExecutionContext(Array.Empty(), -1, new ReferenceCounter()); + + // Test factory + + var flag = context.GetState(() => new TestState() { Flag = true }); + Assert.IsTrue(flag.Flag); + + flag.Flag = false; + + flag = context.GetState(() => new TestState() { Flag = true }); + Assert.IsFalse(flag.Flag); + + // Test new + + var stack = context.GetState>(); + Assert.AreEqual(0, stack.Count); + stack.Push(100); + stack = context.GetState>(); + Assert.AreEqual(100, stack.Pop()); + stack.Push(100); + + // Test clone + + var copy = context.Clone(); + var copyStack = copy.GetState>(); + Assert.AreEqual(1, copyStack.Count); + copyStack.Push(200); + copyStack = context.GetState>(); + Assert.AreEqual(200, copyStack.Pop()); + Assert.AreEqual(100, copyStack.Pop()); + copyStack.Push(200); + + stack = context.GetState>(); + Assert.AreEqual(200, stack.Pop()); + } + } +} diff --git a/tests/Neo.VM.Tests/UtReferenceCounter.cs b/tests/Neo.VM.Tests/UtReferenceCounter.cs new file mode 100644 index 0000000000..3a877eac83 --- /dev/null +++ b/tests/Neo.VM.Tests/UtReferenceCounter.cs @@ -0,0 +1,167 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.Test +{ + [TestClass] + public class UtReferenceCounter + { + [TestMethod] + public void TestCircularReferences() + { + using ScriptBuilder sb = new(); + sb.Emit(OpCode.INITSSLOT, new byte[] { 1 }); //{}|{null}:1 + sb.EmitPush(0); //{0}|{null}:2 + sb.Emit(OpCode.NEWARRAY); //{A[]}|{null}:2 + sb.Emit(OpCode.DUP); //{A[],A[]}|{null}:3 + sb.Emit(OpCode.DUP); //{A[],A[],A[]}|{null}:4 + sb.Emit(OpCode.APPEND); //{A[A]}|{null}:3 + sb.Emit(OpCode.DUP); //{A[A],A[A]}|{null}:4 + sb.EmitPush(0); //{A[A],A[A],0}|{null}:5 + sb.Emit(OpCode.NEWARRAY); //{A[A],A[A],B[]}|{null}:5 + sb.Emit(OpCode.STSFLD0); //{A[A],A[A]}|{B[]}:4 + sb.Emit(OpCode.LDSFLD0); //{A[A],A[A],B[]}|{B[]}:5 + sb.Emit(OpCode.APPEND); //{A[A,B]}|{B[]}:4 + sb.Emit(OpCode.LDSFLD0); //{A[A,B],B[]}|{B[]}:5 + sb.EmitPush(0); //{A[A,B],B[],0}|{B[]}:6 + sb.Emit(OpCode.NEWARRAY); //{A[A,B],B[],C[]}|{B[]}:6 + sb.Emit(OpCode.TUCK); //{A[A,B],C[],B[],C[]}|{B[]}:7 + sb.Emit(OpCode.APPEND); //{A[A,B],C[]}|{B[C]}:6 + sb.EmitPush(0); //{A[A,B],C[],0}|{B[C]}:7 + sb.Emit(OpCode.NEWARRAY); //{A[A,B],C[],D[]}|{B[C]}:7 + sb.Emit(OpCode.TUCK); //{A[A,B],D[],C[],D[]}|{B[C]}:8 + sb.Emit(OpCode.APPEND); //{A[A,B],D[]}|{B[C[D]]}:7 + sb.Emit(OpCode.LDSFLD0); //{A[A,B],D[],B[C]}|{B[C[D]]}:8 + sb.Emit(OpCode.APPEND); //{A[A,B]}|{B[C[D[B]]]}:7 + sb.Emit(OpCode.PUSHNULL); //{A[A,B],null}|{B[C[D[B]]]}:8 + sb.Emit(OpCode.STSFLD0); //{A[A,B[C[D[B]]]]}|{null}:7 + sb.Emit(OpCode.DUP); //{A[A,B[C[D[B]]]],A[A,B]}|{null}:8 + sb.EmitPush(1); //{A[A,B[C[D[B]]]],A[A,B],1}|{null}:9 + sb.Emit(OpCode.REMOVE); //{A[A]}|{null}:3 + sb.Emit(OpCode.STSFLD0); //{}|{A[A]}:2 + sb.Emit(OpCode.RET); //{}:0 + + using ExecutionEngine engine = new(); + Debugger debugger = new(engine); + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(1, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(5, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(5, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(5, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(5, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(6, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(6, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(6, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(8, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(8, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(8, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(8, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(9, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.HALT, debugger.Execute()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + } + + [TestMethod] + public void TestRemoveReferrer() + { + using ScriptBuilder sb = new(); + sb.Emit(OpCode.INITSSLOT, new byte[] { 1 }); //{}|{null}:1 + sb.EmitPush(0); //{0}|{null}:2 + sb.Emit(OpCode.NEWARRAY); //{A[]}|{null}:2 + sb.Emit(OpCode.DUP); //{A[],A[]}|{null}:3 + sb.EmitPush(0); //{A[],A[],0}|{null}:4 + sb.Emit(OpCode.NEWARRAY); //{A[],A[],B[]}|{null}:4 + sb.Emit(OpCode.STSFLD0); //{A[],A[]}|{B[]}:3 + sb.Emit(OpCode.LDSFLD0); //{A[],A[],B[]}|{B[]}:4 + sb.Emit(OpCode.APPEND); //{A[B]}|{B[]}:3 + sb.Emit(OpCode.DROP); //{}|{B[]}:1 + sb.Emit(OpCode.RET); //{}:0 + + using ExecutionEngine engine = new(); + Debugger debugger = new(engine); + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(1, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(1, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.HALT, debugger.Execute()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + } + + [TestMethod] + public void TestArrayNoPush() + { + using ScriptBuilder sb = new(); + sb.Emit(OpCode.RET); + using ExecutionEngine engine = new(); + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + Array array = new(engine.ReferenceCounter, new StackItem[] { 1, 2, 3, 4 }); + Assert.AreEqual(array.Count, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.HALT, engine.Execute()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + } + } +} diff --git a/tests/Neo.VM.Tests/UtScript.cs b/tests/Neo.VM.Tests/UtScript.cs new file mode 100644 index 0000000000..7e5c401488 --- /dev/null +++ b/tests/Neo.VM.Tests/UtScript.cs @@ -0,0 +1,93 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using System; +using System.Text; + +namespace Neo.Test +{ + [TestClass] + public class UtScript + { + [TestMethod] + public void Conversion() + { + byte[] rawScript; + using (var builder = new ScriptBuilder()) + { + builder.Emit(OpCode.PUSH0); + builder.Emit(OpCode.CALL, new byte[] { 0x00, 0x01 }); + builder.EmitSysCall(123); + + rawScript = builder.ToArray(); + } + + var script = new Script(rawScript); + + ReadOnlyMemory scriptConversion = script; + Assert.AreEqual(rawScript, scriptConversion); + } + + [TestMethod] + public void StrictMode() + { + var rawScript = new byte[] { (byte)OpCode.PUSH0, 0xFF }; + Assert.ThrowsException(() => new Script(rawScript, true)); + + var script = new Script(rawScript, false); + Assert.AreEqual(2, script.Length); + + rawScript = new byte[] { (byte)OpCode.PUSHDATA1 }; + Assert.ThrowsException(() => new Script(rawScript, true)); + + rawScript = new byte[] { (byte)OpCode.PUSHDATA2 }; + Assert.ThrowsException(() => new Script(rawScript, true)); + + rawScript = new byte[] { (byte)OpCode.PUSHDATA4 }; + Assert.ThrowsException(() => new Script(rawScript, true)); + } + + [TestMethod] + public void Parse() + { + Script script; + + using (var builder = new ScriptBuilder()) + { + builder.Emit(OpCode.PUSH0); + builder.Emit(OpCode.CALL_L, new byte[] { 0x00, 0x01, 0x00, 0x00 }); + builder.EmitSysCall(123); + + script = new Script(builder.ToArray()); + } + + Assert.AreEqual(11, script.Length); + + var ins = script.GetInstruction(0); + + Assert.AreEqual(OpCode.PUSH0, ins.OpCode); + Assert.IsTrue(ins.Operand.IsEmpty); + Assert.AreEqual(1, ins.Size); + Assert.ThrowsException(() => { var x = ins.TokenI16; }); + Assert.ThrowsException(() => { var x = ins.TokenU32; }); + + ins = script.GetInstruction(1); + + Assert.AreEqual(OpCode.CALL_L, ins.OpCode); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x01, 0x00, 0x00 }, ins.Operand.ToArray()); + Assert.AreEqual(5, ins.Size); + Assert.AreEqual(256, ins.TokenI32); + Assert.AreEqual(Encoding.ASCII.GetString(new byte[] { 0x00, 0x01, 0x00, 0x00 }), ins.TokenString); + + ins = script.GetInstruction(6); + + Assert.AreEqual(OpCode.SYSCALL, ins.OpCode); + CollectionAssert.AreEqual(new byte[] { 123, 0x00, 0x00, 0x00 }, ins.Operand.ToArray()); + Assert.AreEqual(5, ins.Size); + Assert.AreEqual(123, ins.TokenI16); + Assert.AreEqual(Encoding.ASCII.GetString(new byte[] { 123, 0x00, 0x00, 0x00 }), ins.TokenString); + Assert.AreEqual(123U, ins.TokenU32); + + Assert.ThrowsException(() => script.GetInstruction(100)); + } + } +} diff --git a/tests/Neo.VM.Tests/UtScriptBuilder.cs b/tests/Neo.VM.Tests/UtScriptBuilder.cs new file mode 100644 index 0000000000..006e8f0acd --- /dev/null +++ b/tests/Neo.VM.Tests/UtScriptBuilder.cs @@ -0,0 +1,264 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.Test.Helpers; +using Neo.VM; +using System; +using System.Linq; +using System.Numerics; +using System.Text; + +namespace Neo.Test +{ + [TestClass] + public class UtScriptBuilder + { + [TestMethod] + public void TestEmit() + { + using (ScriptBuilder script = new()) + { + Assert.AreEqual(0, script.Length); + script.Emit(OpCode.NOP); + Assert.AreEqual(1, script.Length); + + CollectionAssert.AreEqual(new byte[] { 0x21 }, script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + script.Emit(OpCode.NOP, new byte[] { 0x66 }); + CollectionAssert.AreEqual(new byte[] { 0x21, 0x66 }, script.ToArray()); + } + } + + [TestMethod] + public void TestBigInteger() + { + using (ScriptBuilder script = new()) + { + Assert.AreEqual(0, script.Length); + script.EmitPush(-100000); + Assert.AreEqual(5, script.Length); + + CollectionAssert.AreEqual(new byte[] { 2, 96, 121, 254, 255 }, script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + Assert.AreEqual(0, script.Length); + script.EmitPush(100000); + Assert.AreEqual(5, script.Length); + + CollectionAssert.AreEqual(new byte[] { 2, 160, 134, 1, 0 }, script.ToArray()); + } + } + + [TestMethod] + public void TestEmitSysCall() + { + using ScriptBuilder script = new(); + script.EmitSysCall(0xE393C875); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.SYSCALL, 0x75, 0xC8, 0x93, 0xE3 }.ToArray(), script.ToArray()); + } + + [TestMethod] + public void TestEmitCall() + { + using (ScriptBuilder script = new()) + { + script.EmitCall(0); + CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL, (byte)0 }, script.ToArray()); + } + using (ScriptBuilder script = new()) + { + script.EmitCall(12345); + CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL_L }.Concat(BitConverter.GetBytes(12345)).ToArray(), script.ToArray()); + } + using (ScriptBuilder script = new()) + { + script.EmitCall(-12345); + CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL_L }.Concat(BitConverter.GetBytes(-12345)).ToArray(), script.ToArray()); + } + } + + [TestMethod] + public void TestEmitJump() + { + var offset_i8 = sbyte.MaxValue; + var offset_i32 = int.MaxValue; + + foreach (OpCode op in Enum.GetValues(typeof(OpCode))) + { + using ScriptBuilder script = new(); + if (op < OpCode.JMP || op > OpCode.JMPLE_L) + { + Assert.ThrowsException(() => script.EmitJump(op, offset_i8)); + Assert.ThrowsException(() => script.EmitJump(op, offset_i32)); + } + else + { + script.EmitJump(op, offset_i8); + script.EmitJump(op, offset_i32); + if ((int)op % 2 == 0) + CollectionAssert.AreEqual(new[] { (byte)op, (byte)offset_i8, (byte)(op + 1) }.Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); + else + CollectionAssert.AreEqual(new[] { (byte)op }.Concat(BitConverter.GetBytes((int)offset_i8)).Concat(new[] { (byte)op }).Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); + } + } + + offset_i8 = sbyte.MinValue; + offset_i32 = int.MinValue; + + foreach (OpCode op in Enum.GetValues(typeof(OpCode))) + { + using ScriptBuilder script = new(); + if (op < OpCode.JMP || op > OpCode.JMPLE_L) + { + Assert.ThrowsException(() => script.EmitJump(op, offset_i8)); + Assert.ThrowsException(() => script.EmitJump(op, offset_i32)); + } + else + { + script.EmitJump(op, offset_i8); + script.EmitJump(op, offset_i32); + if ((int)op % 2 == 0) + CollectionAssert.AreEqual(new[] { (byte)op, (byte)offset_i8, (byte)(op + 1) }.Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); + else + CollectionAssert.AreEqual(new[] { (byte)op }.Concat(BitConverter.GetBytes((int)offset_i8)).Concat(new[] { (byte)op }).Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); + } + } + } + + [TestMethod] + public void TestEmitPushBigInteger() + { + using (ScriptBuilder script = new()) + { + script.EmitPush(BigInteger.MinusOne); + CollectionAssert.AreEqual(new byte[] { 0x0F }, script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + script.EmitPush(BigInteger.Zero); + CollectionAssert.AreEqual(new byte[] { 0x10 }, script.ToArray()); + } + + for (byte x = 1; x <= 16; x++) + { + using ScriptBuilder script = new(); + script.EmitPush(new BigInteger(x)); + CollectionAssert.AreEqual(new byte[] { (byte)(OpCode.PUSH0 + x) }, script.ToArray()); + } + + CollectionAssert.AreEqual("0080".FromHexString(), new ScriptBuilder().EmitPush(sbyte.MinValue).ToArray()); + CollectionAssert.AreEqual("007f".FromHexString(), new ScriptBuilder().EmitPush(sbyte.MaxValue).ToArray()); + CollectionAssert.AreEqual("01ff00".FromHexString(), new ScriptBuilder().EmitPush(byte.MaxValue).ToArray()); + CollectionAssert.AreEqual("010080".FromHexString(), new ScriptBuilder().EmitPush(short.MinValue).ToArray()); + CollectionAssert.AreEqual("01ff7f".FromHexString(), new ScriptBuilder().EmitPush(short.MaxValue).ToArray()); + CollectionAssert.AreEqual("02ffff0000".FromHexString(), new ScriptBuilder().EmitPush(ushort.MaxValue).ToArray()); + CollectionAssert.AreEqual("0200000080".FromHexString(), new ScriptBuilder().EmitPush(int.MinValue).ToArray()); + CollectionAssert.AreEqual("02ffffff7f".FromHexString(), new ScriptBuilder().EmitPush(int.MaxValue).ToArray()); + CollectionAssert.AreEqual("03ffffffff00000000".FromHexString(), new ScriptBuilder().EmitPush(uint.MaxValue).ToArray()); + CollectionAssert.AreEqual("030000000000000080".FromHexString(), new ScriptBuilder().EmitPush(long.MinValue).ToArray()); + CollectionAssert.AreEqual("03ffffffffffffff7f".FromHexString(), new ScriptBuilder().EmitPush(long.MaxValue).ToArray()); + CollectionAssert.AreEqual("04ffffffffffffffff0000000000000000".FromHexString(), new ScriptBuilder().EmitPush(ulong.MaxValue).ToArray()); + CollectionAssert.AreEqual("050100000000000000feffffffffffffff00000000000000000000000000000000".FromHexString(), new ScriptBuilder().EmitPush(new BigInteger(ulong.MaxValue) * new BigInteger(ulong.MaxValue)).ToArray()); + + Assert.ThrowsException(() => new ScriptBuilder().EmitPush( + new BigInteger("050100000000000000feffffffffffffff0100000000000000feffffffffffffff00000000000000000000000000000000".FromHexString()))); + } + + [TestMethod] + public void TestEmitPushBool() + { + using (ScriptBuilder script = new()) + { + script.EmitPush(true); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHT }, script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + script.EmitPush(false); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHF }, script.ToArray()); + } + } + + [TestMethod] + public void TestEmitPushReadOnlySpan() + { + using ScriptBuilder script = new(); + var data = new byte[] { 0x01, 0x02 }; + script.EmitPush(new ReadOnlySpan(data)); + + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA1, (byte)data.Length }.Concat(data).ToArray(), script.ToArray()); + } + + [TestMethod] + public void TestEmitPushByteArray() + { + using (ScriptBuilder script = new()) + { + Assert.ThrowsException(() => script.EmitPush((byte[])null)); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandBuffer(0x4C); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA1, (byte)data.Length }.Concat(data).ToArray(), script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandBuffer(0x100); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA2 }.Concat(BitConverter.GetBytes((short)data.Length)).Concat(data).ToArray(), script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandBuffer(0x10000); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA4 }.Concat(BitConverter.GetBytes(data.Length)).Concat(data).ToArray(), script.ToArray()); + } + } + + [TestMethod] + public void TestEmitPushString() + { + using (ScriptBuilder script = new()) + { + Assert.ThrowsException(() => script.EmitPush((string)null)); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandString(0x4C); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA1, (byte)data.Length }.Concat(Encoding.UTF8.GetBytes(data)).ToArray(), script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandString(0x100); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA2 }.Concat(BitConverter.GetBytes((short)data.Length)).Concat(Encoding.UTF8.GetBytes(data)).ToArray(), script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandString(0x10000); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA4 }.Concat(BitConverter.GetBytes(data.Length)).Concat(Encoding.UTF8.GetBytes(data)).ToArray(), script.ToArray()); + } + } + } +} diff --git a/tests/Neo.VM.Tests/UtSlot.cs b/tests/Neo.VM.Tests/UtSlot.cs new file mode 100644 index 0000000000..1e3403d650 --- /dev/null +++ b/tests/Neo.VM.Tests/UtSlot.cs @@ -0,0 +1,90 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections; +using System.Linq; +using System.Numerics; + +namespace Neo.Test +{ + [TestClass] + public class UtSlot + { + private static Slot CreateOrderedSlot(int count) + { + var check = new Integer[count]; + + for (int x = 1; x <= count; x++) + { + check[x - 1] = x; + } + + var slot = new Slot(check, new ReferenceCounter()); + + Assert.AreEqual(count, slot.Count); + CollectionAssert.AreEqual(check, slot.ToArray()); + + return slot; + } + + public static IEnumerable GetEnumerable(IEnumerator enumerator) + { + while (enumerator.MoveNext()) yield return enumerator.Current; + } + + [TestMethod] + public void TestGet() + { + var slot = CreateOrderedSlot(3); + + Assert.IsTrue(slot[0] is Integer item0 && item0.Equals(1)); + Assert.IsTrue(slot[1] is Integer item1 && item1.Equals(2)); + Assert.IsTrue(slot[2] is Integer item2 && item2.Equals(3)); + Assert.ThrowsException(() => slot[3] is Integer item3); + } + + [TestMethod] + public void TestEnumerable() + { + var slot = CreateOrderedSlot(3); + + BigInteger i = 1; + foreach (Integer item in slot) + { + Assert.AreEqual(item.GetInteger(), i); + i++; + } + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, slot.ToArray()); + + // Test IEnumerable + + var enumerable = (IEnumerable)slot; + var enumerator = enumerable.GetEnumerator(); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, GetEnumerable(enumerator).Cast().ToArray()); + + Assert.AreEqual(3, slot.Count); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, slot.ToArray()); + + // Empty + + slot = CreateOrderedSlot(0); + + CollectionAssert.AreEqual(System.Array.Empty(), slot.ToArray()); + + // Test IEnumerable + + enumerable = (IEnumerable)slot; + enumerator = enumerable.GetEnumerator(); + + CollectionAssert.AreEqual(System.Array.Empty(), GetEnumerable(enumerator).Cast().ToArray()); + + Assert.AreEqual(0, slot.Count); + + CollectionAssert.AreEqual(System.Array.Empty(), slot.ToArray()); + } + } +} diff --git a/tests/Neo.VM.Tests/UtStackItem.cs b/tests/Neo.VM.Tests/UtStackItem.cs new file mode 100644 index 0000000000..5ca73ae796 --- /dev/null +++ b/tests/Neo.VM.Tests/UtStackItem.cs @@ -0,0 +1,199 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; +using System.Numerics; + +namespace Neo.Test +{ + [TestClass] + public class UtStackItem + { + [TestMethod] + public void HashCodeTest() + { + StackItem itemA = "NEO"; + StackItem itemB = "NEO"; + StackItem itemC = "SmartEconomy"; + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + Assert.IsTrue(itemA.GetHashCode() != itemC.GetHashCode()); + + itemA = new VM.Types.Buffer(1); + itemB = new VM.Types.Buffer(1); + + Assert.IsTrue(itemA.GetHashCode() != itemB.GetHashCode()); + + itemA = true; + itemB = true; + itemC = false; + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + Assert.IsTrue(itemA.GetHashCode() != itemC.GetHashCode()); + + itemA = 1; + itemB = 1; + itemC = 123; + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + Assert.IsTrue(itemA.GetHashCode() != itemC.GetHashCode()); + + itemA = new Null(); + itemB = new Null(); + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + + itemA = new VM.Types.Array(); + + Assert.ThrowsException(() => itemA.GetHashCode()); + + itemA = new Struct(); + + Assert.ThrowsException(() => itemA.GetHashCode()); + + itemA = new Map(); + + Assert.ThrowsException(() => itemA.GetHashCode()); + + itemA = new InteropInterface(123); + itemB = new InteropInterface(123); + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + + var script = new Script(System.Array.Empty()); + itemA = new Pointer(script, 123); + itemB = new Pointer(script, 123); + itemC = new Pointer(script, 1234); + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + Assert.IsTrue(itemA.GetHashCode() != itemC.GetHashCode()); + } + + [TestMethod] + public void NullTest() + { + StackItem nullItem = System.Array.Empty(); + Assert.AreNotEqual(StackItem.Null, nullItem); + + nullItem = new Null(); + Assert.AreEqual(StackItem.Null, nullItem); + } + + [TestMethod] + public void EqualTest() + { + StackItem itemA = "NEO"; + StackItem itemB = "NEO"; + StackItem itemC = "SmartEconomy"; + StackItem itemD = "Smarteconomy"; + StackItem itemE = "smarteconomy"; + + Assert.IsTrue(itemA.Equals(itemB)); + Assert.IsFalse(itemA.Equals(itemC)); + Assert.IsFalse(itemC.Equals(itemD)); + Assert.IsFalse(itemD.Equals(itemE)); + Assert.IsFalse(itemA.Equals(new object())); + } + + [TestMethod] + public void CastTest() + { + // Signed byte + + StackItem item = sbyte.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(sbyte.MaxValue), ((Integer)item).GetInteger()); + + // Unsigned byte + + item = byte.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(byte.MaxValue), ((Integer)item).GetInteger()); + + // Signed short + + item = short.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(short.MaxValue), ((Integer)item).GetInteger()); + + // Unsigned short + + item = ushort.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(ushort.MaxValue), ((Integer)item).GetInteger()); + + // Signed integer + + item = int.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(int.MaxValue), ((Integer)item).GetInteger()); + + // Unsigned integer + + item = uint.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(uint.MaxValue), ((Integer)item).GetInteger()); + + // Signed long + + item = long.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(long.MaxValue), ((Integer)item).GetInteger()); + + // Unsigned long + + item = ulong.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(ulong.MaxValue), ((Integer)item).GetInteger()); + + // BigInteger + + item = BigInteger.MinusOne; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(-1), ((Integer)item).GetInteger()); + + // Boolean + + item = true; + + Assert.IsInstanceOfType(item, typeof(VM.Types.Boolean)); + Assert.IsTrue(item.GetBoolean()); + + // ByteString + + item = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + + Assert.IsInstanceOfType(item, typeof(ByteString)); + CollectionAssert.AreEqual(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }, item.GetSpan().ToArray()); + } + + [TestMethod] + public void DeepCopyTest() + { + Array a = new() + { + true, + 1, + new byte[] { 1 }, + StackItem.Null, + new Buffer(new byte[] { 1 }), + new Map { [0] = 1, [2] = 3 }, + new Struct { 1, 2, 3 } + }; + a.Add(a); + Array aa = (Array)a.DeepCopy(); + Assert.AreNotEqual(a, aa); + Assert.AreSame(aa, aa[^1]); + Assert.IsTrue(a[^2].Equals(aa[^2], ExecutionEngineLimits.Default)); + Assert.AreNotSame(a[^2], aa[^2]); + } + } +} diff --git a/tests/Neo.VM.Tests/UtStruct.cs b/tests/Neo.VM.Tests/UtStruct.cs new file mode 100644 index 0000000000..eb66ca934b --- /dev/null +++ b/tests/Neo.VM.Tests/UtStruct.cs @@ -0,0 +1,64 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; +using System; + +namespace Neo.Test +{ + [TestClass] + public class UtStruct + { + private readonly Struct @struct; + + public UtStruct() + { + @struct = new Struct { 1 }; + for (int i = 0; i < 20000; i++) + @struct = new Struct { @struct }; + } + + [TestMethod] + public void Clone() + { + Struct s1 = new() { 1, new Struct { 2 } }; + Struct s2 = s1.Clone(ExecutionEngineLimits.Default); + s1[0] = 3; + Assert.AreEqual(1, s2[0]); + ((Struct)s1[1])[0] = 3; + Assert.AreEqual(2, ((Struct)s2[1])[0]); + Assert.ThrowsException(() => @struct.Clone(ExecutionEngineLimits.Default)); + } + + [TestMethod] + public void Equals() + { + Struct s1 = new() { 1, new Struct { 2 } }; + Struct s2 = new() { 1, new Struct { 2 } }; + Assert.IsTrue(s1.Equals(s2, ExecutionEngineLimits.Default)); + Struct s3 = new() { 1, new Struct { 3 } }; + Assert.IsFalse(s1.Equals(s3, ExecutionEngineLimits.Default)); + Assert.ThrowsException(() => @struct.Equals(@struct.Clone(ExecutionEngineLimits.Default), ExecutionEngineLimits.Default)); + } + + [TestMethod] + public void EqualsDos() + { + string payloadStr = new string('h', 65535); + Struct s1 = new(); + Struct s2 = new(); + for (int i = 0; i < 2; i++) + { + s1.Add(payloadStr); + s2.Add(payloadStr); + } + Assert.ThrowsException(() => s1.Equals(s2, ExecutionEngineLimits.Default)); + + for (int i = 0; i < 1000; i++) + { + s1.Add(payloadStr); + s2.Add(payloadStr); + } + Assert.ThrowsException(() => s1.Equals(s2, ExecutionEngineLimits.Default)); + } + } +} diff --git a/tests/Neo.VM.Tests/UtUnsafe.cs b/tests/Neo.VM.Tests/UtUnsafe.cs new file mode 100644 index 0000000000..50c5ce59af --- /dev/null +++ b/tests/Neo.VM.Tests/UtUnsafe.cs @@ -0,0 +1,22 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; + +namespace Neo.Test +{ + [TestClass] + public class UtUnsafe + { + [TestMethod] + public void NotZero() + { + Assert.IsFalse(Unsafe.NotZero(System.Array.Empty())); + Assert.IsFalse(Unsafe.NotZero(new byte[4])); + Assert.IsFalse(Unsafe.NotZero(new byte[8])); + Assert.IsFalse(Unsafe.NotZero(new byte[11])); + + Assert.IsTrue(Unsafe.NotZero(new byte[4] { 0x00, 0x00, 0x00, 0x01 })); + Assert.IsTrue(Unsafe.NotZero(new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })); + Assert.IsTrue(Unsafe.NotZero(new byte[11] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })); + } + } +} diff --git a/tests/Neo.VM.Tests/UtUtility.cs b/tests/Neo.VM.Tests/UtUtility.cs new file mode 100644 index 0000000000..d833a57fdf --- /dev/null +++ b/tests/Neo.VM.Tests/UtUtility.cs @@ -0,0 +1,36 @@ +using System; +using System.Numerics; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; + +namespace Neo.Test +{ + [TestClass] + public class UtUtility + { + [TestMethod] + public void SqrtTest() + { + Assert.ThrowsException(() => BigInteger.MinusOne.Sqrt()); + + Assert.AreEqual(BigInteger.Zero, BigInteger.Zero.Sqrt()); + Assert.AreEqual(new BigInteger(1), new BigInteger(1).Sqrt()); + Assert.AreEqual(new BigInteger(1), new BigInteger(2).Sqrt()); + Assert.AreEqual(new BigInteger(1), new BigInteger(3).Sqrt()); + Assert.AreEqual(new BigInteger(2), new BigInteger(4).Sqrt()); + Assert.AreEqual(new BigInteger(9), new BigInteger(81).Sqrt()); + } + + [TestMethod] + public void ModInverseTest() + { + Assert.ThrowsException(() => BigInteger.One.ModInverse(BigInteger.Zero)); + Assert.ThrowsException(() => BigInteger.One.ModInverse(BigInteger.One)); + Assert.ThrowsException(() => BigInteger.Zero.ModInverse(BigInteger.Zero)); + Assert.ThrowsException(() => BigInteger.Zero.ModInverse(BigInteger.One)); + Assert.ThrowsException(() => new BigInteger(ushort.MaxValue).ModInverse(byte.MaxValue)); + + Assert.AreEqual(new BigInteger(52), new BigInteger(19).ModInverse(141)); + } + } +} diff --git a/tests/Neo.VM.Tests/UtVMJson.cs b/tests/Neo.VM.Tests/UtVMJson.cs new file mode 100644 index 0000000000..a80395b9c5 --- /dev/null +++ b/tests/Neo.VM.Tests/UtVMJson.cs @@ -0,0 +1,74 @@ +using System; +using System.IO; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.Test.Types; + +namespace Neo.Test +{ + [TestClass] + public class UtVMJson : VMJsonTestBase + { + [TestMethod] + public void TestOthers() => TestJson("./Tests/Others"); + + [TestMethod] + public void TestOpCodesArrays() => TestJson("./Tests/OpCodes/Arrays"); + + [TestMethod] + public void TestOpCodesStack() => TestJson("./Tests/OpCodes/Stack"); + + [TestMethod] + public void TestOpCodesSlot() => TestJson("./Tests/OpCodes/Slot"); + + [TestMethod] + public void TestOpCodesSplice() => TestJson("./Tests/OpCodes/Splice"); + + [TestMethod] + public void TestOpCodesControl() => TestJson("./Tests/OpCodes/Control"); + + [TestMethod] + public void TestOpCodesPush() => TestJson("./Tests/OpCodes/Push"); + + [TestMethod] + public void TestOpCodesArithmetic() => TestJson("./Tests/OpCodes/Arithmetic"); + + [TestMethod] + public void TestOpCodesBitwiseLogic() => TestJson("./Tests/OpCodes/BitwiseLogic"); + + [TestMethod] + public void TestOpCodesTypes() => TestJson("./Tests/OpCodes/Types"); + + private void TestJson(string path) + { + foreach (var file in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) + { + Console.WriteLine($"Processing file '{file}'"); + + var realFile = Path.GetFullPath(file); + var json = File.ReadAllText(realFile, Encoding.UTF8); + var ut = json.DeserializeJson(); + + Assert.IsFalse(string.IsNullOrEmpty(ut.Name), "Name is required"); + + if (json != ut.ToJson().Replace("\r\n", "\n")) + { + // Format json + + Console.WriteLine($"The file '{realFile}' was optimized"); + //File.WriteAllText(realFile, ut.ToJson().Replace("\r\n", "\n"), Encoding.UTF8); + } + + try + { + ExecuteTest(ut); + } + catch (Exception ex) + { + throw new AggregateException("Error in file: " + realFile, ex); + } + } + } + } +} diff --git a/tests/Neo.VM.Tests/VMJsonTestBase.cs b/tests/Neo.VM.Tests/VMJsonTestBase.cs new file mode 100644 index 0000000000..ac8e1494f6 --- /dev/null +++ b/tests/Neo.VM.Tests/VMJsonTestBase.cs @@ -0,0 +1,312 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.Test.Types; +using Neo.VM; +using Neo.VM.Types; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Neo.Test +{ + public abstract class VMJsonTestBase + { + /// + /// Execute this test + /// + /// Test + public void ExecuteTest(VMUT ut) + { + foreach (var test in ut.Tests) + { + Assert.IsFalse(string.IsNullOrEmpty(test.Name), "Name is required"); + + using TestEngine engine = new(); + Debugger debugger = new(engine); + + if (test.Script.Length > 0) + { + engine.LoadScript(test.Script); + } + + // Execute Steps + + if (test.Steps != null) + { + foreach (var step in test.Steps) + { + // Actions + + if (step.Actions != null) foreach (var run in step.Actions) + { + switch (run) + { + case VMUTActionType.Execute: debugger.Execute(); break; + case VMUTActionType.StepInto: debugger.StepInto(); break; + case VMUTActionType.StepOut: debugger.StepOut(); break; + case VMUTActionType.StepOver: debugger.StepOver(); break; + } + } + + // Review results + + var add = string.IsNullOrEmpty(step.Name) ? "" : "-" + step.Name; + + AssertResult(step.Result, engine, $"{ut.Category}-{ut.Name}-{test.Name}{add}: "); + } + } + } + } + + /// + /// Assert result + /// + /// Engine + /// Result + /// Message + private void AssertResult(VMUTExecutionEngineState result, TestEngine engine, string message) + { + AssertAreEqual(result.State.ToString().ToLowerInvariant(), engine.State.ToString().ToLowerInvariant(), message + "State is different"); + if (engine.State == VMState.FAULT) + { + if (result.ExceptionMessage != null) + { + AssertAreEqual(result.ExceptionMessage, engine.FaultException.Message, message + " [Exception]"); + } + return; + } + AssertResult(result.InvocationStack, engine.InvocationStack, message + " [Invocation stack]"); + AssertResult(result.ResultStack, engine.ResultStack, message + " [Result stack] "); + } + + /// + /// Assert invocation stack + /// + /// Stack + /// Result + /// Message + private void AssertResult(VMUTExecutionContextState[] result, Stack stack, string message) + { + AssertAreEqual(result == null ? 0 : result.Length, stack.Count, message + "Stack is different"); + + int x = 0; + foreach (var context in stack) + { + var opcode = context.InstructionPointer >= context.Script.Length ? OpCode.RET : context.Script[context.InstructionPointer]; + + AssertAreEqual(result[x].NextInstruction, opcode, message + "Next instruction is different"); + AssertAreEqual(result[x].InstructionPointer, context.InstructionPointer, message + "Instruction pointer is different"); + + // Check stack + + AssertResult(result[x].EvaluationStack, context.EvaluationStack, message + " [EvaluationStack]"); + + // Check slots + + AssertResult(result[x].Arguments, context.Arguments, message + " [Arguments]"); + AssertResult(result[x].LocalVariables, context.LocalVariables, message + " [LocalVariables]"); + AssertResult(result[x].StaticFields, context.StaticFields, message + " [StaticFields]"); + + x++; + } + } + + /// + /// Assert result stack + /// + /// Stack + /// Result + /// Message + private void AssertResult(VMUTStackItem[] result, EvaluationStack stack, string message) + { + AssertAreEqual(stack.Count, result == null ? 0 : result.Length, message + "Stack is different"); + + for (int x = 0, max = stack.Count; x < max; x++) + { + AssertAreEqual(ItemToJson(stack.Peek(x)).ToString(Formatting.None), PrepareJsonItem(result[x]).ToString(Formatting.None), message + "Stack item is different"); + } + } + + /// + /// Assert result slot + /// + /// Slot + /// Result + /// Message + private void AssertResult(VMUTStackItem[] result, Slot slot, string message) + { + AssertAreEqual(slot == null ? 0 : slot.Count, result == null ? 0 : result.Length, message + "Slot is different"); + + for (int x = 0, max = slot == null ? 0 : slot.Count; x < max; x++) + { + AssertAreEqual(ItemToJson(slot[x]).ToString(Formatting.None), PrepareJsonItem(result[x]).ToString(Formatting.None), message + "Stack item is different"); + } + } + + private JObject PrepareJsonItem(VMUTStackItem item) + { + var ret = new JObject + { + ["type"] = item.Type.ToString(), + ["value"] = item.Value + }; + + switch (item.Type) + { + case VMUTStackItemType.Null: + { + ret["type"] = VMUTStackItemType.Null.ToString(); + ret.Remove("value"); + break; + } + case VMUTStackItemType.Pointer: + { + ret["type"] = VMUTStackItemType.Pointer.ToString(); + ret["value"] = item.Value.Value(); + break; + } + case VMUTStackItemType.String: + { + // Easy access + + ret["type"] = VMUTStackItemType.ByteString.ToString(); + ret["value"] = Encoding.UTF8.GetBytes(item.Value.Value()); + break; + } + case VMUTStackItemType.ByteString: + case VMUTStackItemType.Buffer: + { + var value = ret["value"].Value(); + Assert.IsTrue(string.IsNullOrEmpty(value) || value.StartsWith("0x"), $"'0x' prefix required for value: '{value}'"); + ret["value"] = value.FromHexString(); + break; + } + case VMUTStackItemType.Integer: + { + // Ensure format + + ret["value"] = ret["value"].Value(); + break; + } + case VMUTStackItemType.Struct: + case VMUTStackItemType.Array: + { + var array = (JArray)ret["value"]; + + for (int x = 0, m = array.Count; x < m; x++) + { + array[x] = PrepareJsonItem(JsonConvert.DeserializeObject(array[x].ToString())); + } + + ret["value"] = array; + break; + } + case VMUTStackItemType.Map: + { + var obj = (JObject)ret["value"]; + + foreach (var prop in obj.Properties()) + { + obj[prop.Name] = PrepareJsonItem(JsonConvert.DeserializeObject(prop.Value.ToString())); + } + + ret["value"] = obj; + break; + } + } + + return ret; + } + + private JToken ItemToJson(StackItem item) + { + if (item == null) return null; + + JToken value; + string type = item.GetType().Name; + + switch (item) + { + case VM.Types.Null _: + { + return new JObject + { + ["type"] = type, + }; + } + case Pointer p: + { + return new JObject + { + ["type"] = type, + ["value"] = p.Position + }; + } + case VM.Types.Boolean v: value = new JValue(v.GetBoolean()); break; + case VM.Types.Integer v: value = new JValue(v.GetInteger().ToString()); break; + case VM.Types.ByteString v: value = new JValue(v.GetSpan().ToArray()); break; + case VM.Types.Buffer v: value = new JValue(v.InnerBuffer.ToArray()); break; + //case VM.Types.Struct v: + case VM.Types.Array v: + { + var jarray = new JArray(); + + foreach (var entry in v) + { + jarray.Add(ItemToJson(entry)); + } + + value = jarray; + break; + } + case VM.Types.Map v: + { + var jdic = new JObject(); + + foreach (var entry in v) + { + jdic.Add(entry.Key.GetSpan().ToArray().ToHexString(), ItemToJson(entry.Value)); + } + + value = jdic; + break; + } + case VM.Types.InteropInterface v: + { + type = "Interop"; + var obj = v.GetInterface(); + + value = obj.GetType().Name.ToString(); + break; + } + default: throw new NotImplementedException(); + } + + return new JObject + { + ["type"] = type, + ["value"] = value + }; + } + + /// + /// Assert with message + /// + /// A + /// B + /// Message + private static void AssertAreEqual(object expected, object actual, string message) + { + if (expected is byte[] ba) expected = ba.ToHexString().ToUpperInvariant(); + if (actual is byte[] bb) actual = bb.ToHexString().ToUpperInvariant(); + + if (expected.ToJson() != actual.ToJson()) + { + throw new Exception(message + + $"{Environment.NewLine}Expected:{Environment.NewLine + expected.ToString() + Environment.NewLine}Actual:{Environment.NewLine + actual.ToString()}"); + } + } + } +}