diff --git a/src/Neo.SmartContract.Testing/Attributes/FieldOrderAttribute.cs b/src/Neo.SmartContract.Testing/Attributes/FieldOrderAttribute.cs new file mode 100644 index 000000000..7935ef7fc --- /dev/null +++ b/src/Neo.SmartContract.Testing/Attributes/FieldOrderAttribute.cs @@ -0,0 +1,21 @@ +using System; + +namespace Neo.SmartContract.Testing.Attributes; + +[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] +public sealed class FieldOrderAttribute : Attribute +{ + /// + /// Gets the deserialization order of the property. + /// + public int Order { get; } + + /// + /// Constructor + /// + /// Order + public FieldOrderAttribute(int order) + { + Order = order; + } +} diff --git a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs index 427c4ff8c..b09127c5c 100644 --- a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs @@ -1,5 +1,6 @@ +using Akka.Util; using Neo.Cryptography.ECC; -using Neo.SmartContract.Iterators; +using Neo.SmartContract.Testing.Attributes; using Neo.VM.Types; using System; using System.Collections.Generic; @@ -11,6 +12,9 @@ namespace Neo.SmartContract.Testing.Extensions { public static class TestExtensions { + private static readonly Dictionary> _propertyCache = new(); + private static readonly Dictionary _fieldCache = new(); + /// /// Convert Array stack item to dotnet array /// @@ -75,18 +79,84 @@ public static class TestExtensions _ when type == typeof(UInt160) => new UInt160(stackItem.GetSpan().ToArray()), _ when type == typeof(UInt256) => new UInt256(stackItem.GetSpan().ToArray()), _ when type == typeof(ECPoint) => ECPoint.FromBytes(stackItem.GetSpan().ToArray(), ECCurve.Secp256r1), - _ when type == typeof(IDictionary) && stackItem is Map mp => ToDictionary(mp), // SubItems in StackItem type - _ when type == typeof(Dictionary) && stackItem is Map mp => ToDictionary(mp), // SubItems in StackItem type - _ when type == typeof(IList) && stackItem is CompoundType cp => new List(cp.SubItems), // SubItems in StackItem type - _ when type == typeof(List) && stackItem is CompoundType cp => new List(cp.SubItems), // SubItems in StackItem type _ when typeof(IInteroperable).IsAssignableFrom(type) => CreateInteroperable(stackItem, type), - _ when type.IsArray && stackItem is CompoundType cp => CreateTypeArray(cp.SubItems, type.GetElementType()!), _ when stackItem is InteropInterface it && it.GetInterface().GetType() == type => it.GetInterface(), + _ when stackItem is VM.Types.Array ar => type switch + { + _ when type == typeof(IList) => new List(ar.SubItems), // SubItems in StackItem type + _ when type == typeof(List) => new List(ar.SubItems), // SubItems in StackItem type + _ when type.IsArray => CreateTypeArray(ar.SubItems, type.GetElementType()!), + _ when type.IsClass => CreateObject(ar.SubItems, type), + _ when type.IsValueType => CreateValueType(ar.SubItems, type), + _ => throw new FormatException($"Impossible to convert {stackItem} to {type}"), + }, + _ when stackItem is Map mp => type switch + { + _ when type == typeof(IDictionary) => ToDictionary(mp), // SubItems in StackItem type + _ when type == typeof(Dictionary) => ToDictionary(mp), // SubItems in StackItem type + _ => throw new FormatException($"Impossible to convert {stackItem} to {type}"), + }, + _ => throw new FormatException($"Impossible to convert {stackItem} to {type}"), }; } + private static object CreateObject(IEnumerable subItems, Type type) + { + var index = 0; + var obj = Activator.CreateInstance(type) ?? throw new FormatException($"Impossible create {type}"); + + // Cache the object properties by offset + + if (!_propertyCache.TryGetValue(type, out var cache)) + { + cache = new Dictionary(); + + foreach (var property in type.GetProperties()) + { + var fieldOffset = property.GetCustomAttribute(); + if (fieldOffset is null) continue; + if (!property.CanWrite) continue; + + cache.Add(fieldOffset.Order, property); + } + + if (cache.Count == 0) + { + // Without FieldOrderAttribute, by order + + foreach (var property in type.GetProperties()) + { + if (!property.CanWrite) continue; + cache.Add(index, property); + index++; + } + index = 0; + } + + _propertyCache[type] = cache; + } + + // Fill the object + + foreach (var item in subItems) + { + if (cache.TryGetValue(index, out var property)) + { + property.SetValue(obj, ConvertTo(item, property.PropertyType)); + } + else + { + throw new FormatException($"Error converting {type}, the property with the offset {index} was not found."); + } + + index++; + } + + return obj; + } + private static IDictionary ToDictionary(Map map) { Dictionary dictionary = new(); @@ -99,6 +169,32 @@ private static IDictionary ToDictionary(Map map) return dictionary; } + private static object CreateValueType(IEnumerable objects, Type valueType) + { + var arr = objects.ToArray(); + var value = Activator.CreateInstance(valueType); + + // Cache the object properties by offset + + if (!_fieldCache.TryGetValue(valueType, out var cache)) + { + cache = valueType.GetFields().ToArray(); + _fieldCache[valueType] = cache; + } + + if (cache.Length != arr.Length) + { + throw new FormatException($"Error converting {valueType}, field count doesn't match."); + } + + for (int x = 0; x < arr.Length; x++) + { + cache[x].SetValue(value, ConvertTo(arr[x], cache[x].FieldType)); + } + + return value; + } + private static object CreateTypeArray(IEnumerable objects, Type elementType) { var obj = objects.ToArray(); diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index 01c73a8be..ddb60c955 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -2,7 +2,7 @@ using System.ComponentModel; using System.Numerics; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class ContractManagement : SmartContract { diff --git a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs index 54b50f1cd..ce7ed3bde 100644 --- a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Numerics; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class CryptoLib : SmartContract { diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs index 568aad13d..8745a9ea1 100644 --- a/src/Neo.SmartContract.Testing/Native/GasToken.cs +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Numerics; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class GasToken : SmartContract { diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs index 142a0d852..ef6eaf820 100644 --- a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -4,7 +4,7 @@ using System.ComponentModel; using System.Numerics; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class LedgerContract : SmartContract { diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index 82fe6139e..8c2bdc3a0 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -1,45 +1,26 @@ using Neo.Cryptography.ECC; -using Neo.IO; using Neo.SmartContract.Iterators; -using Neo.VM; -using Neo.VM.Types; -using System; +using Neo.SmartContract.Testing.Attributes; using System.ComponentModel; using System.Numerics; -using Neo.SmartContract.Testing.Extensions; -using System.Linq; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class NeoToken : SmartContract { - public class Candidate : IInteroperable + public class Candidate { /// /// Public key /// - public ECPoint? PublicKey { get; private set; } + [FieldOrder(0)] + public ECPoint? PublicKey { get; set; } /// /// Votes /// - public BigInteger Votes { get; private set; } = BigInteger.Zero; - - public void FromStackItem(StackItem stackItem) - { - if (stackItem is not CompoundType cp) throw new FormatException(); - if (cp.Count < 2) throw new FormatException(); - - var items = cp.SubItems.ToArray(); - - PublicKey = (ECPoint)items[0].ConvertTo(typeof(ECPoint))!; - Votes = (BigInteger)items[1].ConvertTo(typeof(BigInteger))!; - } - - public StackItem ToStackItem(ReferenceCounter referenceCounter) - { - return new VM.Types.Array(new StackItem[] { PublicKey.ToArray(), Votes }); - } + [FieldOrder(1)] + public BigInteger Votes { get; set; } } #region Events @@ -119,7 +100,7 @@ public StackItem ToStackItem(ReferenceCounter referenceCounter) /// Safe method /// [DisplayName("getAccountState")] - public abstract Native.NeoToken.NeoAccountState GetAccountState(UInt160? account); + public abstract Neo.SmartContract.Native.NeoToken.NeoAccountState GetAccountState(UInt160? account); /// /// Safe method diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs index 3c83fd3d0..bb3bc2b67 100644 --- a/src/Neo.SmartContract.Testing/Native/OracleContract.cs +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Numerics; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class OracleContract : SmartContract { diff --git a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs index fc9737f24..4b76b5055 100644 --- a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs +++ b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Numerics; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class PolicyContract : SmartContract { diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index 62eed6f97..c01b1f491 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -3,7 +3,7 @@ using System.ComponentModel; using System.Numerics; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class RoleManagement : SmartContract { diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index b687b9025..9d13dbe19 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Numerics; -namespace Neo.SmartContract.Testing; +namespace Neo.SmartContract.Testing.Native; public abstract class StdLib : SmartContract { diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index 7cc88c494..c93e3bfcf 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -1,4 +1,5 @@ using Neo.Persistence; +using Neo.SmartContract.Testing.Native; using System; using System.Reflection; @@ -64,15 +65,15 @@ public NativeArtifacts(TestEngine engine) { _engine = engine; - ContractManagement = _engine.FromHash(Native.NativeContract.ContractManagement.Hash, Native.NativeContract.ContractManagement.Id); - CryptoLib = _engine.FromHash(Native.NativeContract.CryptoLib.Hash, Native.NativeContract.CryptoLib.Id); - GAS = _engine.FromHash(Native.NativeContract.GAS.Hash, Native.NativeContract.GAS.Id); - NEO = _engine.FromHash(Native.NativeContract.NEO.Hash, Native.NativeContract.NEO.Id); - Ledger = _engine.FromHash(Native.NativeContract.Ledger.Hash, Native.NativeContract.Ledger.Id); - Oracle = _engine.FromHash(Native.NativeContract.Oracle.Hash, Native.NativeContract.Oracle.Id); - Policy = _engine.FromHash(Native.NativeContract.Policy.Hash, Native.NativeContract.Policy.Id); - RoleManagement = _engine.FromHash(Native.NativeContract.RoleManagement.Hash, Native.NativeContract.RoleManagement.Id); - StdLib = _engine.FromHash(Native.NativeContract.StdLib.Hash, Native.NativeContract.StdLib.Id); + ContractManagement = _engine.FromHash(Neo.SmartContract.Native.NativeContract.ContractManagement.Hash, Neo.SmartContract.Native.NativeContract.ContractManagement.Id); + CryptoLib = _engine.FromHash(Neo.SmartContract.Native.NativeContract.CryptoLib.Hash, Neo.SmartContract.Native.NativeContract.CryptoLib.Id); + GAS = _engine.FromHash(Neo.SmartContract.Native.NativeContract.GAS.Hash, Neo.SmartContract.Native.NativeContract.GAS.Id); + NEO = _engine.FromHash(Neo.SmartContract.Native.NativeContract.NEO.Hash, Neo.SmartContract.Native.NativeContract.NEO.Id); + Ledger = _engine.FromHash(Neo.SmartContract.Native.NativeContract.Ledger.Hash, Neo.SmartContract.Native.NativeContract.Ledger.Id); + Oracle = _engine.FromHash(Neo.SmartContract.Native.NativeContract.Oracle.Hash, Neo.SmartContract.Native.NativeContract.Oracle.Id); + Policy = _engine.FromHash(Neo.SmartContract.Native.NativeContract.Policy.Hash, Neo.SmartContract.Native.NativeContract.Policy.Id); + RoleManagement = _engine.FromHash(Neo.SmartContract.Native.NativeContract.RoleManagement.Hash, Neo.SmartContract.Native.NativeContract.RoleManagement.Id); + StdLib = _engine.FromHash(Neo.SmartContract.Native.NativeContract.StdLib.Hash, Neo.SmartContract.Native.NativeContract.StdLib.Id); } /// @@ -92,12 +93,12 @@ public void Initialize(bool commit = false) // Process native contracts - foreach (var native in new Native.NativeContract[] + foreach (var native in new Neo.SmartContract.Native.NativeContract[] { - Native.NativeContract.ContractManagement, - Native.NativeContract.Ledger, - Native.NativeContract.NEO, - Native.NativeContract.GAS + Neo.SmartContract.Native.NativeContract.ContractManagement, + Neo.SmartContract.Native.NativeContract.Ledger, + Neo.SmartContract.Native.NativeContract.NEO, + Neo.SmartContract.Native.NativeContract.GAS } ) { diff --git a/src/Neo.SmartContract.Testing/Storage/EngineStorage.cs b/src/Neo.SmartContract.Testing/Storage/EngineStorage.cs index 8c4500db7..06aaaf281 100644 --- a/src/Neo.SmartContract.Testing/Storage/EngineStorage.cs +++ b/src/Neo.SmartContract.Testing/Storage/EngineStorage.cs @@ -12,7 +12,7 @@ namespace Neo.SmartContract.Testing.Storage public class EngineStorage { // Key to check if native contracts are initialized, by default: Neo.votersCountPrefix - private static readonly StorageKey _initKey = new() { Id = Native.NativeContract.NEO.Id, Key = new byte[] { 1 } }; + private static readonly StorageKey _initKey = new() { Id = Neo.SmartContract.Native.NativeContract.NEO.Id, Key = new byte[] { 1 } }; /// /// Store diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 88465d50b..550dfcc6e 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -11,6 +11,7 @@ using Neo.VM.Types; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; @@ -394,7 +395,9 @@ private T MockContract(UInt160 hash, int? contractId = null, Action>? if (mock.IsMocked(method)) { - var mockName = method.Name + ";" + method.GetParameters().Length; + var display = method.GetCustomAttribute(); + var name = display is not null ? display.DisplayName : method.Name; + var mockName = name + ";" + method.GetParameters().Length; var cm = new CustomMock(mock.Object, method); if (_customMocks.TryGetValue(hash, out var mocks)) diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs index 2a6f6e6c5..d4988db76 100644 --- a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -1,5 +1,6 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.SmartContract.Native; using Neo.SmartContract.Testing.Extensions; using Neo.VM; using Neo.VM.Types; @@ -76,7 +77,7 @@ private void RecoverCoverage(Instruction instruction) { // We need the contract state without pay gas - var state = Native.NativeContract.ContractManagement.GetContract(Engine.Storage.Snapshot, contractHash); + var state = NativeContract.ContractManagement.GetContract(Engine.Storage.Snapshot, contractHash); coveredContract = new(Engine.MethodDetection, contractHash, state); Engine.Coverage[contractHash] = coveredContract; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/TestExtensionsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/TestExtensionsTests.cs index b909d3f38..66fe04a53 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/TestExtensionsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/TestExtensionsTests.cs @@ -1,7 +1,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography.ECC; +using Neo.IO; using Neo.SmartContract.Testing.Extensions; +using Neo.SmartContract.Testing.Native; using Neo.VM; using Neo.VM.Types; +using System.Numerics; namespace Neo.SmartContract.TestEngine.UnitTests.Extensions { @@ -15,5 +19,26 @@ public void TestConvertEnum() Assert.AreEqual(VMState.FAULT, (VMState)stackItem.ConvertTo(typeof(VMState))); } + + [TestMethod] + public void TestClass() + { + var point = ECCurve.Secp256r1.G; + StackItem stackItem = new Array(new StackItem[] { point.ToArray(), BigInteger.One }); + + var ret = (NeoToken.Candidate)stackItem.ConvertTo(typeof(NeoToken.Candidate)); + + Assert.AreEqual(point, ret.PublicKey); + Assert.AreEqual(1, ret.Votes); + } + + [TestMethod] + public void TestValueType() + { + StackItem stackItem = new Array(new StackItem[] { 1, 2 }); + var ret = stackItem.ConvertTo(typeof((int, int))); + + Assert.IsTrue(ret.GetType().IsValueType); + } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Neo.SmartContract.Testing.UnitTests.csproj b/tests/Neo.SmartContract.Testing.UnitTests/Neo.SmartContract.Testing.UnitTests.csproj index 09a33cb2e..87d6fe5fe 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Neo.SmartContract.Testing.UnitTests.csproj +++ b/tests/Neo.SmartContract.Testing.UnitTests/Neo.SmartContract.Testing.UnitTests.csproj @@ -5,6 +5,7 @@ + diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 728f4ab0d..7406f7f5a 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Neo.SmartContract.Testing.Extensions; +using Neo.SmartContract.Testing.Native; using Neo.VM; using System.Collections.Generic; using System.IO; @@ -19,7 +20,7 @@ protected MyUndeployedContract(SmartContractInitialize initialize) : base(initia //[TestMethod] public void GenerateNativeArtifacts() { - foreach (var n in Native.NativeContract.Contracts) + foreach (var n in Neo.SmartContract.Native.NativeContract.Contracts) { var manifest = n.Manifest; var source = manifest.GetArtifactsSource(manifest.Name, generateProperties: true); @@ -62,7 +63,7 @@ public void TestCustomMock() using (ScriptBuilder script = new()) { - script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.ValidatorsAddress); + script.EmitDynamicCall(neo.Hash, "balanceOf", engine.ValidatorsAddress); Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); } @@ -86,14 +87,14 @@ public void TestNativeContracts() { TestEngine engine = new(false); - Assert.AreEqual(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash); - Assert.AreEqual(engine.Native.StdLib.Hash, Native.NativeContract.StdLib.Hash); - Assert.AreEqual(engine.Native.CryptoLib.Hash, Native.NativeContract.CryptoLib.Hash); - Assert.AreEqual(engine.Native.GAS.Hash, Native.NativeContract.GAS.Hash); - Assert.AreEqual(engine.Native.NEO.Hash, Native.NativeContract.NEO.Hash); - Assert.AreEqual(engine.Native.Oracle.Hash, Native.NativeContract.Oracle.Hash); - Assert.AreEqual(engine.Native.Policy.Hash, Native.NativeContract.Policy.Hash); - Assert.AreEqual(engine.Native.RoleManagement.Hash, Native.NativeContract.RoleManagement.Hash); + Assert.AreEqual(engine.Native.ContractManagement.Hash, Neo.SmartContract.Native.NativeContract.ContractManagement.Hash); + Assert.AreEqual(engine.Native.StdLib.Hash, Neo.SmartContract.Native.NativeContract.StdLib.Hash); + Assert.AreEqual(engine.Native.CryptoLib.Hash, Neo.SmartContract.Native.NativeContract.CryptoLib.Hash); + Assert.AreEqual(engine.Native.GAS.Hash, Neo.SmartContract.Native.NativeContract.GAS.Hash); + Assert.AreEqual(engine.Native.NEO.Hash, Neo.SmartContract.Native.NativeContract.NEO.Hash); + Assert.AreEqual(engine.Native.Oracle.Hash, Neo.SmartContract.Native.NativeContract.Oracle.Hash); + Assert.AreEqual(engine.Native.Policy.Hash, Neo.SmartContract.Native.NativeContract.Policy.Hash); + Assert.AreEqual(engine.Native.RoleManagement.Hash, Neo.SmartContract.Native.NativeContract.RoleManagement.Hash); } [TestMethod]