diff --git a/neo.UnitTests/SmartContract/Enumerators/UT_ConcatenatedEnumerator.cs b/neo.UnitTests/SmartContract/Enumerators/UT_ConcatenatedEnumerator.cs new file mode 100644 index 0000000000..bbcfcdde78 --- /dev/null +++ b/neo.UnitTests/SmartContract/Enumerators/UT_ConcatenatedEnumerator.cs @@ -0,0 +1,55 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Enumerators; +using Neo.SmartContract.Iterators; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections.Generic; + +namespace Neo.UnitTests.SmartContract.Enumerators +{ + [TestClass] + public class UT_ConcatenatedEnumerator + { + [TestMethod] + public void TestConcatenatedIteratorAndDispose() + { + List list1 = new List(); + StackItem stackItem1 = new Integer(0); + list1.Add(stackItem1); + List list2 = new List(); + StackItem stackItem2 = new Integer(0); + list2.Add(stackItem2); + ArrayWrapper arrayWrapper1 = new ArrayWrapper(list1); + ArrayWrapper arrayWrapper2 = new ArrayWrapper(list2); + IteratorKeysWrapper it1 = new IteratorKeysWrapper(arrayWrapper1); + IteratorKeysWrapper it2 = new IteratorKeysWrapper(arrayWrapper2); + ConcatenatedEnumerator uut = new ConcatenatedEnumerator(it1, it2); + Assert.IsNotNull(uut); + Action action = () => uut.Dispose(); + action.Should().NotThrow(); + } + + [TestMethod] + public void TestNextAndValue() + { + List list1 = new List(); + StackItem stackItem1 = new Integer(1); + list1.Add(stackItem1); + List list2 = new List(); + StackItem stackItem2 = new Integer(0); + list2.Add(stackItem2); + ArrayWrapper arrayWrapper1 = new ArrayWrapper(list1); + ArrayWrapper arrayWrapper2 = new ArrayWrapper(list2); + IteratorKeysWrapper it1 = new IteratorKeysWrapper(arrayWrapper1); + IteratorKeysWrapper it2 = new IteratorKeysWrapper(arrayWrapper2); + ConcatenatedEnumerator uut = new ConcatenatedEnumerator(it1, it2); + Assert.AreEqual(true, uut.Next()); + Assert.AreEqual(new Integer(0), uut.Value()); + Assert.AreEqual(true, uut.Next()); + Assert.AreEqual(new Integer(0), uut.Value()); + Assert.AreEqual(false, uut.Next()); + } + } +} diff --git a/neo.UnitTests/SmartContract/Enumerators/UT_IteratorKeysWrapper.cs b/neo.UnitTests/SmartContract/Enumerators/UT_IteratorKeysWrapper.cs new file mode 100644 index 0000000000..2a345893e0 --- /dev/null +++ b/neo.UnitTests/SmartContract/Enumerators/UT_IteratorKeysWrapper.cs @@ -0,0 +1,36 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Enumerators; +using Neo.SmartContract.Iterators; +using Neo.VM; +using System; +using System.Collections.Generic; + +namespace Neo.UnitTests.SmartContract.Enumerators +{ + [TestClass] + public class UT_IteratorKeysWrapper + { + [TestMethod] + public void TestGeneratorAndDispose() + { + IteratorKeysWrapper iteratorKeysWrapper = new IteratorKeysWrapper(new ArrayWrapper(new List())); + Assert.IsNotNull(iteratorKeysWrapper); + Action action = () => iteratorKeysWrapper.Dispose(); + action.Should().NotThrow(); + } + + [TestMethod] + public void TestNextAndValue() + { + StackItem stackItem = new VM.Types.Boolean(true); + List list = new List(); + list.Add(stackItem); + ArrayWrapper wrapper = new ArrayWrapper(list); + IteratorKeysWrapper iteratorKeysWrapper = new IteratorKeysWrapper(wrapper); + Action action = () => iteratorKeysWrapper.Next(); + action.Should().NotThrow(); + Assert.AreEqual(new VM.Types.Integer(0), iteratorKeysWrapper.Value()); + } + } +} diff --git a/neo.UnitTests/SmartContract/Enumerators/UT_IteratorValuesWrapper.cs b/neo.UnitTests/SmartContract/Enumerators/UT_IteratorValuesWrapper.cs new file mode 100644 index 0000000000..f236faab1a --- /dev/null +++ b/neo.UnitTests/SmartContract/Enumerators/UT_IteratorValuesWrapper.cs @@ -0,0 +1,37 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Enumerators; +using Neo.SmartContract.Iterators; +using Neo.VM; +using System; +using System.Collections.Generic; + +namespace Neo.UnitTests.SmartContract.Enumerators +{ + + [TestClass] + public class UT_IteratorValuesWrapper + { + [TestMethod] + public void TestGeneratorAndDispose() + { + IteratorValuesWrapper iteratorValuesWrapper = new IteratorValuesWrapper(new ArrayWrapper(new List())); + Assert.IsNotNull(iteratorValuesWrapper); + Action action = () => iteratorValuesWrapper.Dispose(); + action.Should().NotThrow(); + } + + [TestMethod] + public void TestNextAndValue() + { + StackItem stackItem = new VM.Types.Boolean(true); + List list = new List(); + list.Add(stackItem); + ArrayWrapper wrapper = new ArrayWrapper(list); + IteratorValuesWrapper iteratorValuesWrapper = new IteratorValuesWrapper(wrapper); + Action action = () => iteratorValuesWrapper.Next(); + action.Should().NotThrow(); + Assert.AreEqual(stackItem, iteratorValuesWrapper.Value()); + } + } +} diff --git a/neo.UnitTests/SmartContract/Iterators/UT_ArrayWrapper.cs b/neo.UnitTests/SmartContract/Iterators/UT_ArrayWrapper.cs new file mode 100644 index 0000000000..9aebf0861c --- /dev/null +++ b/neo.UnitTests/SmartContract/Iterators/UT_ArrayWrapper.cs @@ -0,0 +1,50 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Iterators; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections.Generic; + +namespace Neo.UnitTests.SmartContract.Iterators +{ + [TestClass] + public class UT_ArrayWrapper + { + [TestMethod] + public void TestGeneratorAndDispose() + { + ArrayWrapper arrayWrapper = new ArrayWrapper(new List()); + Assert.IsNotNull(arrayWrapper); + Action action = () => arrayWrapper.Dispose(); + action.Should().NotThrow(); + } + + [TestMethod] + public void TestKeyAndValue() + { + List list = new List(); + StackItem stackItem = new Integer(0); + list.Add(stackItem); + ArrayWrapper arrayWrapper = new ArrayWrapper(list); + Action action1 = () => arrayWrapper.Key(); + action1.Should().Throw(); + Action action2 = () => arrayWrapper.Value(); + action2.Should().Throw(); + arrayWrapper.Next(); + Assert.AreEqual(stackItem, arrayWrapper.Key()); + Assert.AreEqual(stackItem, arrayWrapper.Value()); + } + + [TestMethod] + public void TestNext() + { + List list = new List(); + ArrayWrapper arrayWrapper = new ArrayWrapper(list); + Assert.AreEqual(false, arrayWrapper.Next()); + StackItem stackItem = new Integer(0); + list.Add(stackItem); + Assert.AreEqual(true, arrayWrapper.Next()); + } + } +} diff --git a/neo.UnitTests/SmartContract/Iterators/UT_ConcatenatedIterator.cs b/neo.UnitTests/SmartContract/Iterators/UT_ConcatenatedIterator.cs index 5fad01c94b..84b3ffe041 100644 --- a/neo.UnitTests/SmartContract/Iterators/UT_ConcatenatedIterator.cs +++ b/neo.UnitTests/SmartContract/Iterators/UT_ConcatenatedIterator.cs @@ -2,11 +2,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract.Iterators; using Neo.VM.Types; +using System; using System.Numerics; namespace Neo.UnitTests.SmartContract.Iterators { - [TestClass] public class UT_ConcatenatedIterator { @@ -65,5 +65,17 @@ private Integer MakeIntegerStackItem(int val) { return new Integer(new BigInteger(val)); } + + [TestMethod] + public void TestDispose() + { + Integer[] array1 = { MakeIntegerStackItem(1), MakeIntegerStackItem(7), MakeIntegerStackItem(23) }; + Integer[] array2 = { MakeIntegerStackItem(8), MakeIntegerStackItem(47) }; + ArrayWrapper it1 = new ArrayWrapper(array1); + ArrayWrapper it2 = new ArrayWrapper(array2); + ConcatenatedIterator uut = new ConcatenatedIterator(it1, it2); + Action action = () => uut.Dispose(); + action.Should().NotThrow(); + } } } diff --git a/neo.UnitTests/SmartContract/Iterators/UT_MapWrapper.cs b/neo.UnitTests/SmartContract/Iterators/UT_MapWrapper.cs new file mode 100644 index 0000000000..b111b0aa54 --- /dev/null +++ b/neo.UnitTests/SmartContract/Iterators/UT_MapWrapper.cs @@ -0,0 +1,43 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Iterators; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections.Generic; + +namespace Neo.UnitTests.SmartContract.Iterators +{ + [TestClass] + public class UT_MapWrapper + { + [TestMethod] + public void TestGeneratorAndDispose() + { + MapWrapper mapWrapper = new MapWrapper(new List>()); + Assert.IsNotNull(mapWrapper); + Action action = () => mapWrapper.Dispose(); + action.Should().NotThrow(); + } + + [TestMethod] + public void TestKeyAndValue() + { + List> list = new List>(); + StackItem stackItem1 = new Integer(0); + StackItem stackItem2 = new Integer(1); + list.Add(new KeyValuePair(stackItem1, stackItem2)); + MapWrapper mapWrapper = new MapWrapper(list); + mapWrapper.Next(); + Assert.AreEqual(stackItem1, mapWrapper.Key()); + Assert.AreEqual(stackItem2, mapWrapper.Value()); + } + + [TestMethod] + public void TestNext() + { + MapWrapper mapWrapper = new MapWrapper(new List>()); + Assert.AreEqual(false, mapWrapper.Next()); + } + } +} diff --git a/neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs b/neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs new file mode 100644 index 0000000000..aad833b04e --- /dev/null +++ b/neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs @@ -0,0 +1,38 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Ledger; +using Neo.SmartContract.Iterators; +using Neo.VM.Types; +using System; +using System.Collections.Generic; + +namespace Neo.UnitTests.SmartContract.Iterators +{ + [TestClass] + public class UT_StorageIterator + { + [TestMethod] + public void TestGeneratorAndDispose() + { + StorageIterator storageIterator = new StorageIterator(new List>().GetEnumerator()); + Assert.IsNotNull(storageIterator); + Action action = () => storageIterator.Dispose(); + action.Should().NotThrow(); + } + + [TestMethod] + public void TestKeyAndValueAndNext() + { + List> list = new List>(); + StorageKey storageKey = new StorageKey(); + storageKey.Key = new byte[1]; + StorageItem storageItem = new StorageItem(); + storageItem.Value = new byte[1]; + list.Add(new KeyValuePair(storageKey, storageItem)); + StorageIterator storageIterator = new StorageIterator(list.GetEnumerator()); + storageIterator.Next(); + Assert.AreEqual(new ByteArray(new byte[1]), storageIterator.Key()); + Assert.AreEqual(new ByteArray(new byte[1]), storageIterator.Value()); + } + } +} diff --git a/neo.UnitTests/SmartContract/Manifest/UT_ContractEventDescriptor.cs b/neo.UnitTests/SmartContract/Manifest/UT_ContractEventDescriptor.cs new file mode 100644 index 0000000000..abbc4af5a0 --- /dev/null +++ b/neo.UnitTests/SmartContract/Manifest/UT_ContractEventDescriptor.cs @@ -0,0 +1,22 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Manifest; + +namespace Neo.UnitTests.SmartContract.Manifest +{ + [TestClass] + public class UT_ContractEventDescriptor + { + [TestMethod] + public void TestFromJson() + { + ContractEventDescriptor expected = new ContractEventDescriptor + { + Name = "AAA", + Parameters = new ContractParameterDefinition[0] + }; + ContractEventDescriptor actual = ContractEventDescriptor.FromJson(expected.ToJson()); + Assert.AreEqual(expected.Name, actual.Name); + Assert.AreEqual(0, actual.Parameters.Length); + } + } +} diff --git a/neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs b/neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs new file mode 100644 index 0000000000..92519e26e5 --- /dev/null +++ b/neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs @@ -0,0 +1,42 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography; +using Neo.Cryptography.ECC; +using Neo.SmartContract.Manifest; +using Neo.Wallets; +using System; +using System.Linq; + +namespace Neo.UnitTests.SmartContract.Manifest +{ + [TestClass] + public class UT_ContractGroup + { + [TestMethod] + public void TestIsValid() + { + Random random = new Random(); + byte[] privateKey = new byte[32]; + random.NextBytes(privateKey); + KeyPair keyPair = new KeyPair(privateKey); + ContractGroup contractGroup = new ContractGroup + { + PubKey = keyPair.PublicKey, + Signature = new byte[20] + }; + Assert.AreEqual(false, contractGroup.IsValid(UInt160.Zero)); + + + byte[] message = new byte[] { 0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01 }; + byte[] signature = Crypto.Default.Sign(message, keyPair.PrivateKey, keyPair.PublicKey.EncodePoint(false).Skip(1).ToArray()); + contractGroup = new ContractGroup + { + PubKey = keyPair.PublicKey, + Signature = signature + }; + Assert.AreEqual(true, contractGroup.IsValid(new UInt160(message))); + } + } +} diff --git a/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs b/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs index a96c3ff4c5..910f30b019 100644 --- a/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs +++ b/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; using Neo.SmartContract.Manifest; +using System.IO; namespace Neo.UnitTests.SmartContract.Manifest { @@ -84,5 +85,59 @@ public void ParseFromJson_Groups() check.Groups = new ContractGroup[] { new ContractGroup() { PubKey = ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1), Signature = "41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141".HexToBytes() } }; Assert.AreEqual(manifest.ToString(), check.ToString()); } + + [TestMethod] + public void TestDeserializeAndSerialize() + { + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + BinaryReader reader = new BinaryReader(stream); + var expected = ContractManifest.CreateDefault(UInt160.Zero); + expected.SafeMethods = WildCardContainer.Create(new string[] { "AAA" }); + expected.Serialize(writer); + stream.Seek(0, SeekOrigin.Begin); + var actual = ContractManifest.CreateDefault(UInt160.Zero); + actual.Deserialize(reader); + Assert.AreEqual(expected.SafeMethods.ToString(), actual.SafeMethods.ToString()); + Assert.AreEqual(expected.SafeMethods.Count, 1); + } + + [TestMethod] + public void TestGetHash() + { + var temp = ContractManifest.CreateDefault(UInt160.Zero); + Assert.AreEqual(temp.Abi.Hash, temp.Hash); + } + + [TestMethod] + public void TestGetSize() + { + var temp = ContractManifest.CreateDefault(UInt160.Zero); + Assert.AreEqual(353, temp.Size); + } + + [TestMethod] + public void TestGenerator() + { + ContractManifest contractManifest = new ContractManifest(); + Assert.IsNotNull(contractManifest); + } + + [TestMethod] + public void TestCanCall() + { + var temp = ContractManifest.CreateDefault(UInt160.Zero); + temp.SafeMethods = WildCardContainer.Create(new string[] { "AAA" }); + Assert.AreEqual(true, temp.CanCall(ContractManifest.CreateDefault(UInt160.Zero), "AAA")); + } + + [TestMethod] + public void TestClone() + { + var expected = ContractManifest.CreateDefault(UInt160.Zero); + expected.SafeMethods = WildCardContainer.Create(new string[] { "AAA" }); + var actual = expected.Clone(); + Assert.AreEqual(actual.SafeMethods.ToString(), expected.SafeMethods.ToString()); + } } } diff --git a/neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs b/neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs new file mode 100644 index 0000000000..7517458423 --- /dev/null +++ b/neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs @@ -0,0 +1,52 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography.ECC; +using Neo.SmartContract.Manifest; +using System; + +namespace Neo.UnitTests.SmartContract.Manifest +{ + [TestClass] + public class UT_ContractPermission + { + [TestMethod] + public void TestIsAllowed() + { + ContractManifest contractManifest1 = ContractManifest.CreateDefault(UInt160.Zero); + ContractPermission contractPermission1 = ContractPermission.DefaultPermission; + contractPermission1.Contract = ContractPermissionDescriptor.Create(UInt160.Zero); + Assert.AreEqual(true, contractPermission1.IsAllowed(contractManifest1, "AAA")); + contractPermission1.Contract = ContractPermissionDescriptor.CreateWildcard(); + + ContractManifest contractManifest2 = ContractManifest.CreateDefault(UInt160.Zero); + ContractPermission contractPermission2 = ContractPermission.DefaultPermission; + contractPermission2.Contract = ContractPermissionDescriptor.Create(UInt160.Parse("0x0000000000000000000000000000000000000001")); + Assert.AreEqual(false, contractPermission2.IsAllowed(contractManifest2, "AAA")); + contractPermission2.Contract = ContractPermissionDescriptor.CreateWildcard(); + + Random random3 = new Random(); + byte[] privateKey3 = new byte[32]; + random3.NextBytes(privateKey3); + ECPoint publicKey3 = ECCurve.Secp256r1.G * privateKey3; + ContractManifest contractManifest3 = ContractManifest.CreateDefault(UInt160.Zero); + contractManifest3.Groups = new ContractGroup[] { new ContractGroup() { PubKey = publicKey3 } }; + ContractPermission contractPermission3 = ContractPermission.DefaultPermission; + contractPermission3.Contract = ContractPermissionDescriptor.Create(publicKey3); + Assert.AreEqual(true, contractPermission3.IsAllowed(contractManifest3, "AAA")); + contractPermission3.Contract = ContractPermissionDescriptor.CreateWildcard(); + + Random random4 = new Random(); + byte[] privateKey41 = new byte[32]; + random4.NextBytes(privateKey41); + ECPoint publicKey41 = ECCurve.Secp256r1.G * privateKey41; + byte[] privateKey42 = new byte[32]; + random4.NextBytes(privateKey42); + ECPoint publicKey42 = ECCurve.Secp256r1.G * privateKey42; + ContractManifest contractManifest4 = ContractManifest.CreateDefault(UInt160.Zero); + contractManifest4.Groups = new ContractGroup[] { new ContractGroup() { PubKey = publicKey42 } }; + ContractPermission contractPermission4 = ContractPermission.DefaultPermission; + contractPermission4.Contract = ContractPermissionDescriptor.Create(publicKey41); + Assert.AreEqual(false, contractPermission4.IsAllowed(contractManifest4, "AAA")); + contractPermission4.Contract = ContractPermissionDescriptor.CreateWildcard(); + } + } +} diff --git a/neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs b/neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs new file mode 100644 index 0000000000..299ff2e49d --- /dev/null +++ b/neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs @@ -0,0 +1,37 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Manifest; +using Neo.Wallets; +using System.Security.Cryptography; + +namespace Neo.UnitTests.SmartContract.Manifest +{ + [TestClass] + public class UT_ContractPermissionDescriptor + { + [TestMethod] + public void TestCreateByECPointAndIsWildcard() + { + byte[] privateKey = new byte[32]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes(privateKey); + KeyPair key = new KeyPair(privateKey); + ContractPermissionDescriptor contractPermissionDescriptor = ContractPermissionDescriptor.Create(key.PublicKey); + Assert.IsNotNull(contractPermissionDescriptor); + Assert.AreEqual(key.PublicKey, contractPermissionDescriptor.Group); + Assert.AreEqual(false, contractPermissionDescriptor.IsWildcard); + } + + [TestMethod] + public void TestFromAndToJson() + { + byte[] privateKey = new byte[32]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes(privateKey); + KeyPair key = new KeyPair(privateKey); + ContractPermissionDescriptor temp = ContractPermissionDescriptor.Create(key.PublicKey); + ContractPermissionDescriptor result = ContractPermissionDescriptor.FromJson(temp.ToJson()); + Assert.AreEqual(null, result.Hash); + Assert.AreEqual(result.Group, result.Group); + } + } +} diff --git a/neo.UnitTests/SmartContract/Manifest/UT_WildCardContainer.cs b/neo.UnitTests/SmartContract/Manifest/UT_WildCardContainer.cs new file mode 100644 index 0000000000..96bec21d2d --- /dev/null +++ b/neo.UnitTests/SmartContract/Manifest/UT_WildCardContainer.cs @@ -0,0 +1,91 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO.Json; +using Neo.SmartContract.Manifest; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Neo.UnitTests.SmartContract.Manifest +{ + [TestClass] + public class UT_WildCardContainer + { + [TestMethod] + public void TestFromJson() + { + JString jstring = new JString("*"); + WildCardContainer s = WildCardContainer.FromJson(jstring, u => u.AsString()); + s.Should().BeEmpty(); + + jstring = new JString("hello world"); + Action action = () => WildCardContainer.FromJson(jstring, u => u.AsString()); + action.Should().Throw(); + + JObject alice = new JObject(); + alice["name"] = "alice"; + alice["age"] = 30; + JArray jarray = new JArray { alice }; + WildCardContainer r = WildCardContainer.FromJson(jarray, u => u.AsString()); + r[0].Should().Be("{\"name\":\"alice\",\"age\":30}"); + + JBoolean jbool = new JBoolean(); + action = () => WildCardContainer.FromJson(jbool, u => u.AsString()); + action.Should().Throw(); + } + + [TestMethod] + public void TestGetCount() + { + string[] s = new string[] { "hello", "world" }; + WildCardContainer container = WildCardContainer.Create(s); + container.Count.Should().Be(2); + + s = null; + container = WildCardContainer.Create(s); + container.Count.Should().Be(0); + } + + [TestMethod] + public void TestGetItem() + { + string[] s = new string[] { "hello", "world" }; + WildCardContainer container = WildCardContainer.Create(s); + container[0].Should().Be("hello"); + container[1].Should().Be("world"); + } + + [TestMethod] + public void TestGetEnumerator() + { + string[] s = null; + IReadOnlyList rs = (IReadOnlyList)new string[0]; + WildCardContainer container = WildCardContainer.Create(s); + IEnumerator enumerator = container.GetEnumerator(); + enumerator.Should().Be(rs.GetEnumerator()); + + s = new string[] { "hello", "world" }; + container = WildCardContainer.Create(s); + enumerator = container.GetEnumerator(); + foreach (string _ in s) + { + enumerator.MoveNext(); + enumerator.Current.Should().Be(_); + } + } + + [TestMethod] + public void TestIEnumerableGetEnumerator() + { + string[] s = new string[] { "hello", "world" }; + WildCardContainer container = WildCardContainer.Create(s); + IEnumerable enumerable = container; + var enumerator = enumerable.GetEnumerator(); + foreach (string _ in s) + { + enumerator.MoveNext(); + enumerator.Current.Should().Be(_); + } + } + } +} diff --git a/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 0202e9d6d0..7e811d3eda 100644 --- a/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -7,6 +7,7 @@ using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; using Neo.VM; +using Neo.VM.Types; using System; using System.Linq; using System.Numerics; @@ -140,5 +141,46 @@ public void Check_BadScript() NativeContract.GAS.Invoke(engine).Should().BeFalse(); } + + [TestMethod] + public void TestGetSysFeeAmount1() + { + using (ApplicationEngine engine = NativeContract.GAS.TestCall("getSysFeeAmount", 2u)) + { + engine.ResultStack.Peek().GetBigInteger().Should().Be(new BigInteger(0)); + engine.ResultStack.Peek().GetType().Should().Be(typeof(Integer)); + } + + using (ApplicationEngine engine = NativeContract.GAS.TestCall("getSysFeeAmount", 0u)) + { + engine.ResultStack.Peek().GetBigInteger().Should().Be(new BigInteger(0)); + } + } + + [TestMethod] + public void TestGetSysFeeAmount2() + { + var snapshot = Store.GetSnapshot().Clone(); + NativeContract.GAS.GetSysFeeAmount(snapshot, 0).Should().Be(new BigInteger(0)); + NativeContract.GAS.GetSysFeeAmount(snapshot, 1).Should().Be(new BigInteger(0)); + + byte[] key = BitConverter.GetBytes(1); + StorageKey storageKey = new StorageKey + { + ScriptHash = NativeContract.GAS.Hash, + Key = new byte[sizeof(byte) + (key?.Length ?? 0)] + }; + storageKey.Key[0] = 15; + Buffer.BlockCopy(key, 0, storageKey.Key, 1, key.Length); + + BigInteger sys_fee = new BigInteger(10); + snapshot.Storages.Add(storageKey, new StorageItem + { + Value = sys_fee.ToByteArray(), + IsConstant = true + }); + + NativeContract.GAS.GetSysFeeAmount(snapshot, 1).Should().Be(sys_fee); + } } } diff --git a/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 38befbe790..6df9f7074e 100644 --- a/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -14,6 +14,7 @@ using System; using System.Linq; using System.Numerics; +using static Neo.SmartContract.Native.Tokens.NeoToken; namespace Neo.UnitTests.SmartContract.Native.Tokens { @@ -248,6 +249,335 @@ public void Check_BadScript() NativeContract.NEO.Invoke(engine).Should().BeFalse(); } + [TestMethod] + public void TestCalculateBonus() + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); + snapshot.Storages.Add(key, new StorageItem + { + Value = new AccountState() + { + Balance = -100 + }.ToByteArray() + }); + Action action = () => NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + action.Should().Throw(); + snapshot.Storages.Delete(key); + snapshot.Storages.GetAndChange(key, () => new StorageItem + { + Value = new AccountState() + { + Balance = 100 + }.ToByteArray() + }); + NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 30 * Blockchain.DecrementInterval).Should().Be(new BigInteger(7000000000)); + } + + [TestMethod] + public void TestGetNextBlockValidators1() + { + using (ApplicationEngine engine = NativeContract.NEO.TestCall("getNextBlockValidators")) + { + var result = engine.ResultStack.Peek(); + result.GetType().Should().Be(typeof(VM.Types.Array)); + ((VM.Types.Array)result).Count.Should().Be(7); + ((VM.Types.ByteArray)((VM.Types.Array)result)[0]).GetByteArray().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[1]).GetByteArray().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[2]).GetByteArray().ToHexString().Should().Be("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[3]).GetByteArray().ToHexString().Should().Be("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[4]).GetByteArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[5]).GetByteArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[6]).GetByteArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); + } + } + + [TestMethod] + public void TestGetNextBlockValidators2() + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + var result = NativeContract.NEO.GetNextBlockValidators(snapshot); + result.Length.Should().Be(7); + result[0].ToArray().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); + result[1].ToArray().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); + result[2].ToArray().ToHexString().Should().Be("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"); + result[3].ToArray().ToHexString().Should().Be("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"); + result[4].ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); + result[5].ToArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); + result[6].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); + + snapshot.Storages.Add(CreateStorageKey(14), new StorageItem() + { + Value = new ECPoint[] { ECCurve.Secp256r1.G }.ToByteArray() + }); + result = NativeContract.NEO.GetNextBlockValidators(snapshot); + result.Length.Should().Be(1); + result[0].ToArray().ToHexString().Should().Be("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"); + } + + [TestMethod] + public void TestGetRegisteredValidators1() + { + using (ApplicationEngine engine = NativeContract.NEO.TestCall("getRegisteredValidators")) + { + var result = engine.ResultStack.Peek(); + result.GetType().Should().Be(typeof(VM.Types.Array)); + ((VM.Types.Array)result).Count.Should().Be(7); + ((VM.Types.ByteArray)((VM.Types.Struct)((VM.Types.Array)result)[0])[0]).GetByteArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); + ((VM.Types.Struct)((VM.Types.Array)result)[0])[1].GetBigInteger().Should().Be(new BigInteger(0)); + ((VM.Types.ByteArray)((VM.Types.Struct)((VM.Types.Array)result)[1])[0]).GetByteArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); + ((VM.Types.Struct)((VM.Types.Array)result)[1])[1].GetBigInteger().Should().Be(new BigInteger(0)); + ((VM.Types.ByteArray)((VM.Types.Struct)((VM.Types.Array)result)[2])[0]).GetByteArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); + ((VM.Types.Struct)((VM.Types.Array)result)[2])[1].GetBigInteger().Should().Be(new BigInteger(0)); + ((VM.Types.ByteArray)((VM.Types.Struct)((VM.Types.Array)result)[3])[0]).GetByteArray().ToHexString().Should().Be("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"); + ((VM.Types.Struct)((VM.Types.Array)result)[3])[1].GetBigInteger().Should().Be(new BigInteger(0)); + ((VM.Types.ByteArray)((VM.Types.Struct)((VM.Types.Array)result)[4])[0]).GetByteArray().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); + ((VM.Types.Struct)((VM.Types.Array)result)[4])[1].GetBigInteger().Should().Be(new BigInteger(0)); + ((VM.Types.ByteArray)((VM.Types.Struct)((VM.Types.Array)result)[5])[0]).GetByteArray().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); + ((VM.Types.Struct)((VM.Types.Array)result)[5])[1].GetBigInteger().Should().Be(new BigInteger(0)); + ((VM.Types.ByteArray)((VM.Types.Struct)((VM.Types.Array)result)[6])[0]).GetByteArray().ToHexString().Should().Be("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"); + ((VM.Types.Struct)((VM.Types.Array)result)[6])[1].GetBigInteger().Should().Be(new BigInteger(0)); + } + } + + [TestMethod] + public void TestGetRegisteredValidators2() + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + var result = NativeContract.NEO.GetRegisteredValidators(snapshot).ToArray(); + result.Length.Should().Be(7); + result[0].PublicKey.ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); + result[0].Votes.Should().Be(new BigInteger(0)); + result[1].PublicKey.ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); + result[1].Votes.Should().Be(new BigInteger(0)); + result[2].PublicKey.ToArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); + result[2].Votes.Should().Be(new BigInteger(0)); + result[3].PublicKey.ToArray().ToHexString().Should().Be("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"); + result[3].Votes.Should().Be(new BigInteger(0)); + result[4].PublicKey.ToArray().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); + result[4].Votes.Should().Be(new BigInteger(0)); + result[5].PublicKey.ToArray().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); + result[5].Votes.Should().Be(new BigInteger(0)); + result[6].PublicKey.ToArray().ToHexString().Should().Be("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"); + result[6].Votes.Should().Be(new BigInteger(0)); + + StorageKey key = NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G); + snapshot.Storages.Add(key, new StorageItem + { + Value = new ValidatorState().ToByteArray() + }); + NativeContract.NEO.GetRegisteredValidators(snapshot).ToArray().Length.Should().Be(8); + } + + [TestMethod] + public void TestGetValidators1() + { + using (ApplicationEngine engine = NativeContract.NEO.TestCall("getValidators")) + { + var result = engine.ResultStack.Peek(); + result.GetType().Should().Be(typeof(VM.Types.Array)); + ((VM.Types.Array)result).Count.Should().Be(7); + ((VM.Types.ByteArray)((VM.Types.Array)result)[0]).GetByteArray().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[1]).GetByteArray().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[2]).GetByteArray().ToHexString().Should().Be("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[3]).GetByteArray().ToHexString().Should().Be("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[4]).GetByteArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[5]).GetByteArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); + ((VM.Types.ByteArray)((VM.Types.Array)result)[6]).GetByteArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); + } + } + + [TestMethod] + public void TestGetValidators2() + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + var result = NativeContract.NEO.GetValidators(snapshot); + result[0].ToArray().ToHexString().Should().Be("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"); + result[1].ToArray().ToHexString().Should().Be("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093"); + result[2].ToArray().ToHexString().Should().Be("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a"); + result[3].ToArray().ToHexString().Should().Be("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554"); + result[4].ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); + result[5].ToArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); + result[6].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); + + StorageKey key = CreateStorageKey(15); + ValidatorsCountState state = new ValidatorsCountState(); + for (int i = 0; i < 100; i++) + { + state.Votes[i] = new BigInteger(i + 1); + } + snapshot.Storages.Add(key, new StorageItem() + { + Value = state.ToByteArray() + }); + NativeContract.NEO.GetValidators(snapshot).ToArray().Length.Should().Be(7); + } + + [TestMethod] + public void TestInitialize() + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + var engine = new ApplicationEngine(TriggerType.System, null, snapshot, 0, true); + Action action = () => NativeContract.NEO.Initialize(engine); + action.Should().Throw(); + + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + NativeContract.NEO.Initialize(engine).Should().BeFalse(); + + snapshot.Storages.Delete(CreateStorageKey(11)); + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + NativeContract.NEO.Initialize(engine).Should().BeTrue(); + } + + [TestMethod] + public void TestOnBalanceChanging() + { + var ret = Transfer4TesingOnBalanceChanging(new BigInteger(0), false); + ret.Result.Should().BeTrue(); + ret.State.Should().BeTrue(); + + ret = Transfer4TesingOnBalanceChanging(new BigInteger(1), false); + ret.Result.Should().BeTrue(); + ret.State.Should().BeTrue(); + + ret = Transfer4TesingOnBalanceChanging(new BigInteger(1), true); + ret.Result.Should().BeTrue(); + ret.State.Should().BeTrue(); + } + + [TestMethod] + public void TestTotalSupply() + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + NativeContract.NEO.TotalSupply(snapshot).Should().Be(new BigInteger(100000000)); + } + + [TestMethod] + public void TestUnclaimedGas() + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + snapshot.Storages.Add(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem + { + Value = new AccountState().ToByteArray() + }); + NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + } + + [TestMethod] + public void TestVote() + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + UInt160 account = UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4"); + StorageKey keyAccount = CreateStorageKey(20, account.ToArray()); + StorageKey keyValidator = CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()); + var ret = Check_Vote(snapshot, account.ToArray(), new byte[][] { ECCurve.Secp256r1.G.ToArray() }, false); + ret.State.Should().BeTrue(); + ret.Result.Should().BeFalse(); + + ret = Check_Vote(snapshot, account.ToArray(), new byte[][] { ECCurve.Secp256r1.G.ToArray() }, true); + ret.State.Should().BeTrue(); + ret.Result.Should().BeFalse(); + + snapshot.Storages.Add(keyAccount, new StorageItem + { + Value = new AccountState().ToByteArray() + }); + ret = Check_Vote(snapshot, account.ToArray(), new byte[][] { ECCurve.Secp256r1.G.ToArray() }, true); + ret.State.Should().BeTrue(); + ret.Result.Should().BeTrue(); + + snapshot.Storages.Delete(keyAccount); + snapshot.Storages.GetAndChange(keyAccount, () => new StorageItem + { + Value = new AccountState() + { + Votes = new ECPoint[] { ECCurve.Secp256r1.G } + }.ToByteArray() + }); + snapshot.Storages.Add(keyValidator, new StorageItem + { + Value = new ValidatorState().ToByteArray() + }); + ret = Check_Vote(snapshot, account.ToArray(), new byte[][] { ECCurve.Secp256r1.G.ToArray() }, true); + ret.State.Should().BeTrue(); + ret.Result.Should().BeTrue(); + } + + [TestMethod] + public void TestValidatorsCountState_FromByteArray() + { + ValidatorsCountState input = new ValidatorsCountState { Votes = new BigInteger[] { new BigInteger(1000) } }; + ValidatorsCountState output = ValidatorsCountState.FromByteArray(input.ToByteArray()); + output.Should().BeEquivalentTo(input); + } + + [TestMethod] + public void TestValidatorState_FromByteArray() + { + ValidatorState input = new ValidatorState { Votes = new BigInteger(1000) }; + ValidatorState output = ValidatorState.FromByteArray(input.ToByteArray()); + output.Should().BeEquivalentTo(input); + } + + [TestMethod] + public void TestValidatorState_ToByteArray() + { + ValidatorState input = new ValidatorState { Votes = new BigInteger(1000) }; + input.ToByteArray().ToHexString().Should().Be("e803"); + } + + internal (bool State, bool Result) Transfer4TesingOnBalanceChanging(BigInteger amount, bool addVotes) + { + Snapshot snapshot = Store.GetSnapshot().Clone(); + var engine = new ApplicationEngine(TriggerType.Application, Blockchain.GenesisBlock, snapshot, 0, true); + ScriptBuilder sb = new ScriptBuilder(); + var tmp = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot); + UInt160 from = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot)[0]; + if (addVotes) + { + snapshot.Storages.Add(CreateStorageKey(20, from.ToArray()), new StorageItem + { + Value = new AccountState() + { + Votes = new ECPoint[] { ECCurve.Secp256r1.G }, + Balance = new BigInteger(1000) + }.ToByteArray() + }); + snapshot.Storages.Add(NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G), new StorageItem + { + Value = new ValidatorState().ToByteArray() + }); + + ValidatorsCountState state = new ValidatorsCountState(); + for (int i = 0; i < 100; i++) + { + state.Votes[i] = new BigInteger(i + 1); + } + snapshot.Storages.Add(CreateStorageKey(15), new StorageItem() + { + Value = state.ToByteArray() + }); + } + else + { + snapshot.Storages.Add(CreateStorageKey(20, from.ToArray()), new StorageItem + { + Value = new AccountState() + { + Balance = new BigInteger(1000) + }.ToByteArray() + }); + } + + sb.EmitAppCall(NativeContract.NEO.Hash, "transfer", from, UInt160.Zero, amount); + engine.LoadScript(sb.ToArray()); + engine.Execute(); + var result = engine.ResultStack.Peek(); + result.GetType().Should().Be(typeof(VM.Types.Boolean)); + return (true, (result as VM.Types.Boolean).GetBoolean()); + } + internal static (bool State, bool Result) Check_Vote(Snapshot snapshot, byte[] account, byte[][] pubkeys, bool signAccount) { var engine = new ApplicationEngine(TriggerType.Application, @@ -370,5 +700,18 @@ internal static void CheckBalance(byte[] account, DataCache(); + var myDataCache = new TestDataCache(); + StorageItem item = new StorageItem + { + Value = new byte[] { 0x01 } + }; + var key = CreateStorageKey(Prefix_TotalSupply); + + var ServiceHash = "test".ToInteropMethodHash(); + byte[] script = null; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitSysCall(ServiceHash); + script = sb.ToArray(); + } + var Hash = script.ToScriptHash(); + key.ScriptHash = Hash; + + myDataCache.Add(key, item); + mockSnapshot.SetupGet(p => p.Storages).Returns(myDataCache); + TestNep5Token test = new TestNep5Token(); + ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + StackItem stackItem = test.TotalSupply(ae, null); + stackItem.GetBigInteger().Should().Be(1); + } + + [TestMethod] + public void TestTotalSupplyDecimal() + { + var mockSnapshot = new Mock(); + var myDataCache = new TestDataCache(); + + TestNep5Token test = new TestNep5Token(); + BigInteger totalSupply = 100_000_000; + totalSupply *= test.Factor; + + byte[] value = totalSupply.ToByteArray(); + StorageItem item = new StorageItem + { + Value = value + }; + var key = CreateStorageKey(Prefix_TotalSupply); + + var ServiceHash = "test".ToInteropMethodHash(); + byte[] script = null; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitSysCall(ServiceHash); + script = sb.ToArray(); + } + var Hash = script.ToScriptHash(); + key.ScriptHash = Hash; + + myDataCache.Add(key, item); + mockSnapshot.SetupGet(p => p.Storages).Returns(myDataCache); + + ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + StackItem stackItem = test.TotalSupply(ae, null); + stackItem.GetBigInteger().Should().Be(10_000_000_000_000_000); + } + + public StorageKey CreateStorageKey(byte prefix, byte[] key = null) + { + StorageKey storageKey = new StorageKey + { + ScriptHash = null, + Key = new byte[sizeof(byte) + (key?.Length ?? 0)] + }; + storageKey.Key[0] = prefix; + if (key != null) + Buffer.BlockCopy(key, 0, storageKey.Key, 1, key.Length); + return storageKey; + } + } + + public class TestNep5Token : Nep5Token + { + public override string Name => throw new NotImplementedException(); + + public override string Symbol => throw new NotImplementedException(); + + public override byte Decimals => 8; + + public override string ServiceName => "test"; + + public new StackItem TotalSupply(ApplicationEngine engine, VM.Types.Array args) + { + return base.TotalSupply(engine, args); + } + } +} diff --git a/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs new file mode 100644 index 0000000000..61e93de6ad --- /dev/null +++ b/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -0,0 +1,100 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.VM.Types; +using System; +using VMArray = Neo.VM.Types.Array; + +namespace Neo.UnitTests.SmartContract.Native +{ + [TestClass] + public class UT_NativeContract + { + Store Store; + + [TestInitialize] + public void TestSetup() + { + TestBlockchain.InitializeMockNeoSystem(); + Store = TestBlockchain.GetStore(); + } + + [TestMethod] + public void TestInitialize() + { + ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0); + TestNativeContract pc = new TestNativeContract(); + pc.Initialize(ae).Should().BeTrue(); + + ae = new ApplicationEngine(TriggerType.System, null, null, 0); + Action action = () => pc.Initialize(ae); + action.Should().Throw(); + } + + [TestMethod] + public void TestInvoke() + { + ApplicationEngine engine1 = new ApplicationEngine(TriggerType.Application, null, Store.GetSnapshot(), 0); + TestNativeContract testNativeContract = new TestNativeContract(); + + ScriptBuilder sb1 = new ScriptBuilder(); + + sb1.EmitSysCall("null".ToInteropMethodHash()); + engine1.LoadScript(sb1.ToArray()); + testNativeContract.Invoke(engine1).Should().BeFalse(); + + ApplicationEngine engine2 = new ApplicationEngine(TriggerType.Application, null, Store.GetSnapshot(), 0); + + ScriptBuilder sb2 = new ScriptBuilder(); + sb2.EmitSysCall("test".ToInteropMethodHash()); + engine2.LoadScript(sb2.ToArray()); + + ByteArray method1 = new ByteArray(System.Text.Encoding.Default.GetBytes("wrongMethod")); + VMArray args1 = new VMArray(); + engine2.CurrentContext.EvaluationStack.Push(args1); + engine2.CurrentContext.EvaluationStack.Push(method1); + testNativeContract.Invoke(engine2).Should().BeFalse(); + + ByteArray method2 = new ByteArray(System.Text.Encoding.Default.GetBytes("onPersist")); + VMArray args2 = new VMArray(); + engine2.CurrentContext.EvaluationStack.Push(args2); + engine2.CurrentContext.EvaluationStack.Push(method2); + testNativeContract.Invoke(engine2).Should().BeTrue(); + } + + [TestMethod] + public void TestOnPersistWithArgs() + { + ApplicationEngine engine1 = new ApplicationEngine(TriggerType.Application, null, Store.GetSnapshot(), 0); + TestNativeContract testNativeContract = new TestNativeContract(); + VMArray args = new VMArray(); + + VM.Types.Boolean result1 = new VM.Types.Boolean(false); + testNativeContract.TestOnPersist(engine1, args).Should().Be(result1); + + ApplicationEngine engine2 = new ApplicationEngine(TriggerType.System, null, Store.GetSnapshot(), 0); + VM.Types.Boolean result2 = new VM.Types.Boolean(true); + testNativeContract.TestOnPersist(engine2, args).Should().Be(result2); + } + + [TestMethod] + public void TestTestCall() + { + TestNativeContract testNativeContract = new TestNativeContract(); + ApplicationEngine engine = testNativeContract.TestCall("System.Blockchain.GetHeight", 0); + engine.ResultStack.Should().BeEmpty(); + } + } + + public class TestNativeContract : NativeContract + { + public override string ServiceName => "test"; + public StackItem TestOnPersist(ApplicationEngine engine, VMArray args) + { + return OnPersist(engine, args); + } + } +} diff --git a/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 940230660a..e0f87182a6 100644 --- a/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -1,5 +1,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; @@ -225,5 +227,28 @@ public void Check_Block_UnblockAccount() ret.Should().BeOfType(); ((VM.Types.Array)ret).Count.Should().Be(0); } + + [TestMethod] + public void TestCheckPolicy() + { + Transaction tx = Blockchain.GenesisBlock.Transactions[0]; + Snapshot snapshot = Store.GetSnapshot().Clone(); + + StorageKey storageKey = new StorageKey + { + ScriptHash = NativeContract.Policy.Hash, + Key = new byte[sizeof(byte)] + }; + storageKey.Key[0] = 15; + snapshot.Storages.Add(storageKey, new StorageItem + { + Value = new UInt160[] { tx.Sender }.ToByteArray(), + }); + + NativeContract.Policy.CheckPolicy(tx, snapshot).Should().BeFalse(); + + snapshot = Store.GetSnapshot().Clone(); + NativeContract.Policy.CheckPolicy(tx, snapshot).Should().BeTrue(); + } } } diff --git a/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs new file mode 100644 index 0000000000..fae3938a22 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -0,0 +1,185 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.IO; +using Neo.IO.Caching; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.UnitTests.Ledger; +using Neo.VM; +using System; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_ApplicationEngine + { + private string message = null; + private StackItem item = null; + private Store Store; + + [TestInitialize] + public void TestSetup() + { + TestBlockchain.InitializeMockNeoSystem(); + Store = TestBlockchain.GetStore(); + } + + [TestMethod] + public void TestLog() + { + var snapshot = Store.GetSnapshot().Clone(); + var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + ApplicationEngine.Log += Test_Log1; + string logMessage = "TestMessage"; + + engine.SendLog(UInt160.Zero, logMessage); + message.Should().Be(logMessage); + + ApplicationEngine.Log += Test_Log2; + engine.SendLog(UInt160.Zero, logMessage); + message.Should().Be(null); + + message = logMessage; + ApplicationEngine.Log -= Test_Log1; + engine.SendLog(UInt160.Zero, logMessage); + message.Should().Be(null); + + ApplicationEngine.Log -= Test_Log2; + engine.SendLog(UInt160.Zero, logMessage); + message.Should().Be(null); + } + + [TestMethod] + public void TestNotify() + { + var snapshot = Store.GetSnapshot().Clone(); + var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + ApplicationEngine.Notify += Test_Notify1; + StackItem notifyItem = "TestItem"; + + engine.SendNotification(UInt160.Zero, notifyItem); + item.Should().Be(notifyItem); + + ApplicationEngine.Notify += Test_Notify2; + engine.SendNotification(UInt160.Zero, notifyItem); + item.Should().Be(null); + + item = notifyItem; + ApplicationEngine.Notify -= Test_Notify1; + engine.SendNotification(UInt160.Zero, notifyItem); + item.Should().Be(null); + + ApplicationEngine.Notify -= Test_Notify2; + engine.SendNotification(UInt160.Zero, notifyItem); + item.Should().Be(null); + } + + [TestMethod] + public void TestDisposable() + { + var snapshot = Store.GetSnapshot().Clone(); + var replica = snapshot.Clone(); + var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine.AddDisposable(replica).Should().Be(replica); + Action action = () => engine.Dispose(); + action.Should().NotThrow(); + } + + private void Test_Log1(object sender, LogEventArgs e) + { + message = e.Message; + } + + private void Test_Log2(object sender, LogEventArgs e) + { + message = null; + } + + private void Test_Notify1(object sender, NotifyEventArgs e) + { + item = e.State; + } + + private void Test_Notify2(object sender, NotifyEventArgs e) + { + item = null; + } + + [TestMethod] + public void TestCreateDummyBlock() + { + var mockSnapshot = new Mock(); + UInt256 currentBlockHash = UInt256.Parse("0x0000000000000000000000000000000000000000000000000000000000000000"); + TrimmedBlock block = new TrimmedBlock(); + var cache = new TestDataCache(); + cache.Add(currentBlockHash, block); + mockSnapshot.SetupGet(p => p.Blocks).Returns(cache); + TestMetaDataCache testCache = new TestMetaDataCache(); + mockSnapshot.SetupGet(p => p.BlockHashIndex).Returns(testCache); + byte[] SyscallSystemRuntimeCheckWitnessHash = new byte[] { 0x68, 0xf8, 0x27, 0xec, 0x8c }; + ApplicationEngine.Run(SyscallSystemRuntimeCheckWitnessHash, mockSnapshot.Object); + mockSnapshot.Object.PersistingBlock.Version.Should().Be(0); + mockSnapshot.Object.PersistingBlock.PrevHash.Should().Be(currentBlockHash); + mockSnapshot.Object.PersistingBlock.MerkleRoot.Should().Be(new UInt256()); + } + + [TestMethod] + public void TestOnSysCall() + { + InteropDescriptor descriptor = new InteropDescriptor("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application); + TestApplicationEngine engine = new TestApplicationEngine(TriggerType.Application, null, null, 0); + byte[] SyscallSystemRuntimeCheckWitnessHash = new byte[] { 0x68, 0xf8, 0x27, 0xec, 0x8c }; + engine.LoadScript(SyscallSystemRuntimeCheckWitnessHash); + engine.GetOnSysCall(descriptor.Hash).Should().BeFalse(); + + var mockSnapshot = new Mock(); + TestMetaDataCache testCache = new TestMetaDataCache(); + mockSnapshot.SetupGet(p => p.BlockHashIndex).Returns(testCache); + engine = new TestApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0, true); + engine.LoadScript(SyscallSystemRuntimeCheckWitnessHash); + engine.GetOnSysCall(descriptor.Hash).Should().BeTrue(); + } + + private static bool Blockchain_GetHeight(ApplicationEngine engine) + { + engine.CurrentContext.EvaluationStack.Push(engine.Snapshot.Height); + return true; + } + } + + public class TestApplicationEngine : ApplicationEngine + { + public TestApplicationEngine(TriggerType trigger, IVerifiable container, Snapshot snapshot, long gas, bool testMode = false) : base(trigger, container, snapshot, gas, testMode) + { + } + + public bool GetOnSysCall(uint method) + { + return OnSysCall(method); + } + } + + public class TestMetaDataCache : MetaDataCache where T : class, ICloneable, ISerializable, new() + { + public TestMetaDataCache() + : base(null) + { + } + + protected override void AddInternal(T item) + { + } + + protected override T TryGetInternal() + { + return new T(); + } + + protected override void UpdateInternal(T item) + { + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_ContainerPlaceholder.cs b/neo.UnitTests/SmartContract/UT_ContainerPlaceholder.cs new file mode 100644 index 0000000000..e7ed55ac42 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_ContainerPlaceholder.cs @@ -0,0 +1,43 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract; +using Neo.VM.Types; +using System; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_ContainerPlaceholder + { + [TestMethod] + public void TestGenerator() + { + ContainerPlaceholder containerPlaceholder = new ContainerPlaceholder(); + Assert.IsNotNull(containerPlaceholder); + } + + [TestMethod] + public void TestEquals() + { + ContainerPlaceholder containerPlaceholder = new ContainerPlaceholder(); + Action action = () => containerPlaceholder.Equals(new Integer(0)); + action.Should().Throw(); + } + + [TestMethod] + public void TestGetBoolean() + { + ContainerPlaceholder containerPlaceholder = new ContainerPlaceholder(); + Action action = () => containerPlaceholder.GetBoolean(); + action.Should().Throw(); + } + + [TestMethod] + public void TestGetByteArray() + { + ContainerPlaceholder containerPlaceholder = new ContainerPlaceholder(); + Action action = () => containerPlaceholder.GetByteArray(); + action.Should().Throw(); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_Contract.cs b/neo.UnitTests/SmartContract/UT_Contract.cs new file mode 100644 index 0000000000..458128f569 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_Contract.cs @@ -0,0 +1,156 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract; +using Neo.Wallets; +using System; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_Contract + { + [TestMethod] + public void TestGetAddress() + { + byte[] privateKey = new byte[32]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes(privateKey); + KeyPair key = new KeyPair(privateKey); + Contract contract = Contract.CreateSignatureContract(key.PublicKey); + byte[] script = contract.Script; + byte[] expectedArray = new byte[39]; + expectedArray[0] = 0x21; + Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 1, 33); + expectedArray[34] = 0x68; + Array.Copy(BitConverter.GetBytes(InteropService.Neo_Crypto_CheckSig), 0, expectedArray, 35, 4); + Assert.AreEqual(expectedArray.ToScriptHash().ToAddress(), contract.Address); + } + + [TestMethod] + public void TestGetScriptHash() + { + byte[] privateKey = new byte[32]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes(privateKey); + KeyPair key = new KeyPair(privateKey); + Contract contract = Contract.CreateSignatureContract(key.PublicKey); + byte[] script = contract.Script; + byte[] expectedArray = new byte[39]; + expectedArray[0] = 0x21; + Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 1, 33); + expectedArray[34] = 0x68; + Array.Copy(BitConverter.GetBytes(InteropService.Neo_Crypto_CheckSig), 0, expectedArray, 35, 4); + Assert.AreEqual(expectedArray.ToScriptHash(), contract.ScriptHash); + } + + [TestMethod] + public void TestCreate() + { + byte[] script = new byte[32]; + ContractParameterType[] parameterList = new ContractParameterType[] { ContractParameterType.Signature }; + Contract contract = Contract.Create(parameterList, script); + Assert.AreEqual(contract.Script, script); + Assert.AreEqual(1, contract.ParameterList.Length); + Assert.AreEqual(ContractParameterType.Signature, contract.ParameterList[0]); + } + + [TestMethod] + public void TestCreateMultiSigContract() + { + byte[] privateKey1 = new byte[32]; + RandomNumberGenerator rng1 = RandomNumberGenerator.Create(); + rng1.GetBytes(privateKey1); + KeyPair key1 = new KeyPair(privateKey1); + byte[] privateKey2 = new byte[32]; + RandomNumberGenerator rng2 = RandomNumberGenerator.Create(); + rng2.GetBytes(privateKey2); + KeyPair key2 = new KeyPair(privateKey2); + Neo.Cryptography.ECC.ECPoint[] publicKeys = new Neo.Cryptography.ECC.ECPoint[2]; + publicKeys[0] = key1.PublicKey; + publicKeys[1] = key2.PublicKey; + publicKeys = publicKeys.OrderBy(p => p).ToArray(); + Contract contract = Contract.CreateMultiSigContract(2, publicKeys); + byte[] expectedArray = new byte[75]; + expectedArray[0] = 0x52; + expectedArray[1] = 0x21; + Array.Copy(publicKeys[0].EncodePoint(true), 0, expectedArray, 2, 33); + expectedArray[35] = 0x21; + Array.Copy(publicKeys[1].EncodePoint(true), 0, expectedArray, 36, 33); + expectedArray[69] = 0x52; + expectedArray[70] = 0x68; + Array.Copy(BitConverter.GetBytes(InteropService.Neo_Crypto_CheckMultiSig), 0, expectedArray, 71, 4); + Assert.AreEqual(Encoding.Default.GetString(expectedArray), Encoding.Default.GetString(contract.Script)); + Assert.AreEqual(2, contract.ParameterList.Length); + Assert.AreEqual(ContractParameterType.Signature, contract.ParameterList[0]); + Assert.AreEqual(ContractParameterType.Signature, contract.ParameterList[1]); + } + + [TestMethod] + public void TestCreateMultiSigRedeemScript() + { + byte[] privateKey1 = new byte[32]; + RandomNumberGenerator rng1 = RandomNumberGenerator.Create(); + rng1.GetBytes(privateKey1); + KeyPair key1 = new KeyPair(privateKey1); + byte[] privateKey2 = new byte[32]; + RandomNumberGenerator rng2 = RandomNumberGenerator.Create(); + rng2.GetBytes(privateKey2); + KeyPair key2 = new KeyPair(privateKey2); + Neo.Cryptography.ECC.ECPoint[] publicKeys = new Neo.Cryptography.ECC.ECPoint[2]; + publicKeys[0] = key1.PublicKey; + publicKeys[1] = key2.PublicKey; + publicKeys = publicKeys.OrderBy(p => p).ToArray(); + Action action = () => Contract.CreateMultiSigRedeemScript(0, publicKeys); + action.Should().Throw(); + byte[] script = Contract.CreateMultiSigRedeemScript(2, publicKeys); + byte[] expectedArray = new byte[75]; + expectedArray[0] = 0x52; + expectedArray[1] = 0x21; + Array.Copy(publicKeys[0].EncodePoint(true), 0, expectedArray, 2, 33); + expectedArray[35] = 0x21; + Array.Copy(publicKeys[1].EncodePoint(true), 0, expectedArray, 36, 33); + expectedArray[69] = 0x52; + expectedArray[70] = 0x68; + Array.Copy(BitConverter.GetBytes(InteropService.Neo_Crypto_CheckMultiSig), 0, expectedArray, 71, 4); + Assert.AreEqual(Encoding.Default.GetString(expectedArray), Encoding.Default.GetString(script)); + } + + [TestMethod] + public void TestCreateSignatureContract() + { + byte[] privateKey = new byte[32]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes(privateKey); + KeyPair key = new KeyPair(privateKey); + Contract contract = Contract.CreateSignatureContract(key.PublicKey); + byte[] script = contract.Script; + byte[] expectedArray = new byte[39]; + expectedArray[0] = 0x21; + Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 1, 33); + expectedArray[34] = 0x68; + Array.Copy(BitConverter.GetBytes(InteropService.Neo_Crypto_CheckSig), 0, expectedArray, 35, 4); + Assert.AreEqual(Encoding.Default.GetString(expectedArray), Encoding.Default.GetString(script)); + Assert.AreEqual(1, contract.ParameterList.Length); + Assert.AreEqual(ContractParameterType.Signature, contract.ParameterList[0]); + } + + [TestMethod] + public void TestCreateSignatureRedeemScript() + { + byte[] privateKey = new byte[32]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes(privateKey); + KeyPair key = new KeyPair(privateKey); + byte[] script = Contract.CreateSignatureRedeemScript(key.PublicKey); + byte[] expectedArray = new byte[39]; + expectedArray[0] = 0x21; + Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 1, 33); + expectedArray[34] = 0x68; + Array.Copy(BitConverter.GetBytes(InteropService.Neo_Crypto_CheckSig), 0, expectedArray, 35, 4); + Assert.AreEqual(Encoding.Default.GetString(expectedArray), Encoding.Default.GetString(script)); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_ContractParameter.cs b/neo.UnitTests/SmartContract/UT_ContractParameter.cs new file mode 100644 index 0000000000..124f852e5e --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_ContractParameter.cs @@ -0,0 +1,201 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography.ECC; +using Neo.IO.Json; +using Neo.SmartContract; +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Text; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_ContractParameter + { + [TestMethod] + public void TestGenerator1() + { + ContractParameter contractParameter = new ContractParameter(); + Assert.IsNotNull(contractParameter); + } + + [TestMethod] + public void TestGenerator2() + { + ContractParameter contractParameter1 = new ContractParameter(ContractParameterType.Signature); + byte[] expectedArray1 = new byte[64]; + Assert.IsNotNull(contractParameter1); + Assert.AreEqual(Encoding.Default.GetString(expectedArray1), Encoding.Default.GetString((byte[])contractParameter1.Value)); + + ContractParameter contractParameter2 = new ContractParameter(ContractParameterType.Boolean); + Assert.IsNotNull(contractParameter2); + Assert.AreEqual(false, contractParameter2.Value); + + ContractParameter contractParameter3 = new ContractParameter(ContractParameterType.Integer); + Assert.IsNotNull(contractParameter3); + Assert.AreEqual(0, contractParameter3.Value); + + ContractParameter contractParameter4 = new ContractParameter(ContractParameterType.Hash160); + Assert.IsNotNull(contractParameter4); + Assert.AreEqual(new UInt160(), contractParameter4.Value); + + ContractParameter contractParameter5 = new ContractParameter(ContractParameterType.Hash256); + Assert.IsNotNull(contractParameter5); + Assert.AreEqual(new UInt256(), contractParameter5.Value); + + ContractParameter contractParameter6 = new ContractParameter(ContractParameterType.ByteArray); + byte[] expectedArray6 = new byte[0]; + Assert.IsNotNull(contractParameter6); + Assert.AreEqual(Encoding.Default.GetString(expectedArray6), Encoding.Default.GetString((byte[])contractParameter6.Value)); + + ContractParameter contractParameter7 = new ContractParameter(ContractParameterType.PublicKey); + Assert.IsNotNull(contractParameter7); + Assert.AreEqual(ECCurve.Secp256r1.G, contractParameter7.Value); + + ContractParameter contractParameter8 = new ContractParameter(ContractParameterType.String); + Assert.IsNotNull(contractParameter8); + Assert.AreEqual("", contractParameter8.Value); + + ContractParameter contractParameter9 = new ContractParameter(ContractParameterType.Array); + Assert.IsNotNull(contractParameter9); + Assert.AreEqual(0, ((List)contractParameter9.Value).Count); + + ContractParameter contractParameter10 = new ContractParameter(ContractParameterType.Map); + Assert.IsNotNull(contractParameter10); + Assert.AreEqual(0, ((List>)contractParameter10.Value).Count); + + Action action = () => new ContractParameter(ContractParameterType.Void); + action.Should().Throw(); + } + + [TestMethod] + public void TestFromAndToJson() + { + ContractParameter contractParameter1 = new ContractParameter(ContractParameterType.Signature); + JObject jobject1 = contractParameter1.ToJson(); + Assert.AreEqual(jobject1.ToString(), ContractParameter.FromJson(jobject1).ToJson().ToString()); + + ContractParameter contractParameter2 = new ContractParameter(ContractParameterType.Boolean); + JObject jobject2 = contractParameter2.ToJson(); + Assert.AreEqual(jobject2.ToString(), ContractParameter.FromJson(jobject2).ToJson().ToString()); + + ContractParameter contractParameter3 = new ContractParameter(ContractParameterType.Integer); + JObject jobject3 = contractParameter3.ToJson(); + Assert.AreEqual(jobject3.ToString(), ContractParameter.FromJson(jobject3).ToJson().ToString()); + + ContractParameter contractParameter4 = new ContractParameter(ContractParameterType.Hash160); + JObject jobject4 = contractParameter4.ToJson(); + Assert.AreEqual(jobject4.ToString(), ContractParameter.FromJson(jobject4).ToJson().ToString()); + + ContractParameter contractParameter5 = new ContractParameter(ContractParameterType.Hash256); + JObject jobject5 = contractParameter5.ToJson(); + Assert.AreEqual(jobject5.ToString(), ContractParameter.FromJson(jobject5).ToJson().ToString()); + + ContractParameter contractParameter6 = new ContractParameter(ContractParameterType.ByteArray); + JObject jobject6 = contractParameter6.ToJson(); + Assert.AreEqual(jobject6.ToString(), ContractParameter.FromJson(jobject6).ToJson().ToString()); + + ContractParameter contractParameter7 = new ContractParameter(ContractParameterType.PublicKey); + JObject jobject7 = contractParameter7.ToJson(); + Assert.AreEqual(jobject7.ToString(), ContractParameter.FromJson(jobject7).ToJson().ToString()); + + ContractParameter contractParameter8 = new ContractParameter(ContractParameterType.String); + JObject jobject8 = contractParameter8.ToJson(); + Assert.AreEqual(jobject8.ToString(), ContractParameter.FromJson(jobject8).ToJson().ToString()); + + ContractParameter contractParameter9 = new ContractParameter(ContractParameterType.Array); + JObject jobject9 = contractParameter9.ToJson(); + Assert.AreEqual(jobject9.ToString(), ContractParameter.FromJson(jobject9).ToJson().ToString()); + + ContractParameter contractParameter10 = new ContractParameter(ContractParameterType.Map); + JObject jobject10 = contractParameter10.ToJson(); + Assert.AreEqual(jobject10.ToString(), ContractParameter.FromJson(jobject10).ToJson().ToString()); + + ContractParameter contractParameter11 = new ContractParameter(ContractParameterType.String); + JObject jobject11 = contractParameter11.ToJson(); + jobject11["type"] = "Void"; + Action action = () => ContractParameter.FromJson(jobject11); + action.Should().Throw(); + } + + [TestMethod] + public void TestSetValue() + { + ContractParameter contractParameter1 = new ContractParameter(ContractParameterType.Signature); + byte[] expectedArray1 = new byte[64]; + contractParameter1.SetValue(new byte[64].ToHexString()); + Assert.AreEqual(Encoding.Default.GetString(expectedArray1), Encoding.Default.GetString((byte[])contractParameter1.Value)); + Action action1 = () => contractParameter1.SetValue(new byte[50].ToHexString()); + action1.Should().Throw(); + + ContractParameter contractParameter2 = new ContractParameter(ContractParameterType.Boolean); + contractParameter2.SetValue("true"); + Assert.AreEqual(true, contractParameter2.Value); + + ContractParameter contractParameter3 = new ContractParameter(ContractParameterType.Integer); + contractParameter3.SetValue("11"); + Assert.AreEqual(new BigInteger(11), contractParameter3.Value); + + ContractParameter contractParameter4 = new ContractParameter(ContractParameterType.Hash160); + contractParameter4.SetValue("0x0000000000000000000000000000000000000001"); + Assert.AreEqual(UInt160.Parse("0x0000000000000000000000000000000000000001"), contractParameter4.Value); + + ContractParameter contractParameter5 = new ContractParameter(ContractParameterType.Hash256); + contractParameter5.SetValue("0x0000000000000000000000000000000000000000000000000000000000000000"); + Assert.AreEqual(UInt256.Parse("0x0000000000000000000000000000000000000000000000000000000000000000"), contractParameter5.Value); + + ContractParameter contractParameter6 = new ContractParameter(ContractParameterType.ByteArray); + contractParameter6.SetValue("2222"); + byte[] expectedArray6 = new byte[2]; + expectedArray6[0] = 0x22; + expectedArray6[1] = 0x22; + Assert.AreEqual(Encoding.Default.GetString(expectedArray6), Encoding.Default.GetString((byte[])contractParameter6.Value)); + + ContractParameter contractParameter7 = new ContractParameter(ContractParameterType.PublicKey); + Random random7 = new Random(); + byte[] privateKey7 = new byte[32]; + for (int j = 0; j < privateKey7.Length; j++) + privateKey7[j] = (byte)random7.Next(256); + ECPoint publicKey7 = ECCurve.Secp256r1.G * privateKey7; + contractParameter7.SetValue(publicKey7.ToString()); + Assert.AreEqual(true, publicKey7.Equals(contractParameter7.Value)); + + ContractParameter contractParameter8 = new ContractParameter(ContractParameterType.String); + contractParameter8.SetValue("AAA"); + Assert.AreEqual("AAA", contractParameter8.Value); + + ContractParameter contractParameter9 = new ContractParameter(ContractParameterType.Array); + Action action9 = () => contractParameter9.SetValue("AAA"); + action9.Should().Throw(); + } + + [TestMethod] + public void TestToString() + { + ContractParameter contractParameter1 = new ContractParameter(); + Assert.AreEqual("(null)", contractParameter1.ToString()); + + ContractParameter contractParameter2 = new ContractParameter(ContractParameterType.ByteArray); + contractParameter2.Value = new byte[1]; + Assert.AreEqual("00", contractParameter2.ToString()); + + ContractParameter contractParameter3 = new ContractParameter(ContractParameterType.Array); + Assert.AreEqual("[]", contractParameter3.ToString()); + ContractParameter internalContractParameter3 = new ContractParameter(ContractParameterType.Boolean); + ((IList)contractParameter3.Value).Add(internalContractParameter3); + Assert.AreEqual("[False]", contractParameter3.ToString()); + + ContractParameter contractParameter4 = new ContractParameter(ContractParameterType.Map); + Assert.AreEqual("[]", contractParameter4.ToString()); + ContractParameter internalContractParameter4 = new ContractParameter(ContractParameterType.Boolean); + ((IList>)contractParameter4.Value).Add(new KeyValuePair( + internalContractParameter4, internalContractParameter4 + )); + Assert.AreEqual("[{False,False}]", contractParameter4.ToString()); + + ContractParameter contractParameter5 = new ContractParameter(ContractParameterType.String); + Assert.AreEqual("", contractParameter5.ToString()); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs new file mode 100644 index 0000000000..0b06260b24 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -0,0 +1,161 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography.ECC; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.Wallets; +using System; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_ContractParameterContext + { + private static Contract contract; + private static KeyPair key; + + [ClassInitialize] + public static void ClassSetUp(TestContext context) + { + if (contract == null) + { + byte[] privateKey = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; + key = new KeyPair(privateKey); + contract = Contract.CreateSignatureContract(key.PublicKey); + } + TestBlockchain.InitializeMockNeoSystem(); + } + + [TestMethod] + public void TestGetComplete() + { + Transaction tx = TestUtils.GetTransaction(); + tx.Sender = UInt160.Parse("0xbecaad15c0ea585211faf99738a4354014f177f2"); + var context = new ContractParametersContext(tx); + context.Completed.Should().BeFalse(); + } + + [TestMethod] + public void TestToString() + { + Transaction tx = TestUtils.GetTransaction(); + tx.Sender = UInt160.Parse("0xbecaad15c0ea585211faf99738a4354014f177f2"); + var context = new ContractParametersContext(tx); + context.Add(contract, 0, new byte[] { 0x01 }); + string str = context.ToString(); + str.Should().Be("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"hex\":\"0000000000f277f1144035a43897f9fa115258eac015adcabe000000000000000000000000000000000000000000000100\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"21026ff03b949241ce1dadd43519e6960e0a85b41a69a05c328103aa2bce1594ca1668747476aa\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"01\"}]}}}"); + } + + [TestMethod] + public void TestParse() + { + var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"hex\":\"0000000000f277f1144035a43897f9fa115258eac015adcabe000000000000000000000000000000000000000000000100\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"21026ff03b949241ce1dadd43519e6960e0a85b41a69a05c328103aa2bce1594ca1668747476aa\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"01\"}]}}}"); + ret.ScriptHashes[0].ToString().Should().Be("0xbecaad15c0ea585211faf99738a4354014f177f2"); + ((Transaction)ret.Verifiable).Script.ToHexString().Should().Be(new byte[1].ToHexString()); + } + + [TestMethod] + public void TestFromJson() + { + Action action = () => ContractParametersContext.Parse("{\"type\":\"wrongType\",\"hex\":\"0000000000f277f1144035a43897f9fa115258eac015adcabe0000000000000000000000000000000000000000000100\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"21026ff03b949241ce1dadd43519e6960e0a85b41a69a05c328103aa2bce1594ca1668747476aa\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"01\"}]}}}"); + action.Should().Throw(); + } + + [TestMethod] + public void TestAdd() + { + Transaction tx = TestUtils.GetTransaction(); + var context1 = new ContractParametersContext(tx); + context1.Add(contract, 0, new byte[] { 0x01 }).Should().BeFalse(); + + tx.Sender = UInt160.Parse("0xbecaad15c0ea585211faf99738a4354014f177f2"); + var context2 = new ContractParametersContext(tx); + context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); + //test repeatlly createItem + context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); + } + + [TestMethod] + public void TestGetParameter() + { + Transaction tx = TestUtils.GetTransaction(); + tx.Sender = UInt160.Parse("0xbecaad15c0ea585211faf99738a4354014f177f2"); + var context = new ContractParametersContext(tx); + context.GetParameter(tx.Sender, 0).Should().BeNull(); + + context.Add(contract, 0, new byte[] { 0x01 }); + var ret = context.GetParameter(tx.Sender, 0); + ((byte[])ret.Value).ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); + } + + [TestMethod] + public void TestGetWitnesses() + { + Transaction tx = TestUtils.GetTransaction(); + tx.Sender = UInt160.Parse("0xbecaad15c0ea585211faf99738a4354014f177f2"); + var context = new ContractParametersContext(tx); + context.Add(contract, 0, new byte[] { 0x01 }); + Witness[] witnesses = context.GetWitnesses(); + witnesses.Length.Should().Be(1); + witnesses[0].InvocationScript.ToHexString().Should().Be(new byte[] { 0x01, 0x01 }.ToHexString()); + witnesses[0].VerificationScript.ToHexString().Should().Be(contract.Script.ToHexString()); + } + + [TestMethod] + public void TestAddSignature() + { + Transaction tx = TestUtils.GetTransaction(); + var singleSender = UInt160.Parse("0xbecaad15c0ea585211faf99738a4354014f177f2"); + tx.Sender = singleSender; + + //singleSign + + var context = new ContractParametersContext(tx); + context.AddSignature(contract, key.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); + + var contract1 = Contract.CreateSignatureContract(key.PublicKey); + contract1.ParameterList = new ContractParameterType[0]; + context = new ContractParametersContext(tx); + context.AddSignature(contract1, key.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); + + contract1.ParameterList = new[] { ContractParameterType.Signature, ContractParameterType.Signature }; + Action action1 = () => context.AddSignature(contract1, key.PublicKey, new byte[] { 0x01 }); + action1.Should().Throw(); + + //multiSign + + byte[] privateKey2 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02 }; + var key2 = new KeyPair(privateKey2); + var multiSignContract = Contract.CreateMultiSigContract(2, + new ECPoint[] + { + key.PublicKey, + key2.PublicKey + }); + var multiSender = UInt160.Parse("0xa4712ed1a8d813561b28ec828930d85e6e08ec7a"); + tx.Sender = multiSender; + context = new ContractParametersContext(tx); + context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); + context.AddSignature(multiSignContract, key2.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); + + tx.Sender = singleSender; + context = new ContractParametersContext(tx); + context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); + + tx.Sender = multiSender; + context = new ContractParametersContext(tx); + byte[] privateKey3 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03 }; + var key3 = new KeyPair(privateKey3); + context.AddSignature(multiSignContract, key3.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_InteropDescriptor.cs b/neo.UnitTests/SmartContract/UT_InteropDescriptor.cs new file mode 100644 index 0000000000..fcccab5dc7 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_InteropDescriptor.cs @@ -0,0 +1,27 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract; +using System; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_InteropDescriptor + { + [TestMethod] + public void TestGetMethod() + { + string method = @"System.ExecutionEngine.GetScriptContainer"; + long price = 0_00000250; + TriggerType allowedTriggers = TriggerType.All; + InteropDescriptor descriptor = new InteropDescriptor(method, TestHandler, price, allowedTriggers); + descriptor.Method.Should().Be(method); + descriptor.Price.Should().Be(price); + } + + private bool TestHandler(ApplicationEngine engine) + { + return true; + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs new file mode 100644 index 0000000000..885f3d3498 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -0,0 +1,479 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.Cryptography; +using Neo.Cryptography.ECC; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Enumerators; +using Neo.SmartContract.Iterators; +using Neo.SmartContract.Manifest; +using Neo.VM.Types; +using Neo.Wallets; +using System.Linq; +using VMArray = Neo.VM.Types.Array; + +namespace Neo.UnitTests.SmartContract +{ + public partial class UT_InteropService + { + [TestMethod] + public void TestCheckSig() + { + var engine = GetEngine(true); + IVerifiable iv = engine.ScriptContainer; + byte[] message = iv.GetHashData(); + byte[] privateKey = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + KeyPair keyPair = new KeyPair(privateKey); + ECPoint pubkey = keyPair.PublicKey; + byte[] signature = Crypto.Default.Sign(message, privateKey, pubkey.EncodePoint(false).Skip(1).ToArray()); + engine.CurrentContext.EvaluationStack.Push(signature); + engine.CurrentContext.EvaluationStack.Push(pubkey.EncodePoint(false)); + InteropService.Invoke(engine, InteropService.Neo_Crypto_CheckSig).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeTrue(); + + engine.CurrentContext.EvaluationStack.Push(signature); + engine.CurrentContext.EvaluationStack.Push(new byte[70]); + InteropService.Invoke(engine, InteropService.Neo_Crypto_CheckSig).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeFalse(); + } + + [TestMethod] + public void TestCrypto_CheckMultiSig() + { + var engine = GetEngine(true); + IVerifiable iv = engine.ScriptContainer; + byte[] message = iv.GetHashData(); + + byte[] privkey1 = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + KeyPair key1 = new KeyPair(privkey1); + ECPoint pubkey1 = key1.PublicKey; + byte[] signature1 = Crypto.Default.Sign(message, privkey1, pubkey1.EncodePoint(false).Skip(1).ToArray()); + + byte[] privkey2 = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02}; + KeyPair key2 = new KeyPair(privkey2); + ECPoint pubkey2 = key2.PublicKey; + byte[] signature2 = Crypto.Default.Sign(message, privkey2, pubkey2.EncodePoint(false).Skip(1).ToArray()); + + var pubkeys = new VMArray + { + pubkey1.EncodePoint(false), + pubkey2.EncodePoint(false) + }; + var signatures = new VMArray + { + signature1, + signature2 + }; + engine.CurrentContext.EvaluationStack.Push(signatures); + engine.CurrentContext.EvaluationStack.Push(pubkeys); + InteropService.Invoke(engine, InteropService.Neo_Crypto_CheckMultiSig).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeTrue(); + + pubkeys = new VMArray(); + engine.CurrentContext.EvaluationStack.Push(signatures); + engine.CurrentContext.EvaluationStack.Push(pubkeys); + InteropService.Invoke(engine, InteropService.Neo_Crypto_CheckMultiSig).Should().BeFalse(); + + pubkeys = new VMArray + { + pubkey1.EncodePoint(false), + pubkey2.EncodePoint(false) + }; + signatures = new VMArray(); + engine.CurrentContext.EvaluationStack.Push(signatures); + engine.CurrentContext.EvaluationStack.Push(pubkeys); + InteropService.Invoke(engine, InteropService.Neo_Crypto_CheckMultiSig).Should().BeFalse(); + + pubkeys = new VMArray + { + pubkey1.EncodePoint(false), + pubkey2.EncodePoint(false) + }; + signatures = new VMArray + { + signature1, + new byte[64] + }; + engine.CurrentContext.EvaluationStack.Push(signatures); + engine.CurrentContext.EvaluationStack.Push(pubkeys); + InteropService.Invoke(engine, InteropService.Neo_Crypto_CheckMultiSig).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeFalse(); + + pubkeys = new VMArray + { + pubkey1.EncodePoint(false), + new byte[70] + }; + signatures = new VMArray + { + signature1, + signature2 + }; + engine.CurrentContext.EvaluationStack.Push(signatures); + engine.CurrentContext.EvaluationStack.Push(pubkeys); + InteropService.Invoke(engine, InteropService.Neo_Crypto_CheckMultiSig).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeFalse(); + } + + [TestMethod] + public void TestAccount_IsStandard() + { + var engine = GetEngine(false, true); + var hash = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01 }; + engine.CurrentContext.EvaluationStack.Push(hash); + InteropService.Invoke(engine, InteropService.Neo_Account_IsStandard).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeTrue(); + + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); + InteropService.Invoke(engine, InteropService.Neo_Account_IsStandard).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeFalse(); + } + + [TestMethod] + public void TestContract_Create() + { + var engine = GetEngine(false, true); + var script = new byte[1024 * 1024 + 1]; + engine.CurrentContext.EvaluationStack.Push(script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Create).Should().BeFalse(); + + string manifestStr = new string(new char[ContractManifest.MaxLength + 1]); + script = new byte[] { 0x01 }; + engine.CurrentContext.EvaluationStack.Push(manifestStr); + engine.CurrentContext.EvaluationStack.Push(script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Create).Should().BeFalse(); + + var manifest = ContractManifest.CreateDefault(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01")); + engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); + engine.CurrentContext.EvaluationStack.Push(script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Create).Should().BeFalse(); + + manifest.Abi.Hash = script.ToScriptHash(); + engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); + engine.CurrentContext.EvaluationStack.Push(script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Create).Should().BeTrue(); + + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); + engine.CurrentContext.EvaluationStack.Push(state.Script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Create).Should().BeFalse(); + } + + [TestMethod] + public void TestContract_Update() + { + var engine = GetEngine(false, true); + var script = new byte[1024 * 1024 + 1]; + engine.CurrentContext.EvaluationStack.Push(script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Update).Should().BeFalse(); + + string manifestStr = new string(new char[ContractManifest.MaxLength + 1]); + script = new byte[] { 0x01 }; + engine.CurrentContext.EvaluationStack.Push(manifestStr); + engine.CurrentContext.EvaluationStack.Push(script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Update).Should().BeFalse(); + + manifestStr = ""; + engine.CurrentContext.EvaluationStack.Push(manifestStr); + engine.CurrentContext.EvaluationStack.Push(script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Update).Should().BeFalse(); + + var manifest = ContractManifest.CreateDefault(script.ToScriptHash()); + byte[] privkey = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + KeyPair key = new KeyPair(privkey); + ECPoint pubkey = key.PublicKey; + byte[] signature = Crypto.Default.Sign(script.ToScriptHash().ToArray(), privkey, pubkey.EncodePoint(false).Skip(1).ToArray()); + manifest.Groups = new ContractGroup[] + { + new ContractGroup() + { + PubKey = pubkey, + Signature = signature + } + }; + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + var storageItem = new StorageItem + { + Value = new byte[] { 0x01 }, + IsConstant = false + }; + + var storageKey = new StorageKey + { + ScriptHash = state.ScriptHash, + Key = new byte[] { 0x01 } + }; + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(state.Script); + engine.CurrentContext.EvaluationStack.Push(manifest.ToString()); + engine.CurrentContext.EvaluationStack.Push(script); + InteropService.Invoke(engine, InteropService.Neo_Contract_Update).Should().BeTrue(); + } + + [TestMethod] + public void TestStorage_Find() + { + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + + var storageItem = new StorageItem + { + Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, + IsConstant = true + }; + var storageKey = new StorageKey + { + ScriptHash = state.ScriptHash, + Key = new byte[] { 0x01 } + }; + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); + var engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + + engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext + { + ScriptHash = state.ScriptHash, + IsReadOnly = false + })); + InteropService.Invoke(engine, InteropService.Neo_Storage_Find).Should().BeTrue(); + var iterator = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + iterator.Next(); + var ele = iterator.Value(); + ele.GetByteArray().ToHexString().Should().Be(storageItem.Value.ToHexString()); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Storage_Find).Should().BeFalse(); + } + + [TestMethod] + public void TestEnumerator_Create() + { + var engine = GetEngine(); + var arr = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + engine.CurrentContext.EvaluationStack.Push(arr); + InteropService.Invoke(engine, InteropService.Neo_Enumerator_Create).Should().BeTrue(); + var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); + ret.GetInterface().Next(); + ret.GetInterface().Value().GetByteArray().ToHexString() + .Should().Be(new byte[] { 0x01 }.ToHexString()); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Enumerator_Create).Should().BeFalse(); + } + + [TestMethod] + public void TestEnumerator_Next() + { + var engine = GetEngine(); + var arr = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new ArrayWrapper(arr))); + InteropService.Invoke(engine, InteropService.Neo_Enumerator_Next).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeTrue(); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Enumerator_Next).Should().BeFalse(); + } + + [TestMethod] + public void TestEnumerator_Value() + { + var engine = GetEngine(); + var arr = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + var wrapper = new ArrayWrapper(arr); + wrapper.Next(); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper)); + InteropService.Invoke(engine, InteropService.Neo_Enumerator_Value).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Enumerator_Value).Should().BeFalse(); + } + + [TestMethod] + public void TestEnumerator_Concat() + { + var engine = GetEngine(); + var arr1 = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + var arr2 = new VMArray { + new byte[]{ 0x03 }, + new byte[]{ 0x04 } + }; + var wrapper1 = new ArrayWrapper(arr1); + var wrapper2 = new ArrayWrapper(arr2); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper2)); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper1)); + InteropService.Invoke(engine, InteropService.Neo_Enumerator_Concat).Should().BeTrue(); + var ret = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + ret.Next().Should().BeTrue(); + ret.Value().GetByteArray().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); + } + + [TestMethod] + public void TestIterator_Create() + { + var engine = GetEngine(); + var arr = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + engine.CurrentContext.EvaluationStack.Push(arr); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Create).Should().BeTrue(); + var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); + ret.GetInterface().Next(); + ret.GetInterface().Value().GetByteArray().ToHexString() + .Should().Be(new byte[] { 0x01 }.ToHexString()); + + var map = new Map + { + { new Integer(1), new Integer(2) }, + { new Integer(3), new Integer(4) } + }; + engine.CurrentContext.EvaluationStack.Push(map); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Create).Should().BeTrue(); + ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); + ret.GetInterface().Next(); + ret.GetInterface().Key().GetBigInteger().Should().Be(1); + ret.GetInterface().Value().GetBigInteger().Should().Be(2); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Create).Should().BeFalse(); + } + + [TestMethod] + public void TestIterator_Key() + { + var engine = GetEngine(); + var arr = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + var wrapper = new ArrayWrapper(arr); + wrapper.Next(); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper)); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Key).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(0); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Key).Should().BeFalse(); + } + + [TestMethod] + public void TestIterator_Keys() + { + var engine = GetEngine(); + var arr = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + var wrapper = new ArrayWrapper(arr); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper)); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Keys).Should().BeTrue(); + var ret = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + ret.Next(); + ret.Value().GetBigInteger().Should().Be(0); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Keys).Should().BeFalse(); + } + + [TestMethod] + public void TestIterator_Values() + { + var engine = GetEngine(); + var arr = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + var wrapper = new ArrayWrapper(arr); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper)); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Values).Should().BeTrue(); + var ret = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + ret.Next(); + ret.Value().GetByteArray().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Values).Should().BeFalse(); + } + + [TestMethod] + public void TestIterator_Concat() + { + var engine = GetEngine(); + var arr1 = new VMArray { + new byte[]{ 0x01 }, + new byte[]{ 0x02 } + }; + var arr2 = new VMArray { + new byte[]{ 0x03 }, + new byte[]{ 0x04 } + }; + var wrapper1 = new ArrayWrapper(arr1); + var wrapper2 = new ArrayWrapper(arr2); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper2)); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(wrapper1)); + InteropService.Invoke(engine, InteropService.Neo_Iterator_Concat).Should().BeTrue(); + var ret = ((InteropInterface)engine.CurrentContext.EvaluationStack.Pop()).GetInterface(); + ret.Next().Should().BeTrue(); + ret.Value().GetByteArray().ToHexString().Should().Be(new byte[] { 0x01 }.ToHexString()); + } + + [TestMethod] + public void TestJson_Deserialize() + { + var engine = GetEngine(); + engine.CurrentContext.EvaluationStack.Push("1"); + InteropService.Invoke(engine, InteropService.Neo_Json_Deserialize).Should().BeTrue(); + var ret = engine.CurrentContext.EvaluationStack.Pop(); + ret.GetBigInteger().Should().Be(1); + } + + [TestMethod] + public void TestJson_Serialize() + { + var engine = GetEngine(); + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.Neo_Json_Serialize).Should().BeTrue(); + var ret = engine.CurrentContext.EvaluationStack.Pop(); + ret.GetString().Should().Be("1"); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_InteropService.cs b/neo.UnitTests/SmartContract/UT_InteropService.cs index dff17f2025..fe28f1503d 100644 --- a/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -1,12 +1,25 @@ +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.Cryptography; +using Neo.Cryptography.ECC; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Manifest; using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Linq; +using System.Text; namespace Neo.UnitTests.SmartContract { [TestClass] - public class UT_InteropService + public partial class UT_InteropService { [TestInitialize] public void TestSetup() @@ -188,5 +201,644 @@ private void AssertNotification(StackItem stackItem, UInt160 scriptHash, int not CollectionAssert.AreEqual(scriptHash.ToArray(), array[0].GetByteArray()); Assert.AreEqual(notification, array[1].GetBigInteger()); } + + [TestMethod] + public void TestExecutionEngine_GetScriptContainer() + { + var engine = GetEngine(true); + InteropService.Invoke(engine, InteropService.System_ExecutionEngine_GetScriptContainer).Should().BeTrue(); + var stackItem = ((VM.Types.Array)engine.CurrentContext.EvaluationStack.Pop()).ToArray(); + stackItem.Length.Should().Be(8); + stackItem[0].GetByteArray().ToHexString().Should().Be(TestUtils.GetTransaction().Hash.ToArray().ToHexString()); + } + + [TestMethod] + public void TestExecutionEngine_GetExecutingScriptHash() + { + var engine = GetEngine(); + InteropService.Invoke(engine, InteropService.System_ExecutionEngine_GetExecutingScriptHash).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString() + .Should().Be(engine.CurrentScriptHash.ToArray().ToHexString()); + } + + [TestMethod] + public void TestExecutionEngine_GetCallingScriptHash() + { + var engine = GetEngine(true); + InteropService.Invoke(engine, InteropService.System_ExecutionEngine_GetCallingScriptHash).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); + + engine = GetEngine(true); + engine.LoadScript(new byte[] { 0x01 }); + InteropService.Invoke(engine, InteropService.System_ExecutionEngine_GetCallingScriptHash).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString() + .Should().Be(engine.CallingScriptHash.ToArray().ToHexString()); + } + + [TestMethod] + public void TestExecutionEngine_GetEntryScriptHash() + { + var engine = GetEngine(); + InteropService.Invoke(engine, InteropService.System_ExecutionEngine_GetEntryScriptHash).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString() + .Should().Be(engine.EntryScriptHash.ToArray().ToHexString()); + } + + [TestMethod] + public void TestRuntime_Platform() + { + var engine = GetEngine(); + InteropService.Invoke(engine, InteropService.System_Runtime_Platform).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString() + .Should().Be(Encoding.ASCII.GetBytes("NEO").ToHexString()); + } + + [TestMethod] + public void TestRuntime_GetTrigger() + { + var engine = GetEngine(); + InteropService.Invoke(engine, InteropService.System_Runtime_GetTrigger).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBigInteger() + .Should().Be((int)engine.Trigger); + } + + [TestMethod] + public void TestRuntime_CheckWitness() + { + byte[] privateKey = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + KeyPair keyPair = new KeyPair(privateKey); + ECPoint pubkey = keyPair.PublicKey; + + var engine = GetEngine(true); + ((Transaction)engine.ScriptContainer).Sender = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); + + engine.CurrentContext.EvaluationStack.Push(pubkey.EncodePoint(true)); + InteropService.Invoke(engine, InteropService.System_Runtime_CheckWitness).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Peek().GetType().Should().Be(typeof(Neo.VM.Types.Boolean)); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().Be(false); + + engine.CurrentContext.EvaluationStack.Push(((Transaction)engine.ScriptContainer).Sender.ToArray()); + InteropService.Invoke(engine, InteropService.System_Runtime_CheckWitness).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Peek().GetType().Should().Be(typeof(Neo.VM.Types.Boolean)); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().Be(false); + + engine.CurrentContext.EvaluationStack.Push(new byte[0]); + InteropService.Invoke(engine, InteropService.System_Runtime_CheckWitness).Should().BeFalse(); + } + + [TestMethod] + public void TestRuntime_Log() + { + var engine = GetEngine(true); + string message = "hello"; + engine.CurrentContext.EvaluationStack.Push(Encoding.UTF8.GetBytes(message)); + ApplicationEngine.Log += LogEvent; + InteropService.Invoke(engine, InteropService.System_Runtime_Log).Should().BeTrue(); + ((Transaction)engine.ScriptContainer).Script.ToHexString().Should().Be(new byte[] { 0x01, 0x02, 0x03 }.ToHexString()); + ApplicationEngine.Log -= LogEvent; + } + + [TestMethod] + public void TestRuntime_GetTime() + { + Block block = new Block(); + TestUtils.SetupBlockWithValues(block, UInt256.Zero, out var merkRootVal, out var val160, out var timestampVal, out var indexVal, out var scriptVal, out var transactionsVal, 0); + var engine = GetEngine(true, true); + engine.Snapshot.PersistingBlock = block; + + InteropService.Invoke(engine, InteropService.System_Runtime_GetTime).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(block.Timestamp); + } + + [TestMethod] + public void TestRuntime_Serialize() + { + var engine = GetEngine(); + engine.CurrentContext.EvaluationStack.Push(100); + InteropService.Invoke(engine, InteropService.System_Runtime_Serialize).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString() + .Should().Be(new byte[] { 0x02, 0x01, 0x64 }.ToHexString()); + + engine.CurrentContext.EvaluationStack.Push(new byte[1024 * 1024 * 2]); //Larger than MaxItemSize + InteropService.Invoke(engine, InteropService.System_Runtime_Serialize).Should().BeFalse(); + + engine.CurrentContext.EvaluationStack.Push(new TestInteropInterface()); //NotSupportedException + InteropService.Invoke(engine, InteropService.System_Runtime_Serialize).Should().BeFalse(); + } + + [TestMethod] + public void TestRuntime_Deserialize() + { + var engine = GetEngine(); + engine.CurrentContext.EvaluationStack.Push(100); + InteropService.Invoke(engine, InteropService.System_Runtime_Serialize).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.System_Runtime_Deserialize).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(100); + + engine.CurrentContext.EvaluationStack.Push(new byte[] { 0xfa, 0x01 }); //FormatException + InteropService.Invoke(engine, InteropService.System_Runtime_Deserialize).Should().BeFalse(); + } + + [TestMethod] + public void TestRuntime_GetInvocationCounter() + { + var engine = GetEngine(); + InteropService.Invoke(engine, InteropService.System_Runtime_GetInvocationCounter).Should().BeFalse(); + engine.InvocationCounter.TryAdd(engine.CurrentScriptHash, 10); + InteropService.Invoke(engine, InteropService.System_Runtime_GetInvocationCounter).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(10); + } + + [TestMethod] + public void TestCrypto_Verify() + { + var engine = GetEngine(true); + IVerifiable iv = engine.ScriptContainer; + byte[] message = iv.GetHashData(); + byte[] privateKey = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + KeyPair keyPair = new KeyPair(privateKey); + ECPoint pubkey = keyPair.PublicKey; + byte[] signature = Crypto.Default.Sign(message, privateKey, pubkey.EncodePoint(false).Skip(1).ToArray()); + + engine.CurrentContext.EvaluationStack.Push(signature); + engine.CurrentContext.EvaluationStack.Push(pubkey.EncodePoint(false)); + engine.CurrentContext.EvaluationStack.Push(message); + InteropService.Invoke(engine, InteropService.System_Crypto_Verify).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeTrue(); + + byte[] wrongkey = pubkey.EncodePoint(false); + wrongkey[0] = 5; + engine.CurrentContext.EvaluationStack.Push(signature); + engine.CurrentContext.EvaluationStack.Push(wrongkey); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(engine.ScriptContainer)); + InteropService.Invoke(engine, InteropService.System_Crypto_Verify).Should().BeFalse(); + + } + + [TestMethod] + public void TestBlockchain_GetHeight() + { + var engine = GetEngine(true, true); + InteropService.Invoke(engine, InteropService.System_Blockchain_GetHeight).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(0); + } + + [TestMethod] + public void TestBlockchain_GetBlock() + { + var engine = GetEngine(true, true); + + engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); + InteropService.Invoke(engine, InteropService.System_Blockchain_GetBlock).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); + + byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + engine.CurrentContext.EvaluationStack.Push(data1); + InteropService.Invoke(engine, InteropService.System_Blockchain_GetBlock).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeFalse(); + + byte[] data2 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; + engine.CurrentContext.EvaluationStack.Push(data2); + InteropService.Invoke(engine, InteropService.System_Blockchain_GetBlock).Should().BeFalse(); + } + + [TestMethod] + public void TestBlockchain_GetTransaction() + { + var engine = GetEngine(true, true); + byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + engine.CurrentContext.EvaluationStack.Push(data1); + InteropService.Invoke(engine, InteropService.System_Blockchain_GetTransaction).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBoolean().Should().BeFalse(); + } + + [TestMethod] + public void TestBlockchain_GetTransactionHeight() + { + var engine = GetEngine(true, true); + byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + engine.CurrentContext.EvaluationStack.Push(data1); + InteropService.Invoke(engine, InteropService.System_Blockchain_GetTransactionHeight).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetBigInteger().Should().Be(-1); + } + + [TestMethod] + public void TestBlockchain_GetContract() + { + var engine = GetEngine(true, true); + byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01 }; + engine.CurrentContext.EvaluationStack.Push(data1); + InteropService.Invoke(engine, InteropService.System_Blockchain_GetContract).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().Should().Be(StackItem.Null); + + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); + InteropService.Invoke(engine, InteropService.System_Blockchain_GetContract).Should().BeTrue(); + var stackItems = ((VM.Types.Array)engine.CurrentContext.EvaluationStack.Pop()).ToArray(); + stackItems.Length.Should().Be(3); + stackItems[0].GetType().Should().Be(typeof(ByteArray)); + stackItems[0].GetByteArray().ToHexString().Should().Be(state.Script.ToHexString()); + stackItems[1].GetBoolean().Should().BeFalse(); + stackItems[2].GetBoolean().Should().BeFalse(); + } + + [TestMethod] + public void TestStorage_GetContext() + { + var engine = GetEngine(); + InteropService.Invoke(engine, InteropService.System_Storage_GetContext).Should().BeTrue(); + var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); + ret.GetInterface().ScriptHash.Should().Be(engine.CurrentScriptHash); + ret.GetInterface().IsReadOnly.Should().BeFalse(); + } + + [TestMethod] + public void TestStorage_GetReadOnlyContext() + { + var engine = GetEngine(); + InteropService.Invoke(engine, InteropService.System_Storage_GetReadOnlyContext).Should().BeTrue(); + var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); + ret.GetInterface().ScriptHash.Should().Be(engine.CurrentScriptHash); + ret.GetInterface().IsReadOnly.Should().BeTrue(); + } + + [TestMethod] + public void TestStorage_Get() + { + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + + var storageKey = new StorageKey + { + ScriptHash = state.ScriptHash, + Key = new byte[] { 0x01 } + }; + + var storageItem = new StorageItem + { + Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, + IsConstant = true + }; + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); + var engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + + engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext + { + ScriptHash = state.ScriptHash, + IsReadOnly = false + })); + InteropService.Invoke(engine, InteropService.System_Storage_Get).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString().Should().Be(storageItem.Value.ToHexString()); + + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache()); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + engine.CurrentContext.EvaluationStack.Push(new byte[] { 0x01 }); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(new StorageContext + { + ScriptHash = state.ScriptHash, + IsReadOnly = false + })); + InteropService.Invoke(engine, InteropService.System_Storage_Get).Should().BeFalse(); + + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.System_Storage_Get).Should().BeFalse(); + } + + [TestMethod] + public void TestStorage_Put() + { + var engine = GetEngine(false, true); + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeFalse(); + + //CheckStorageContext fail + var key = new byte[] { 0x01 }; + var value = new byte[] { 0x02 }; + engine.CurrentContext.EvaluationStack.Push(value); + engine.CurrentContext.EvaluationStack.Push(key); + var state = TestUtils.GetContract(); + var storageContext = new StorageContext + { + ScriptHash = state.ScriptHash, + IsReadOnly = false + }; + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeFalse(); + + //key.Length > MaxStorageKeySize + key = new byte[InteropService.MaxStorageKeySize + 1]; + value = new byte[] { 0x02 }; + engine.CurrentContext.EvaluationStack.Push(value); + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeFalse(); + + //value.Length > MaxStorageValueSize + key = new byte[] { 0x01 }; + value = new byte[ushort.MaxValue + 1]; + engine.CurrentContext.EvaluationStack.Push(value); + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeFalse(); + + //context.IsReadOnly + key = new byte[] { 0x01 }; + value = new byte[] { 0x02 }; + storageContext.IsReadOnly = true; + engine.CurrentContext.EvaluationStack.Push(value); + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeFalse(); + + //storage value is constant + var mockSnapshot = new Mock(); + state.Manifest.Features = ContractFeatures.HasStorage; + + var storageKey = new StorageKey + { + ScriptHash = state.ScriptHash, + Key = new byte[] { 0x01 } + }; + var storageItem = new StorageItem + { + Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, + IsConstant = true + }; + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + key = new byte[] { 0x01 }; + value = new byte[] { 0x02 }; + storageContext.IsReadOnly = false; + engine.CurrentContext.EvaluationStack.Push(value); + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeFalse(); + + //success + storageItem.IsConstant = false; + engine.CurrentContext.EvaluationStack.Push(value); + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeTrue(); + + //value length == 0 + key = new byte[] { 0x01 }; + value = new byte[0]; + engine.CurrentContext.EvaluationStack.Push(value); + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Put).Should().BeTrue(); + } + + [TestMethod] + public void TestStorage_PutEx() + { + var engine = GetEngine(false, true); + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.System_Storage_PutEx).Should().BeFalse(); + + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + var storageKey = new StorageKey + { + ScriptHash = new UInt160(TestUtils.GetByteArray(20, 0x42)), + Key = new byte[] { 0x01 } + }; + var storageItem = new StorageItem + { + Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, + IsConstant = false + }; + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + var key = new byte[] { 0x01 }; + var value = new byte[] { 0x02 }; + var storageContext = new StorageContext + { + ScriptHash = state.ScriptHash, + IsReadOnly = false + }; + engine.CurrentContext.EvaluationStack.Push((int)StorageFlags.None); + engine.CurrentContext.EvaluationStack.Push(value); + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_PutEx).Should().BeTrue(); + } + + [TestMethod] + public void TestStorage_Delete() + { + var engine = GetEngine(false, true); + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.System_Storage_Delete).Should().BeFalse(); + + + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + var storageKey = new StorageKey + { + ScriptHash = new UInt160(TestUtils.GetByteArray(20, 0x42)), + Key = new byte[] { 0x01 } + }; + var storageItem = new StorageItem + { + Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, + IsConstant = false + }; + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + state.Manifest.Features = ContractFeatures.HasStorage; + var key = new byte[] { 0x01 }; + var storageContext = new StorageContext + { + ScriptHash = state.ScriptHash, + IsReadOnly = false + }; + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Delete).Should().BeTrue(); + + //context is readonly + storageContext.IsReadOnly = true; + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Delete).Should().BeFalse(); + + //CheckStorageContext fail + storageContext.IsReadOnly = false; + state.Manifest.Features = ContractFeatures.NoProperty; + engine.CurrentContext.EvaluationStack.Push(key); + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_Storage_Delete).Should().BeFalse(); + } + + [TestMethod] + public void TestStorageContext_AsReadOnly() + { + var engine = GetEngine(); + engine.CurrentContext.EvaluationStack.Push(1); + InteropService.Invoke(engine, InteropService.System_StorageContext_AsReadOnly).Should().BeFalse(); + + var state = TestUtils.GetContract(); + var storageContext = new StorageContext + { + ScriptHash = state.ScriptHash, + IsReadOnly = false + }; + engine.CurrentContext.EvaluationStack.Push(new InteropInterface(storageContext)); + InteropService.Invoke(engine, InteropService.System_StorageContext_AsReadOnly).Should().BeTrue(); + var ret = (InteropInterface)engine.CurrentContext.EvaluationStack.Pop(); + ret.GetInterface().IsReadOnly.Should().Be(true); + } + + [TestMethod] + public void TestInvoke() + { + var engine = new ApplicationEngine(TriggerType.Verification, null, null, 0); + InteropService.Invoke(engine, 10000).Should().BeFalse(); + InteropService.Invoke(engine, InteropService.System_StorageContext_AsReadOnly).Should().BeFalse(); + } + + [TestMethod] + public void TestContract_Call() + { + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + byte[] method = Encoding.UTF8.GetBytes("method"); + byte[] args = new byte[0]; + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(state.ScriptHash, state)); + var engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[] { 0x01 }); + + engine.CurrentContext.EvaluationStack.Push(args); + engine.CurrentContext.EvaluationStack.Push(method); + engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); + InteropService.Invoke(engine, InteropService.System_Contract_Call).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString().Should().Be(method.ToHexString()); + engine.CurrentContext.EvaluationStack.Pop().GetByteArray().ToHexString().Should().Be(args.ToHexString()); + + state.Manifest.Permissions[0].Methods = WildCardContainer.Create("a"); + engine.CurrentContext.EvaluationStack.Push(args); + engine.CurrentContext.EvaluationStack.Push(method); + engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); + InteropService.Invoke(engine, InteropService.System_Contract_Call).Should().BeFalse(); + state.Manifest.Permissions[0].Methods = WildCardContainer.CreateWildcard(); + + engine.CurrentContext.EvaluationStack.Push(args); + engine.CurrentContext.EvaluationStack.Push(method); + engine.CurrentContext.EvaluationStack.Push(state.ScriptHash.ToArray()); + InteropService.Invoke(engine, InteropService.System_Contract_Call).Should().BeTrue(); + + engine.CurrentContext.EvaluationStack.Push(args); + engine.CurrentContext.EvaluationStack.Push(method); + engine.CurrentContext.EvaluationStack.Push(UInt160.Zero.ToArray()); + InteropService.Invoke(engine, InteropService.System_Contract_Call).Should().BeFalse(); + } + + [TestMethod] + public void TestContract_Destroy() + { + var engine = GetEngine(false, true); + InteropService.Invoke(engine, InteropService.System_Contract_Destroy).Should().BeTrue(); + + var mockSnapshot = new Mock(); + var state = TestUtils.GetContract(); + state.Manifest.Features = ContractFeatures.HasStorage; + var scriptHash = UInt160.Parse("0xcb9f3b7c6fb1cf2c13a40637c189bdd066a272b4"); + var storageItem = new StorageItem + { + Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }, + IsConstant = false + }; + + var storageKey = new StorageKey + { + ScriptHash = scriptHash, + Key = new byte[] { 0x01 } + }; + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(scriptHash, state)); + mockSnapshot.SetupGet(p => p.Storages).Returns(new TestDataCache(storageKey, storageItem)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[0]); + InteropService.Invoke(engine, InteropService.System_Contract_Destroy).Should().BeTrue(); + + //storages are removed + mockSnapshot = new Mock(); + state = TestUtils.GetContract(); + mockSnapshot.SetupGet(p => p.Contracts).Returns(new TestDataCache(scriptHash, state)); + engine = new ApplicationEngine(TriggerType.Application, null, mockSnapshot.Object, 0); + engine.LoadScript(new byte[0]); + InteropService.Invoke(engine, InteropService.System_Contract_Destroy).Should().BeTrue(); + } + + public static void LogEvent(object sender, LogEventArgs args) + { + Transaction tx = (Transaction)args.ScriptContainer; + tx.Script = new byte[] { 0x01, 0x02, 0x03 }; + } + + private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false) + { + var tx = TestUtils.GetTransaction(); + var snapshot = TestBlockchain.GetStore().GetSnapshot().Clone(); + ApplicationEngine engine; + if (hasContainer && hasSnapshot) + { + engine = new ApplicationEngine(TriggerType.Application, tx, snapshot, 0); + } + else if (hasContainer && !hasSnapshot) + { + engine = new ApplicationEngine(TriggerType.Application, tx, null, 0); + } + else if (!hasContainer && hasSnapshot) + { + engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); + } + else + { + engine = new ApplicationEngine(TriggerType.Application, null, null, 0); + } + engine.LoadScript(new byte[] { 0x01 }); + return engine; + } + } + + internal class TestInteropInterface : InteropInterface + { + public override bool Equals(StackItem other) => true; + public override bool GetBoolean() => true; + public override T GetInterface() => throw new NotImplementedException(); } } diff --git a/neo.UnitTests/SmartContract/UT_LogEventArgs.cs b/neo.UnitTests/SmartContract/UT_LogEventArgs.cs new file mode 100644 index 0000000000..8dc3699c82 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_LogEventArgs.cs @@ -0,0 +1,23 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_LogEventArgs + { + [TestMethod] + public void TestGeneratorAndGet() + { + IVerifiable container = new Header(); + UInt160 scripthash = UInt160.Zero; + string message = "lalala"; + LogEventArgs logEventArgs = new LogEventArgs(container, scripthash, message); + Assert.IsNotNull(logEventArgs); + Assert.AreEqual(container, logEventArgs.ScriptContainer); + Assert.AreEqual(scripthash, logEventArgs.ScriptHash); + Assert.AreEqual(message, logEventArgs.Message); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_NefFile.cs b/neo.UnitTests/SmartContract/UT_NefFile.cs new file mode 100644 index 0000000000..23d8040c79 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_NefFile.cs @@ -0,0 +1,148 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.SmartContract; +using System; +using System.IO; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_NefFile + { + public NefFile file = new NefFile() + { + Compiler = "".PadLeft(32, ' '), + Version = new Version(1, 2, 3, 4), + Script = new byte[] { 0x01, 0x02, 0x03 } + }; + + [TestInitialize] + public void TestSetup() + { + file.ScriptHash = file.Script.ToScriptHash(); + file.CheckSum = NefFile.ComputeChecksum(file); + } + + [TestMethod] + public void TestDeserialize() + { + byte[] wrongMagic = { 0x00, 0x00, 0x00, 0x00 }; + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + ((ISerializable)file).Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + ms.Write(wrongMagic, 0, 4); + ms.Seek(0, SeekOrigin.Begin); + ISerializable newFile = new NefFile(); + Action action = () => newFile.Deserialize(reader); + action.Should().Throw(); + } + + file.CheckSum = 0; + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + ((ISerializable)file).Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + ISerializable newFile = new NefFile(); + Action action = () => newFile.Deserialize(reader); + action.Should().Throw(); + } + + file.CheckSum = NefFile.ComputeChecksum(file); + file.ScriptHash = new byte[] { 0x01 }.ToScriptHash(); + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + ((ISerializable)file).Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + ISerializable newFile = new NefFile(); + Action action = () => newFile.Deserialize(reader); + action.Should().Throw(); + } + + file.ScriptHash = file.Script.ToScriptHash(); + var data = file.ToArray(); + var newFile1 = data.AsSerializable(); + newFile1.Version.Should().Be(file.Version); + newFile1.Compiler.Should().Be(file.Compiler); + newFile1.ScriptHash.Should().Be(file.ScriptHash); + newFile1.CheckSum.Should().Be(file.CheckSum); + newFile1.Script.Should().BeEquivalentTo(file.Script); + } + + [TestMethod] + public void TestGetSize() + { + file.Size.Should().Be(4 + 32 + 16 + 20 + 4 + 4); + } + + [TestMethod] + public void ParseTest() + { + var file = new NefFile() + { + Compiler = "".PadLeft(32, ' '), + Version = new Version(1, 2, 3, 4), + Script = new byte[] { 0x01, 0x02, 0x03 } + }; + + file.ScriptHash = file.Script.ToScriptHash(); + file.CheckSum = NefFile.ComputeChecksum(file); + + var data = file.ToArray(); + file = data.AsSerializable(); + + Assert.AreEqual("".PadLeft(32, ' '), file.Compiler); + Assert.AreEqual(new Version(1, 2, 3, 4), file.Version); + Assert.AreEqual(file.Script.ToScriptHash(), file.ScriptHash); + CollectionAssert.AreEqual(new byte[] { 0x01, 0x02, 0x03 }, file.Script); + } + + [TestMethod] + public void LimitTest() + { + var file = new NefFile() + { + Compiler = "".PadLeft(byte.MaxValue, ' '), + Version = new Version(1, 2, 3, 4), + Script = new byte[1024 * 1024], + ScriptHash = new byte[1024 * 1024].ToScriptHash(), + CheckSum = 0 + }; + + // Wrong compiler + + Assert.ThrowsException(() => file.ToArray()); + + // Wrong script + + file.Compiler = ""; + file.Script = new byte[(1024 * 1024) + 1]; + file.ScriptHash = file.Script.ToScriptHash(); + var data = file.ToArray(); + + Assert.ThrowsException(() => data.AsSerializable()); + + // Wrong script hash + + file.Script = new byte[1024 * 1024]; + data = file.ToArray(); + + Assert.ThrowsException(() => data.AsSerializable()); + + // Wrong checksum + + file.Script = new byte[1024]; + data = file.ToArray(); + file.CheckSum = NefFile.ComputeChecksum(file) + 1; + + Assert.ThrowsException(() => data.AsSerializable()); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs b/neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs new file mode 100644 index 0000000000..a1dd95b6ee --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs @@ -0,0 +1,22 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.VM; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_NotifyEventArgs + { + [TestMethod] + public void TestGetScriptContainer() + { + IVerifiable container = new TestVerifiable(); + UInt160 script_hash = new byte[] { 0x00 }.ToScriptHash(); + StackItem state = new ContainerPlaceholder(); + NotifyEventArgs args = new NotifyEventArgs(container, script_hash, state); + args.ScriptContainer.Should().Be(container); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs new file mode 100644 index 0000000000..8379fccd6b --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -0,0 +1,306 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_SmartContractHelper + { + [TestMethod] + public void TestIsMultiSigContract() + { + Neo.Cryptography.ECC.ECPoint[] publicKeys1 = new Neo.Cryptography.ECC.ECPoint[20]; + for (int i = 0; i < 20; i++) + { + byte[] privateKey1 = new byte[32]; + RandomNumberGenerator rng1 = RandomNumberGenerator.Create(); + rng1.GetBytes(privateKey1); + KeyPair key1 = new KeyPair(privateKey1); + publicKeys1[i] = key1.PublicKey; + } + byte[] script1 = Contract.CreateMultiSigRedeemScript(20, publicKeys1); + Assert.AreEqual(true, Neo.SmartContract.Helper.IsMultiSigContract(script1, out int m1, out int n1)); + + Neo.Cryptography.ECC.ECPoint[] publicKeys2 = new Neo.Cryptography.ECC.ECPoint[256]; + for (int i = 0; i < 256; i++) + { + byte[] privateKey2 = new byte[32]; + RandomNumberGenerator rng2 = RandomNumberGenerator.Create(); + rng2.GetBytes(privateKey2); + KeyPair key2 = new KeyPair(privateKey2); + publicKeys2[i] = key2.PublicKey; + } + byte[] script2 = Contract.CreateMultiSigRedeemScript(256, publicKeys2); + Assert.AreEqual(true, Neo.SmartContract.Helper.IsMultiSigContract(script2, out int m2, out int n2)); + + Neo.Cryptography.ECC.ECPoint[] publicKeys3 = new Neo.Cryptography.ECC.ECPoint[3]; + for (int i = 0; i < 3; i++) + { + byte[] privateKey3 = new byte[32]; + RandomNumberGenerator rng3 = RandomNumberGenerator.Create(); + rng3.GetBytes(privateKey3); + KeyPair key3 = new KeyPair(privateKey3); + publicKeys3[i] = key3.PublicKey; + } + byte[] script3 = Contract.CreateMultiSigRedeemScript(3, publicKeys3); + Assert.AreEqual(true, Neo.SmartContract.Helper.IsMultiSigContract(script3, out int m3, out int n3)); + + Neo.Cryptography.ECC.ECPoint[] publicKeys4 = new Neo.Cryptography.ECC.ECPoint[3]; + for (int i = 0; i < 3; i++) + { + byte[] privateKey4 = new byte[32]; + RandomNumberGenerator rng4 = RandomNumberGenerator.Create(); + rng4.GetBytes(privateKey4); + KeyPair key4 = new KeyPair(privateKey4); + publicKeys4[i] = key4.PublicKey; + } + byte[] script4 = Contract.CreateMultiSigRedeemScript(3, publicKeys4); + script4[script4.Length - 1] = 0x00; + Assert.AreEqual(false, Neo.SmartContract.Helper.IsMultiSigContract(script4, out int m4, out int n4)); + + } + + [TestMethod] + public void TestIsSignatureContract() + { + byte[] privateKey = new byte[32]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes(privateKey); + KeyPair key = new KeyPair(privateKey); + byte[] script = Contract.CreateSignatureRedeemScript(key.PublicKey); + Assert.AreEqual(true, Neo.SmartContract.Helper.IsSignatureContract(script)); + script[0] = 0x22; + Assert.AreEqual(false, Neo.SmartContract.Helper.IsSignatureContract(script)); + } + + [TestMethod] + public void TestIsStandardContract() + { + byte[] privateKey1 = new byte[32]; + RandomNumberGenerator rng1 = RandomNumberGenerator.Create(); + rng1.GetBytes(privateKey1); + KeyPair key1 = new KeyPair(privateKey1); + byte[] script1 = Contract.CreateSignatureRedeemScript(key1.PublicKey); + Assert.AreEqual(true, Neo.SmartContract.Helper.IsStandardContract(script1)); + + Neo.Cryptography.ECC.ECPoint[] publicKeys2 = new Neo.Cryptography.ECC.ECPoint[3]; + for (int i = 0; i < 3; i++) + { + byte[] privateKey2 = new byte[32]; + RandomNumberGenerator rng2 = RandomNumberGenerator.Create(); + rng2.GetBytes(privateKey2); + KeyPair key2 = new KeyPair(privateKey2); + publicKeys2[i] = key2.PublicKey; + } + byte[] script2 = Contract.CreateMultiSigRedeemScript(3, publicKeys2); + Assert.AreEqual(true, Neo.SmartContract.Helper.IsStandardContract(script2)); + } + + [TestMethod] + public void TestSerialize() + { + StackItem stackItem1 = new ByteArray(new byte[5]); + byte[] result1 = Neo.SmartContract.Helper.Serialize(stackItem1); + byte[] expectedArray1 = new byte[] { + 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + Assert.AreEqual(Encoding.Default.GetString(expectedArray1), Encoding.Default.GetString(result1)); + + StackItem stackItem2 = new VM.Types.Boolean(true); + byte[] result2 = Neo.SmartContract.Helper.Serialize(stackItem2); + byte[] expectedArray2 = new byte[] { + 0x01, 0x01 + }; + Assert.AreEqual(Encoding.Default.GetString(expectedArray2), Encoding.Default.GetString(result2)); + + StackItem stackItem3 = new VM.Types.Integer(1); + byte[] result3 = Neo.SmartContract.Helper.Serialize(stackItem3); + byte[] expectedArray3 = new byte[] { + 0x02, 0x01, 0x01 + }; + Assert.AreEqual(Encoding.Default.GetString(expectedArray3), Encoding.Default.GetString(result3)); + + StackItem stackItem4 = new InteropInterface(new object()); + Action action4 = () => Neo.SmartContract.Helper.Serialize(stackItem4); + action4.Should().Throw(); + + StackItem stackItem5 = new VM.Types.Integer(1); + byte[] result5 = Neo.SmartContract.Helper.Serialize(stackItem5); + byte[] expectedArray5 = new byte[] { + 0x02, 0x01, 0x01 + }; + Assert.AreEqual(Encoding.Default.GetString(expectedArray5), Encoding.Default.GetString(result5)); + + + StackItem stackItem61 = new VM.Types.Integer(1); + List list6 = new List + { + stackItem61 + }; + StackItem stackItem62 = new VM.Types.Array(list6); + byte[] result6 = Neo.SmartContract.Helper.Serialize(stackItem62); + byte[] expectedArray6 = new byte[] { + 0x80,0x01,0x02,0x01,0x01 + }; + Assert.AreEqual(Encoding.Default.GetString(expectedArray6), Encoding.Default.GetString(result6)); + + StackItem stackItem71 = new VM.Types.Integer(1); + List list7 = new List + { + stackItem71 + }; + StackItem stackItem72 = new VM.Types.Struct(list7); + byte[] result7 = Neo.SmartContract.Helper.Serialize(stackItem72); + byte[] expectedArray7 = new byte[] { + 0x81,0x01,0x02,0x01,0x01 + }; + Assert.AreEqual(Encoding.Default.GetString(expectedArray7), Encoding.Default.GetString(result7)); + + StackItem stackItem81 = new VM.Types.Integer(1); + Dictionary list8 = new Dictionary + { + { new VM.Types.Integer(2), stackItem81 } + }; + StackItem stackItem82 = new VM.Types.Map(list8); + byte[] result8 = Neo.SmartContract.Helper.Serialize(stackItem82); + byte[] expectedArray8 = new byte[] { + 0x82,0x01,0x02,0x01,0x02,0x02,0x01,0x01 + }; + Assert.AreEqual(Encoding.Default.GetString(expectedArray8), Encoding.Default.GetString(result8)); + + StackItem stackItem9 = new VM.Types.Integer(1); + Map stackItem91 = new VM.Types.Map(); + stackItem91.Add(stackItem9, stackItem91); + Action action9 = () => Neo.SmartContract.Helper.Serialize(stackItem91); + action9.Should().Throw(); + + VM.Types.Array stackItem10 = new VM.Types.Array(); + stackItem10.Add(stackItem10); + Action action10 = () => Neo.SmartContract.Helper.Serialize(stackItem10); + action10.Should().Throw(); + } + + [TestMethod] + public void TestDeserializeStackItem() + { + StackItem stackItem1 = new ByteArray(new byte[5]); + byte[] byteArray1 = Neo.SmartContract.Helper.Serialize(stackItem1); + StackItem result1 = Neo.SmartContract.Helper.DeserializeStackItem(byteArray1, 1, (uint)byteArray1.Length); + Assert.AreEqual(stackItem1, result1); + + StackItem stackItem2 = new VM.Types.Boolean(true); + byte[] byteArray2 = Neo.SmartContract.Helper.Serialize(stackItem2); + StackItem result2 = Neo.SmartContract.Helper.DeserializeStackItem(byteArray2, 1, (uint)byteArray2.Length); + Assert.AreEqual(stackItem2, result2); + + StackItem stackItem3 = new VM.Types.Integer(1); + byte[] byteArray3 = Neo.SmartContract.Helper.Serialize(stackItem3); + StackItem result3 = Neo.SmartContract.Helper.DeserializeStackItem(byteArray3, 1, (uint)byteArray3.Length); + Assert.AreEqual(stackItem3, result3); + + StackItem stackItem4 = new VM.Types.Integer(1); + byte[] byteArray4 = Neo.SmartContract.Helper.Serialize(stackItem4); + byteArray4[0] = 0x40; + Action action4 = () => Neo.SmartContract.Helper.DeserializeStackItem(byteArray4, 1, (uint)byteArray4.Length); + action4.Should().Throw(); + + StackItem stackItem51 = new VM.Types.Integer(1); + List list5 = new List(); + list5.Add(stackItem51); + StackItem stackItem52 = new VM.Types.Array(list5); + byte[] byteArray5 = Neo.SmartContract.Helper.Serialize(stackItem52); + StackItem result5 = Neo.SmartContract.Helper.DeserializeStackItem(byteArray5, 1, (uint)byteArray5.Length); + Assert.AreEqual(((VM.Types.Array)stackItem52).Count, ((VM.Types.Array)result5).Count); + Assert.AreEqual(((VM.Types.Array)stackItem52).GetEnumerator().Current, ((VM.Types.Array)result5).GetEnumerator().Current); + + StackItem stackItem61 = new VM.Types.Integer(1); + List list6 = new List(); + list6.Add(stackItem61); + StackItem stackItem62 = new VM.Types.Struct(list6); + byte[] byteArray6 = Neo.SmartContract.Helper.Serialize(stackItem62); + StackItem result6 = Neo.SmartContract.Helper.DeserializeStackItem(byteArray6, 1, (uint)byteArray6.Length); + Assert.AreEqual(((VM.Types.Struct)stackItem62).Count, ((VM.Types.Struct)result6).Count); + Assert.AreEqual(((VM.Types.Struct)stackItem62).GetEnumerator().Current, ((VM.Types.Struct)result6).GetEnumerator().Current); + + StackItem stackItem71 = new VM.Types.Integer(1); + Dictionary list7 = new Dictionary(); + list7.Add(new VM.Types.Integer(2), stackItem71); + StackItem stackItem72 = new VM.Types.Map(list7); + byte[] byteArray7 = Neo.SmartContract.Helper.Serialize(stackItem72); + StackItem result7 = Neo.SmartContract.Helper.DeserializeStackItem(byteArray7, 1, (uint)byteArray7.Length); + Assert.AreEqual(((VM.Types.Map)stackItem72).Count, ((VM.Types.Map)result7).Count); + Assert.AreEqual(((VM.Types.Map)stackItem72).Keys.GetEnumerator().Current, ((VM.Types.Map)result7).Keys.GetEnumerator().Current); + Assert.AreEqual(((VM.Types.Map)stackItem72).Values.GetEnumerator().Current, ((VM.Types.Map)result7).Values.GetEnumerator().Current); + } + + [TestMethod] + public void TestToInteropMethodHash() + { + byte[] temp1 = Encoding.ASCII.GetBytes("AAAA"); + byte[] temp2 = Neo.Cryptography.Helper.Sha256(temp1); + uint result = BitConverter.ToUInt32(temp2, 0); + Assert.AreEqual(result, Neo.SmartContract.Helper.ToInteropMethodHash("AAAA")); + } + + [TestMethod] + public void TestToScriptHash() + { + byte[] temp1 = Encoding.ASCII.GetBytes("AAAA"); + byte[] temp2 = Neo.Cryptography.Helper.Sha256(temp1); + uint result = BitConverter.ToUInt32(temp2, 0); + Assert.AreEqual(result, Neo.SmartContract.Helper.ToInteropMethodHash("AAAA")); + } + + [TestMethod] + public void TestVerifyWitnesses() + { + var mockSnapshot1 = new Mock(); + UInt256 index1 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); + TestDataCache testDataCache1 = new TestDataCache(); + testDataCache1.Add(index1, new TrimmedBlock()); + testDataCache1.Delete(index1); + mockSnapshot1.SetupGet(p => p.Blocks).Returns(testDataCache1); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, mockSnapshot1.Object, 100)); + + var mockSnapshot2 = new Mock(); + UInt256 index2 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); + TrimmedBlock block2 = new TrimmedBlock(); + block2.NextConsensus = UInt160.Zero; + TestDataCache testDataCache21 = new TestDataCache(); + testDataCache21.Add(index2, block2); + Header header2 = new Header() { PrevHash = index2, Witness = new Witness { VerificationScript = new byte[0] } }; + mockSnapshot2.SetupGet(p => p.Blocks).Returns(testDataCache21); + + TestDataCache testDataCache22 = new TestDataCache(); + testDataCache22.Add(UInt160.Zero, new ContractState()); + testDataCache22.Delete(UInt160.Zero); + mockSnapshot2.SetupGet(p => p.Contracts).Returns(testDataCache22); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, mockSnapshot2.Object, 100)); + + var mockSnapshot3 = new Mock(); + UInt256 index3 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); + TrimmedBlock block3 = new TrimmedBlock(); + block3.NextConsensus = UInt160.Zero; + TestDataCache testDataCache31 = new TestDataCache(); + testDataCache31.Add(index3, block3); + Header header3 = new Header() { PrevHash = index3, Witness = new Witness { VerificationScript = new byte[0] } }; + mockSnapshot3.SetupGet(p => p.Blocks).Returns(testDataCache31); + TestDataCache testDataCache32 = new TestDataCache(); + testDataCache32.Add(UInt160.Zero, new ContractState()); + mockSnapshot3.SetupGet(p => p.Contracts).Returns(testDataCache32); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header3, mockSnapshot3.Object, 100)); + } + } +} diff --git a/neo.UnitTests/SmartContract/UT_StorageContext.cs b/neo.UnitTests/SmartContract/UT_StorageContext.cs new file mode 100644 index 0000000000..eff7166a66 --- /dev/null +++ b/neo.UnitTests/SmartContract/UT_StorageContext.cs @@ -0,0 +1,22 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_StorageContext + { + [TestMethod] + public void TestToArray() + { + UInt160 script_hash = new byte[] { 0x00 }.ToScriptHash(); + StorageContext context = new StorageContext() + { + ScriptHash = script_hash, + IsReadOnly = true + }; + context.ToArray().Should().BeEquivalentTo(new byte[] { 0x00 }.ToScriptHash().ToArray()); + } + } +} diff --git a/neo.UnitTests/TestDataCache.cs b/neo.UnitTests/TestDataCache.cs index b468e09e4c..37300f22e1 100644 --- a/neo.UnitTests/TestDataCache.cs +++ b/neo.UnitTests/TestDataCache.cs @@ -18,6 +18,7 @@ public TestDataCache(TKey key, TValue value) { dic.Add(key, value); } + public override void DeleteInternal(TKey key) { dic.Remove(key);