diff --git a/src/Neo.Compiler.MSIL/Helper.cs b/src/Neo.Compiler.MSIL/Helper.cs index 5a3b4a0c3..5c777f22b 100644 --- a/src/Neo.Compiler.MSIL/Helper.cs +++ b/src/Neo.Compiler.MSIL/Helper.cs @@ -35,7 +35,8 @@ public static uint ToInteropMethodHash(this byte[] method) return BitConverter.ToUInt32(sha.ComputeHash(method), 0); } } - public static byte[] HexString2Bytes(string str) + + public static byte[] HexString2Bytes(this string str) { if (str.IndexOf("0x") == 0) str = str.Substring(2); @@ -46,6 +47,7 @@ public static byte[] HexString2Bytes(string str) } return outd; } + public static byte[] OpDataToBytes(string opdata) { try // convert hex string to byte[] @@ -54,7 +56,7 @@ public static byte[] OpDataToBytes(string opdata) } catch { - return System.Text.Encoding.UTF8.GetBytes(opdata); + return Encoding.UTF8.GetBytes(opdata); } } } diff --git a/src/Neo.Compiler.MSIL/MSIL/CctorSubVM.cs b/src/Neo.Compiler.MSIL/MSIL/CctorSubVM.cs index 116dad90e..7292d8992 100644 --- a/src/Neo.Compiler.MSIL/MSIL/CctorSubVM.cs +++ b/src/Neo.Compiler.MSIL/MSIL/CctorSubVM.cs @@ -38,16 +38,6 @@ public static object Dup(object src) } } - public static byte[] HexString2Bytes(string str) - { - byte[] outd = new byte[str.Length / 2]; - for (var i = 0; i < str.Length / 2; i++) - { - outd[i] = byte.Parse(str.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); - } - return outd; - } - public static void Parse(ILMethod from, NeoModule to) { calcStack = new Stack(); @@ -193,8 +183,7 @@ public static void Parse(ILMethod from, NeoModule to) } else if (attrname == "HexToBytes")//HexString2Bytes to bytes[] { - if (text.IndexOf("0x") == 0) text = text.Substring(2); - var hex = HexString2Bytes(text); + var hex = text.HexString2Bytes(); calcStack.Push(hex); } else if (attrname == "ToBigInteger") diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index e35218e86..023ebe13e 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -234,13 +234,10 @@ public bool IsAppCall(Mono.Cecil.MethodDefinition defs, out byte[] hash) try { - hash = new byte[20]; - if (hashstr.Length < 40) - throw new Exception("hash too short:" + hashstr); - for (var i = 0; i < 20; i++) - { - hash[i] = byte.Parse(hashstr.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); - } + hash = hashstr.HexString2Bytes(); + if (hash.Length != 20) + throw new Exception("Wrong hash:" + hashstr); + //string hexhash 需要反序 hash = hash.Reverse().ToArray(); return true; diff --git a/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj b/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj index 5bd4228fd..a20ad8b00 100644 --- a/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj +++ b/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj @@ -1,4 +1,4 @@ - + 2015-2019 The Neo Project @@ -23,7 +23,7 @@ - + diff --git a/src/Neo.SmartContract.Framework/AppcallAttribute.cs b/src/Neo.SmartContract.Framework/AppcallAttribute.cs index 11bbd929b..2ee89255d 100644 --- a/src/Neo.SmartContract.Framework/AppcallAttribute.cs +++ b/src/Neo.SmartContract.Framework/AppcallAttribute.cs @@ -18,6 +18,12 @@ public AppcallAttribute(byte[] scriptHash) public AppcallAttribute(string scriptHash) { if (scriptHash == null) throw new ArgumentNullException(); + + if (scriptHash.StartsWith("0x")) + { + scriptHash = scriptHash.Remove(0, 2); + } + if (scriptHash.Length != 40) throw new ArgumentException(); this.ScriptHash = new byte[scriptHash.Length / 2]; for (int i = 0; i < this.ScriptHash.Length; i++) diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index 4258c63e7..e4d9bd57d 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -238,10 +238,10 @@ public static byte[] Reverse(this byte[] source) [NonemitWithConvert(ConvertMethod.ToBigInteger)] public extern static BigInteger ToBigInteger(this string text); - [Syscall("Neo.Runtime.Serialize")] + [Syscall("System.Runtime.Serialize")] public extern static byte[] Serialize(this object source); - [Syscall("Neo.Runtime.Deserialize")] + [Syscall("System.Runtime.Deserialize")] public extern static object Deserialize(this byte[] source); } } diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Block.cs b/src/Neo.SmartContract.Framework/Services/Neo/Block.cs index 009233712..bfeefd873 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Block.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Block.cs @@ -1,14 +1,14 @@ namespace Neo.SmartContract.Framework.Services.Neo { - public class Block : Header + public class Block { - [Syscall("Neo.Block.GetTransactionCount")] - public extern int GetTransactionCount(); - - [Syscall("Neo.Block.GetTransactions")] - public extern Transaction[] GetTransactions(); - - [Syscall("Neo.Block.GetTransaction")] - public extern Transaction GetTransaction(int index); + public readonly byte[] Hash; + public readonly uint Version; + public readonly byte[] PrevHash; + public readonly byte[] MerkleRoot; + public readonly ulong Timestamp; + public readonly uint Index; + public readonly byte[] NextConsensus; + public readonly int TransactionsCount; } } diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Blockchain.cs b/src/Neo.SmartContract.Framework/Services/Neo/Blockchain.cs index 11b5c6296..05218acc0 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Blockchain.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Blockchain.cs @@ -1,26 +1,31 @@ +using System.Numerics; + namespace Neo.SmartContract.Framework.Services.Neo { public static class Blockchain { - [Syscall("Neo.Blockchain.GetHeight")] + [Syscall("System.Blockchain.GetHeight")] public static extern uint GetHeight(); - [Syscall("Neo.Blockchain.GetHeader")] - public static extern Header GetHeader(uint height); - - [Syscall("Neo.Blockchain.GetHeader")] - public static extern Header GetHeader(byte[] hash); - - [Syscall("Neo.Blockchain.GetBlock")] + [Syscall("System.Blockchain.GetBlock")] public static extern Block GetBlock(uint height); - [Syscall("Neo.Blockchain.GetBlock")] + [Syscall("System.Blockchain.GetBlock")] public static extern Block GetBlock(byte[] hash); - [Syscall("Neo.Blockchain.GetTransaction")] + [Syscall("System.Blockchain.GetTransaction")] public static extern Transaction GetTransaction(byte[] hash); - [Syscall("Neo.Blockchain.GetContract")] + [Syscall("System.Blockchain.GetTransactionFromBlock")] + public static extern Transaction GetTransactionFromBlock(byte[] blockHash, int txIndex); + + [Syscall("System.Blockchain.GetTransactionFromBlock")] + public static extern Transaction GetTransactionFromBlock(uint blockIndex, int txIndex); + + [Syscall("System.Blockchain.GetTransactionHeight")] + public static extern BigInteger GetTransactionHeight(byte[] hash); + + [Syscall("System.Blockchain.GetContract")] public static extern Contract GetContract(byte[] script_hash); } } diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Contract.cs b/src/Neo.SmartContract.Framework/Services/Neo/Contract.cs index 41f3e22b1..65b985300 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Contract.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Contract.cs @@ -2,23 +2,29 @@ namespace Neo.SmartContract.Framework.Services.Neo { public class Contract { - public extern byte[] Script - { - [Syscall("Neo.Contract.GetScript")] - get; - } + /// + /// Script + /// + public readonly byte[] Script; - public extern bool IsPayable - { - [Syscall("Neo.Contract.IsPayable")] - get; - } + /// + /// Has storage + /// + public readonly bool HasStorage; + + /// + /// Is payable + /// + public readonly bool IsPayable; + + [Syscall("System.Contract.Call")] + public static extern object Call(byte[] scriptHash, string method, object[] arguments); [Syscall("Neo.Contract.Create")] - public static extern Contract Create(byte[] script, ContractPropertyState contract_property_state); + public static extern Contract Create(byte[] script, string manifest); - [Syscall("Neo.Contract.Migrate")] - public static extern Contract Migrate(byte[] script, ContractPropertyState contract_property_state); + [Syscall("Neo.Contract.Update")] + public static extern void Update(byte[] script, string manifest); [Syscall("System.Contract.Destroy")] public static extern void Destroy(); diff --git a/src/Neo.SmartContract.Framework/Services/Neo/ContractPropertyState.cs b/src/Neo.SmartContract.Framework/Services/Neo/ContractPropertyState.cs deleted file mode 100644 index 2359bac94..000000000 --- a/src/Neo.SmartContract.Framework/Services/Neo/ContractPropertyState.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Neo.SmartContract.Framework.Services.Neo -{ - public enum ContractPropertyState : byte - { - NoProperty = 0, - - HasStorage = 1 << 0, - Payable = 1 << 2 - } -} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Crypto.cs b/src/Neo.SmartContract.Framework/Services/Neo/Crypto.cs new file mode 100644 index 000000000..bd88dc14a --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/Neo/Crypto.cs @@ -0,0 +1,14 @@ +namespace Neo.SmartContract.Framework.Services.Neo +{ + public static class Crypto + { + [Syscall("Neo.Crypto.CheckSig")] + public extern static bool VerifySignature(byte[] pubkey, byte[] signature); + + [Syscall("System.Crypto.Verify")] + public extern static bool VerifySignature(byte[] message, byte[] pubkey, byte[] signature); + + [Syscall("Neo.Crypto.CheckMultiSig")] + public extern static bool VerifySignatures(byte[][] pubkey, byte[][] signature); + } +} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Enumerator.cs b/src/Neo.SmartContract.Framework/Services/Neo/Enumerator.cs new file mode 100644 index 000000000..6f6d50507 --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/Neo/Enumerator.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace Neo.SmartContract.Framework.Services.Neo +{ + public class Enumerator + { + [Syscall("Neo.Enumerator.Create")] + public static extern Enumerator Create(IEnumerable entry); + + [Syscall("Neo.Enumerator.Concat")] + public extern Enumerator Concat(Enumerator value); + + [Syscall("Neo.Enumerator.Next")] + public extern bool Next(); + + public extern TValue Value + { + [Syscall("Neo.Enumerator.Value")] + get; + } + } +} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Header.cs b/src/Neo.SmartContract.Framework/Services/Neo/Header.cs deleted file mode 100644 index 4b60f6ce8..000000000 --- a/src/Neo.SmartContract.Framework/Services/Neo/Header.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace Neo.SmartContract.Framework.Services.Neo -{ - public class Header : IScriptContainer - { - public extern byte[] Hash - { - [Syscall("System.Header.GetHash")] - get; - } - - public extern uint Version - { - [Syscall("Neo.Header.GetVersion")] - get; - } - - public extern byte[] PrevHash - { - [Syscall("System.Header.GetPrevHash")] - get; - } - - public extern byte[] MerkleRoot - { - [Syscall("Neo.Header.GetMerkleRoot")] - get; - } - - public extern uint Timestamp - { - [Syscall("System.Header.GetTimestamp")] - get; - } - - public extern uint Index - { - [Syscall("System.Header.GetIndex")] - get; - } - - public extern byte[] NextConsensus - { - [Syscall("Neo.Header.GetNextConsensus")] - get; - } - } -} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Iterator.cs b/src/Neo.SmartContract.Framework/Services/Neo/Iterator.cs index 0725e47fa..dd82d8f1b 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Iterator.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Iterator.cs @@ -1,7 +1,18 @@ +using System.Collections.Generic; + namespace Neo.SmartContract.Framework.Services.Neo { public class Iterator { + [Syscall("Neo.Iterator.Create")] + public static extern Iterator Create(Map entry); + + [Syscall("Neo.Iterator.Create")] + public static extern Iterator Create(IEnumerable entry); + + [Syscall("Neo.Iterator.Concat")] + public extern Iterator Concat(Iterator value); + [Syscall("Neo.Enumerator.Next")] public extern bool Next(); @@ -16,5 +27,17 @@ public class Iterator [Syscall("Neo.Enumerator.Value")] get; } + + public extern Enumerator Keys + { + [Syscall("Neo.Iterator.Keys")] + get; + } + + public extern Enumerator Values + { + [Syscall("Neo.Iterator.Values")] + get; + } } } diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Json.cs b/src/Neo.SmartContract.Framework/Services/Neo/Json.cs new file mode 100644 index 000000000..5a4cb2b3f --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/Neo/Json.cs @@ -0,0 +1,11 @@ +namespace Neo.SmartContract.Framework.Services.Neo +{ + public static class Json + { + [Syscall("Neo.Json.Serialize")] + public extern static string Serialize(object obj); + + [Syscall("Neo.Json.Deserialize")] + public extern static object Deserialize(string json); + } +} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Native.cs b/src/Neo.SmartContract.Framework/Services/Neo/Native.cs new file mode 100644 index 000000000..c1fd16aaa --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/Neo/Native.cs @@ -0,0 +1,14 @@ +namespace Neo.SmartContract.Framework.Services.Neo +{ + public class Native + { + [Appcall("0x43cf98eddbe047e198a3e5d57006311442a0ca15")] + public static extern object NEO(string method, object[] arguments); + + [Appcall("0xa1760976db5fcdfab2a9930e8f6ce875b2d18225")] + public static extern object GAS(string method, object[] arguments); + + [Appcall("0x9c5699b260bd468e2160dd5d45dfd2686bba8b77")] + public static extern object Policy(string method, object[] arguments); + } +} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Runtime.cs b/src/Neo.SmartContract.Framework/Services/Neo/Runtime.cs index 96bb9c415..979b381a5 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Runtime.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Runtime.cs @@ -8,7 +8,13 @@ public static class Runtime get; } - public static extern uint Time + public static extern string Platform + { + [Syscall("System.Runtime.Platform")] + get; + } + + public static extern ulong Time { [Syscall("System.Runtime.GetTime")] get; diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Storage.cs b/src/Neo.SmartContract.Framework/Services/Neo/Storage.cs index 8d516e8a5..e41023bb7 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Storage.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Storage.cs @@ -13,6 +13,15 @@ public static class Storage get; } + /// + /// Returns current read only StorageContext + /// + public static extern StorageContext CurrentReadOnlyContext + { + [Syscall("System.Storage.GetReadOnlyContext")] + get; + } + /// /// Returns the byte[] value corresponding to given byte[] key for Storage context (faster: generates opcode directly) /// @@ -106,6 +115,13 @@ public static class Storage [Syscall("System.Storage.Put")] public static extern void Put(byte[] key, byte[] value); + /// + /// Writes BigInteger value on string key for current Storage context + /// + [Syscall("System.Storage.GetContext")] + [Syscall("System.Storage.PutEx")] + public static extern void PutEx(byte[] key, byte[] value, StorageFlags flags); + /// /// Writes BigInteger value on byte[] key for current Storage context /// @@ -113,6 +129,13 @@ public static class Storage [Syscall("System.Storage.Put")] public static extern void Put(byte[] key, BigInteger value); + /// + /// Writes BigInteger value on string key for current Storage context + /// + [Syscall("System.Storage.GetContext")] + [Syscall("System.Storage.PutEx")] + public static extern void PutEx(byte[] key, BigInteger value, StorageFlags flags); + /// /// Writes string value on byte[] key for current Storage context /// @@ -120,6 +143,13 @@ public static class Storage [Syscall("System.Storage.Put")] public static extern void Put(byte[] key, string value); + /// + /// Writes BigInteger value on string key for current Storage context + /// + [Syscall("System.Storage.GetContext")] + [Syscall("System.Storage.PutEx")] + public static extern void PutEx(byte[] key, string value, StorageFlags flags); + /// /// Writes byte[] value on string key for current Storage context /// @@ -127,6 +157,13 @@ public static class Storage [Syscall("System.Storage.Put")] public static extern void Put(string key, byte[] value); + /// + /// Writes BigInteger value on string key for current Storage context + /// + [Syscall("System.Storage.GetContext")] + [Syscall("System.Storage.PutEx")] + public static extern void PutEx(string key, byte[] value, StorageFlags flags); + /// /// Writes BigInteger value on string key for current Storage context /// @@ -134,6 +171,13 @@ public static class Storage [Syscall("System.Storage.Put")] public static extern void Put(string key, BigInteger value); + /// + /// Writes BigInteger value on string key for current Storage context + /// + [Syscall("System.Storage.GetContext")] + [Syscall("System.Storage.PutEx")] + public static extern void PutEx(string key, BigInteger value, StorageFlags flags); + /// /// Writes string value on string key for current Storage context /// @@ -141,6 +185,13 @@ public static class Storage [Syscall("System.Storage.Put")] public static extern void Put(string key, string value); + /// + /// Writes string value on string key for current Storage context + /// + [Syscall("System.Storage.GetContext")] + [Syscall("System.Storage.PutEx")] + public static extern void PutEx(string key, string value, StorageFlags flags); + /// /// Deletes byte[] key from current Storage context /// diff --git a/src/Neo.SmartContract.Framework/Services/Neo/StorageContext.cs b/src/Neo.SmartContract.Framework/Services/Neo/StorageContext.cs index 9ab00f506..a87ed4e45 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/StorageContext.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/StorageContext.cs @@ -2,5 +2,13 @@ namespace Neo.SmartContract.Framework.Services.Neo { public class StorageContext { + /// + /// Returns current StorageContext as ReadOnly + /// + public extern StorageContext AsReadOnly + { + [Syscall("System.StorageContext.AsReadOnly")] + get; + } } } diff --git a/src/Neo.SmartContract.Framework/Services/Neo/StorageFlags.cs b/src/Neo.SmartContract.Framework/Services/Neo/StorageFlags.cs new file mode 100644 index 000000000..d90f38ce7 --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/Neo/StorageFlags.cs @@ -0,0 +1,11 @@ +using System; + +namespace Neo.SmartContract.Framework.Services.Neo +{ + [Flags] + public enum StorageFlags : byte + { + None = 0x00, + Constant = 0x01 + } +} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Transaction.cs b/src/Neo.SmartContract.Framework/Services/Neo/Transaction.cs index 05f5dd1bb..7bde5847f 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Transaction.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Transaction.cs @@ -1,20 +1,14 @@ namespace Neo.SmartContract.Framework.Services.Neo { - public class Transaction : IScriptContainer + public class Transaction { - public extern byte[] Hash - { - [Syscall("System.Transaction.GetHash")] - get; - } - - public extern byte[] Script - { - [Syscall("Neo.Transaction.GetScript")] - get; - } - - [Syscall("Neo.Transaction.GetAttributes")] - public extern TransactionAttribute[] GetAttributes(); + public readonly byte[] Hash; + public readonly byte Version; + public readonly uint Nonce; + public readonly byte[] Sender; + public readonly long SystemFee; + public readonly long NetworkFee; + public readonly uint ValidUntilBlock; + public readonly byte[] Script; } } diff --git a/src/Neo.SmartContract.Framework/Services/Neo/TransactionAttribute.cs b/src/Neo.SmartContract.Framework/Services/Neo/TransactionAttribute.cs deleted file mode 100644 index 4ea7a2a34..000000000 --- a/src/Neo.SmartContract.Framework/Services/Neo/TransactionAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Neo.SmartContract.Framework.Services.Neo -{ - public class TransactionAttribute : IApiInterface - { - public extern byte Usage - { - [Syscall("Neo.Attribute.GetUsage")] - get; - } - - public extern byte[] Data - { - [Syscall("Neo.Attribute.GetData")] - get; - } - } -} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/TriggerType.cs b/src/Neo.SmartContract.Framework/Services/Neo/TriggerType.cs index 7bf1579ab..fd2a878de 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/TriggerType.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/TriggerType.cs @@ -2,7 +2,9 @@ namespace Neo.SmartContract.Framework.Services.Neo { public enum TriggerType : byte { + System = 0x01, Verification = 0x20, Application = 0x40, + All = System | Verification | Application } } diff --git a/src/Neo.SmartContract.Framework/SmartContract.cs b/src/Neo.SmartContract.Framework/SmartContract.cs index e59f7efc5..0443671da 100644 --- a/src/Neo.SmartContract.Framework/SmartContract.cs +++ b/src/Neo.SmartContract.Framework/SmartContract.cs @@ -2,19 +2,6 @@ namespace Neo.SmartContract.Framework { public class SmartContract { - [Syscall("Neo.Crypto.Hash160")] - protected extern static byte[] Hash160(byte[] data); - [Syscall("Neo.Crypto.Hash256")] - protected extern static byte[] Hash256(byte[] data); - - [Syscall("Neo.Crypto.CheckSig")] - protected extern static bool VerifySignature(byte[] signature, byte[] pubkey); - - [Syscall("System.Crypto.Verify")] - protected extern static bool VerifySignature(byte[] message, byte[] signature, byte[] pubkey); - - [Syscall("Neo.Crypto.CheckMultiSig")] - protected extern static bool VerifySignatures(byte[][] signature, byte[][] pubkey); } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Syscalls.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Syscalls.cs deleted file mode 100644 index c96c0d4c6..000000000 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Syscalls.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace Neo.Compiler.MSIL.TestClasses -{ - public class Contract_Syscalls : SmartContract.Framework.SmartContract - { - public static uint GetInvocationCounter() - { - return SmartContract.Framework.Services.Neo.Runtime.InvocationCounter; - } - - public static int GetNotificationsCount(byte[] hash) - { - var notifications = SmartContract.Framework.Services.Neo.Runtime.GetNotifications(hash); - return notifications.Length; - } - - public static int GetNotifications(byte[] hash) - { - int sum = 0; - var notifications = SmartContract.Framework.Services.Neo.Runtime.GetNotifications(hash); - - for (int x = 0; x < notifications.Length; x++) - { - var notify = notifications[x]; - - if (hash.Length != 0) - { - // Check that the hash is working well - - for (int y = 0; y < notify.ScriptHash.Length; y++) - { - if (notify.ScriptHash[y] != hash[y]) return int.MinValue; - } - } - - sum += (int)notify.State; - } - - return sum; - } - } -} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_appcall.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_appcall.cs index 68c673729..fa2b9323c 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_appcall.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_appcall.cs @@ -1,7 +1,4 @@ using Neo.SmartContract.Framework; -using System; -using System.Collections.Generic; -using System.Text; namespace Neo.Compiler.MSIL.TestClasses { @@ -10,6 +7,7 @@ class Contract_syscall : SmartContract.Framework.SmartContract //这个appcall的地址,在testcase中可以配置 [Appcall("0102030405060708090A0102030405060708090A")] static extern object unittest001(string method, object[] arr); + public static object Main(string method, object[] args) { return unittest001(method, args); diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Appcall.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Appcall.cs index 080de1338..53e455229 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Appcall.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Appcall.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Compiler.MSIL.Utils; using Neo.VM; -using System; namespace Neo.Compiler.MSIL { @@ -11,8 +10,15 @@ public class UnitTest_AppCall [TestMethod] public void Test_Appcall() { + var hash = UInt160.Parse("0102030405060708090A0102030405060708090A"); var testengine = new TestEngine(); - testengine.AddAppcallScript("./TestClasses/Contract1.cs", "0102030405060708090A0102030405060708090A"); + + testengine.Snapshot.Contracts.Add(hash, new Ledger.ContractState() + { + Manifest = new SmartContract.Manifest.ContractManifest(), + Script = testengine.Build("./TestClasses/Contract1.cs").finalNEF + }); + //will appcall 0102030405060708090A0102030405060708090A testengine.AddEntryScript("./TestClasses/Contract_appcall.cs"); diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NULL.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NULL.cs index fd4f9c620..06bf04490 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NULL.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NULL.cs @@ -8,13 +8,21 @@ namespace Neo.Compiler.MSIL [TestClass] public class UnitTest_NULL { + private TestEngine testengine; + + [TestInitialize] + public void Init() + { + testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_NULL.cs"); + } + [TestMethod] public void IsNull() { // True - var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_NULL.cs"); + testengine.Reset(); var result = testengine.ExecuteTestCaseStandard("IsNull", StackItem.Null); var item = result.Pop(); @@ -23,7 +31,7 @@ public void IsNull() // False - testengine.InvocationStack.Clear(); + testengine.Reset(); result = testengine.ExecuteTestCaseStandard("IsNull", new Integer(1)); item = result.Pop(); @@ -36,8 +44,7 @@ public void EqualNull() { // True - var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_NULL.cs"); + testengine.Reset(); var result = testengine.ExecuteTestCaseStandard("EqualNullA", StackItem.Null); var item = result.Pop(); @@ -46,7 +53,7 @@ public void EqualNull() // False - testengine.InvocationStack.Clear(); + testengine.Reset(); result = testengine.ExecuteTestCaseStandard("EqualNullA", new Integer(1)); item = result.Pop(); @@ -55,7 +62,7 @@ public void EqualNull() // True - testengine.InvocationStack.Clear(); + testengine.Reset(); result = testengine.ExecuteTestCaseStandard("EqualNullB", StackItem.Null); item = result.Pop(); @@ -64,7 +71,7 @@ public void EqualNull() // False - testengine.InvocationStack.Clear(); + testengine.Reset(); result = testengine.ExecuteTestCaseStandard("EqualNullB", new Integer(1)); item = result.Pop(); diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Syscalls.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Syscalls.cs deleted file mode 100644 index 0d0f87645..000000000 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Syscalls.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Compiler.MSIL.Utils; -using Neo.VM; -using Neo.VM.Types; - -namespace Neo.Compiler.MSIL -{ - [TestClass] - public class UnitTest_Syscalls - { - private TestEngine _engine; - - [TestInitialize] - public void Init() - { - _engine = new TestEngine(); - _engine.AddEntryScript("./TestClasses/Contract_Syscalls.cs"); - } - - [TestMethod] - public void Test_InvocationCounter() - { - var result = _engine.ExecuteTestCaseStandard("GetInvocationCounter"); - Assert.AreEqual(1, result.Count); - - var item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x01, item.GetBigInteger()); - } - - [TestMethod] - public void Test_GetNotificationsCount() - { - var result = _engine.ExecuteTestCaseStandard("GetNotificationsCount", new ByteArray(UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").ToArray())); - Assert.AreEqual(1, result.Count); - - var item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x01, item.GetBigInteger()); - - result = _engine.ExecuteTestCaseStandard("GetNotificationsCount", new ByteArray(new byte[0])); - Assert.AreEqual(1, result.Count); - - item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x02, item.GetBigInteger()); - } - - [TestMethod] - public void Test_GetNotifications() - { - var result = _engine.ExecuteTestCaseStandard("GetNotifications", new ByteArray(UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").ToArray())); - Assert.AreEqual(1, result.Count); - - var item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x02, item.GetBigInteger()); - - result = _engine.ExecuteTestCaseStandard("GetNotifications", new ByteArray(new byte[0])); - Assert.AreEqual(1, result.Count); - - item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x03, item.GetBigInteger()); - } - } -} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildScript.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildScript.cs index 8b7e16eb9..81b080eb1 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildScript.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildScript.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.IO; -using System.Text; namespace Neo.Compiler.MSIL.Utils { - class BuildScript + public class BuildScript { public bool IsBuild { diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/NeonTestTool.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/NeonTestTool.cs index 50871fed8..1e0be8cef 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/NeonTestTool.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/NeonTestTool.cs @@ -51,8 +51,8 @@ public static BuildScript BuildScript(string filename) var coreDir = Path.GetDirectoryName(typeof(object).Assembly.Location); var srccode = File.ReadAllText(filename); var tree = CSharpSyntaxTree.ParseText(srccode); - var op = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); - var comp = CSharpCompilation.Create("aaa.dll", new[] { tree }, new[] + var op = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release); + var comp = CSharpCompilation.Create("TestContract", new[] { tree }, new[] { MetadataReference.CreateFromFile(Path.Combine(coreDir, "mscorlib.dll")), MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.dll")), diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestDataCache.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestDataCache.cs new file mode 100644 index 000000000..3418aed1f --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestDataCache.cs @@ -0,0 +1,52 @@ +using Neo.IO; +using Neo.IO.Caching; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Compiler.MSIL.Utils +{ + public class TestDataCache : DataCache + where TKey : IEquatable, ISerializable + where TValue : class, ICloneable, ISerializable, new() + { + private readonly Dictionary dic = new Dictionary(); + + public TestDataCache() { } + + public TestDataCache(TKey key, TValue value) + { + dic.Add(key, value); + } + public override void DeleteInternal(TKey key) + { + dic.Remove(key); + } + + protected override void AddInternal(TKey key, TValue value) + { + dic.Add(key, value); + } + + protected override IEnumerable> FindInternal(byte[] key_prefix) + { + return dic.ToList(); + } + + protected override TValue GetInternal(TKey key) + { + if (dic[key] == null) throw new NotImplementedException(); + return dic[key]; + } + + protected override TValue TryGetInternal(TKey key) + { + return dic.TryGetValue(key, out TValue value) ? value : null; + } + + protected override void UpdateInternal(TKey key, TValue value) + { + dic[key] = value; + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs index 78173e66d..00d718bca 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs @@ -1,14 +1,14 @@ -using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.VM; -using Neo.VM.Types; using System; using System.Collections.Generic; -using System.Linq; namespace Neo.Compiler.MSIL.Utils { - class TestEngine : ExecutionEngine + public class TestEngine : ApplicationEngine { public const int MaxStorageKeySize = 64; public const int MaxStorageValueSize = ushort.MaxValue; @@ -17,53 +17,48 @@ class TestEngine : ExecutionEngine public readonly IDictionary Scripts; - public readonly IDictionary Storages; + public BuildScript ScriptEntry { get; private set; } - public BuildScript ScriptEntry - { - get; - private set; - } - - public TestEngine() + public TestEngine(TriggerType trigger = TriggerType.Application, IVerifiable verificable = null, Snapshot snapshot = null) + : base(trigger, verificable, snapshot == null ? new TestSnapshot() : snapshot, 0, true) { Scripts = new Dictionary(); - Storages = new Dictionary(); } - public void AddAppcallScript(string filename, string specScriptID) + public BuildScript Build(string filename) { - byte[] hex = NeonTestTool.HexString2Bytes(specScriptID); - if (hex.Length != 20) - throw new Exception("fail Script ID"); - if (scriptsAll.ContainsKey(filename) == false) { scriptsAll[filename] = NeonTestTool.BuildScript(filename); } - Scripts[specScriptID.ToLower()] = scriptsAll[filename]; + return scriptsAll[filename]; } public void AddEntryScript(string filename) { - if (scriptsAll.ContainsKey(filename) == false) - { - scriptsAll[filename] = NeonTestTool.BuildScript(filename); - } + ScriptEntry = Build(filename); + Reset(); + } - ScriptEntry = scriptsAll[filename]; + public void Reset() + { + this.State = VMState.BREAK; // Required for allow to reuse the same TestEngine + this.InvocationStack.Clear(); + this.LoadScript(ScriptEntry.finalNEF); } public class ContractMethod { - TestEngine engine; - string methodname; + readonly TestEngine engine; + readonly string methodname; + public ContractMethod(TestEngine engine, string methodname) { this.engine = engine; this.methodname = methodname; } + public StackItem Run(params StackItem[] _params) { return this.engine.ExecuteTestCaseStandard(methodname, _params).Pop(); @@ -75,13 +70,11 @@ public ContractMethod GetMethod(string methodname) return new ContractMethod(this, methodname); } - public RandomAccessStack ExecuteTestCaseStandard(string methodname, params StackItem[] _params) + public RandomAccessStack ExecuteTestCaseStandard(string methodname, params StackItem[] args) { //var engine = new ExecutionEngine(); - this.State = VMState.BREAK; // Required for allow to reuse the same TestEngine - this.LoadScript(ScriptEntry.finalNEF); this.InvocationStack.Peek().InstructionPointer = 0; - this.CurrentContext.EvaluationStack.Push(_params); + this.CurrentContext.EvaluationStack.Push(args); this.CurrentContext.EvaluationStack.Push(methodname); while (true) { @@ -98,16 +91,15 @@ public RandomAccessStack ExecuteTestCaseStandard(string methodname, p return this.ResultStack; } - public RandomAccessStack ExecuteTestCase(StackItem[] _params) + public RandomAccessStack ExecuteTestCase(params StackItem[] args) { //var engine = new ExecutionEngine(); - this.LoadScript(ScriptEntry.finalNEF); this.InvocationStack.Peek().InstructionPointer = 0; - if (_params != null) + if (args != null) { - for (var i = _params.Length - 1; i >= 0; i--) + for (var i = args.Length - 1; i >= 0; i--) { - this.CurrentContext.EvaluationStack.Push(_params[i]); + this.CurrentContext.EvaluationStack.Push(args[i]); } } while (true) @@ -128,205 +120,73 @@ public RandomAccessStack ExecuteTestCase(StackItem[] _params) protected override bool OnSysCall(uint method) { - if (method == InteropService.System_Contract_Call) - { - //a appcall - return Contract_Call(); - } - else if (method == InteropService.System_Runtime_Log) - { - return Contract_Log(); - } - else if (method == InteropService.System_Runtime_Notify) - { - return Contract_Log(); - } - // Storages - else if (method == InteropService.System_Storage_GetContext) - { - return Contract_Storage_GetContext(); - } - else if (method == InteropService.System_Storage_GetReadOnlyContext) - { - return Contract_Storage_GetReadOnlyContext(); - } - else if (method == InteropService.System_Storage_Get) - { - return Contract_Storage_Get(); - } - else if (method == InteropService.System_Storage_Delete) - { - return Contract_Storage_Delete(); - } - else if (method == InteropService.System_Storage_Put) - { - return Contract_Storage_Put(); - } - else if (method == InteropService.System_Runtime_GetInvocationCounter) - { - return Runtime_GetInvocationCounter(); - } - else if (method == InteropService.System_Runtime_GetNotifications) - { - return Runtime_GetNotifications(); - } - - return base.OnSysCall(method); - } - - private bool Runtime_GetNotifications() - { - byte[] data = CurrentContext.EvaluationStack.Pop().GetByteArray(); - if ((data.Length != 0) && (data.Length != UInt160.Length)) return false; - - IEnumerable notifications = new NotifyEventArgs[] - { - new NotifyEventArgs(null, UInt160.Zero, new Integer(0x01)), - new NotifyEventArgs(null, UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), new Integer(0x02)) - }; - - if (data.Length == UInt160.Length) // must filter by scriptHash - { - var hash = new UInt160(data); - notifications = notifications.Where(p => p.ScriptHash == hash); - } - - CurrentContext.EvaluationStack.Push(notifications.Select(u => new VM.Types.Array(new StackItem[] { u.ScriptHash.ToArray(), u.State })).ToArray()); - return true; - } - - private bool Runtime_GetInvocationCounter() - { - CurrentContext.EvaluationStack.Push(0x01); - return true; - } - - #region Storage - - private bool Contract_Storage_GetContext() - { - CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new TestStorageContext - { - ScriptHash = CurrentContext.ScriptHash(), - IsReadOnly = false - })); - return true; - } - - private bool Contract_Storage_GetReadOnlyContext() - { - CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new TestStorageContext - { - ScriptHash = CurrentContext.ScriptHash(), - IsReadOnly = true - })); - return true; - } - - private bool Contract_Storage_Delete() - { - if (CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - TestStorageContext context = _interface.GetInterface(); - if (context.IsReadOnly) return false; - - StorageKey key = new StorageKey - { - ScriptHash = context.ScriptHash, - Key = CurrentContext.EvaluationStack.Pop().GetByteArray() - }; - if (Storages.TryGetValue(key, out var item) && item.IsConstant == true) return false; - Storages.Remove(key); - return true; - } - return false; - } - - private bool Contract_Storage_Get() - { - if (CurrentContext.EvaluationStack.Pop() is InteropInterface _interface) - { - TestStorageContext context = _interface.GetInterface(); - byte[] key = CurrentContext.EvaluationStack.Pop().GetByteArray(); - - if (Storages.TryGetValue(new StorageKey - { - ScriptHash = context.ScriptHash, - Key = key - }, out var item)) - { - CurrentContext.EvaluationStack.Push(item.Value); - } - else - { - CurrentContext.EvaluationStack.Push(new byte[0]); - } - return true; - } - return false; - } - - private bool Contract_Storage_Put() - { - if (!(CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)) - return false; - TestStorageContext context = _interface.GetInterface(); - byte[] key = CurrentContext.EvaluationStack.Pop().GetByteArray(); - byte[] value = CurrentContext.EvaluationStack.Pop().GetByteArray(); - return PutEx(context, key, value, StorageFlags.None); - } - - private bool PutEx(TestStorageContext context, byte[] key, byte[] value, StorageFlags flags) - { - if (key.Length > MaxStorageKeySize) return false; - if (value.Length > MaxStorageValueSize) return false; - if (context.IsReadOnly) return false; - - StorageKey skey = new StorageKey - { - ScriptHash = context.ScriptHash, - Key = key - }; - - if (Storages.TryGetValue(skey, out var item) && item.IsConstant == true) return false; - - if (value.Length == 0 && !flags.HasFlag(StorageFlags.Constant)) + if ( + // Native + method == InteropService.Neo_Native_Deploy || + // Account + method == InteropService.Neo_Account_IsStandard || + // Storages + method == InteropService.System_Storage_GetContext || + method == InteropService.System_Storage_GetReadOnlyContext || + method == InteropService.System_Storage_GetReadOnlyContext || + method == InteropService.System_StorageContext_AsReadOnly || + method == InteropService.System_Storage_Get || + method == InteropService.System_Storage_Delete || + method == InteropService.System_Storage_Put || + // Enumerator + method == InteropService.Neo_Enumerator_Concat || + method == InteropService.Neo_Enumerator_Create || + method == InteropService.Neo_Enumerator_Next || + method == InteropService.Neo_Enumerator_Value || + // Iterator + method == InteropService.Neo_Iterator_Concat || + method == InteropService.Neo_Iterator_Create || + method == InteropService.Neo_Iterator_Key || + method == InteropService.Neo_Iterator_Keys || + method == InteropService.Neo_Iterator_Values || + // ExecutionEngine + method == InteropService.System_ExecutionEngine_GetCallingScriptHash || + method == InteropService.System_ExecutionEngine_GetEntryScriptHash || + method == InteropService.System_ExecutionEngine_GetExecutingScriptHash || + method == InteropService.System_ExecutionEngine_GetScriptContainer || + // Runtime + method == InteropService.System_Runtime_CheckWitness || + method == InteropService.System_Runtime_GetNotifications || + method == InteropService.System_Runtime_GetInvocationCounter || + method == InteropService.System_Runtime_GetTrigger || + method == InteropService.System_Runtime_GetTime || + method == InteropService.System_Runtime_Platform || + method == InteropService.System_Runtime_Log || + method == InteropService.System_Runtime_Notify || + // Json + method == InteropService.Neo_Json_Deserialize || + method == InteropService.Neo_Json_Serialize || + // Crypto + method == InteropService.Neo_Crypto_CheckSig || + method == InteropService.System_Crypto_Verify || + method == InteropService.Neo_Crypto_CheckMultiSig || + // Blockchain + method == InteropService.System_Blockchain_GetHeight || + method == InteropService.System_Blockchain_GetBlock || + method == InteropService.System_Blockchain_GetContract || + method == InteropService.System_Blockchain_GetTransaction || + method == InteropService.System_Blockchain_GetTransactionHeight || + method == InteropService.System_Blockchain_GetTransactionFromBlock || + // Native + method == NativeContract.NEO.ServiceName.ToInteropMethodHash() || + method == NativeContract.GAS.ServiceName.ToInteropMethodHash() || + method == NativeContract.Policy.ServiceName.ToInteropMethodHash() || + // Contract + method == InteropService.System_Contract_Call || + method == InteropService.System_Contract_Destroy || + method == InteropService.Neo_Contract_Create || + method == InteropService.Neo_Contract_Update + ) { - // If put 'value' is empty (and non-const), we remove it (implicit `Storage.Delete`) - Storages.Remove(skey); + return base.OnSysCall(method); } - else - { - item = Storages[skey] = new StorageItem(); - item.Value = value; - item.IsConstant = flags.HasFlag(StorageFlags.Constant); - } - return true; - } - - #endregion - private bool Contract_Call() - { - StackItem item0 = this.CurrentContext.EvaluationStack.Pop(); - var contractid = item0.GetByteArray(); - var contractkey = NeonTestTool.Bytes2HexString(contractid.Reverse().ToArray()).ToLower(); - var contract = Scripts[contractkey]; - - if (contract is null) return false; - StackItem item1 = this.CurrentContext.EvaluationStack.Pop(); - StackItem item2 = this.CurrentContext.EvaluationStack.Pop(); - ExecutionContext context_new = this.LoadScript(contract.finalNEF, 1); - context_new.EvaluationStack.Push(item2); - context_new.EvaluationStack.Push(item1); - return true; - } - - private bool Contract_Log() - { - StackItem item0 = this.CurrentContext.EvaluationStack.Pop(); - DumpItem(item0); - return true; + throw new Exception($"Syscall not found: {method.ToString("X2")} (using base call)"); } public bool CheckAsciiChar(string s) diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestMetaDataCache.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestMetaDataCache.cs new file mode 100644 index 000000000..42c4655fc --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestMetaDataCache.cs @@ -0,0 +1,26 @@ +using Neo.IO; +using Neo.IO.Caching; + +namespace Neo.Compiler.MSIL.Utils +{ + 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 null; + } + + protected override void UpdateInternal(T item) + { + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestSnapshot.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestSnapshot.cs new file mode 100644 index 000000000..da339f414 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestSnapshot.cs @@ -0,0 +1,42 @@ +using Neo.IO.Caching; +using Neo.IO.Wrappers; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; + +namespace Neo.Compiler.MSIL.Utils +{ + public class TestSnapshot : Snapshot + { + private DataCache _Blocks = new TestDataCache(); + private DataCache _Transactions = new TestDataCache(); + private DataCache _Contracts = new TestDataCache(); + private DataCache _Storages = new TestDataCache(); + private DataCache _HeaderHashList = new TestDataCache(); + private MetaDataCache _BlockHashIndex = new TestMetaDataCache(); + private MetaDataCache _HeaderHashIndex = new TestMetaDataCache(); + + public override DataCache Blocks => _Blocks; + + public override DataCache Transactions => _Transactions; + + public override DataCache Contracts => _Contracts; + + public override DataCache Storages => _Storages; + + public override DataCache HeaderHashList => _HeaderHashList; + + public override MetaDataCache BlockHashIndex => _BlockHashIndex; + + public override MetaDataCache HeaderHashIndex => _HeaderHashIndex; + + /// + /// Set Persisting block for unit test + /// + /// Block + public void SetPersistingBlock(Block block) + { + this.GetType().GetProperty("PersistingBlock").SetValue(this, block); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Neo.SmartContract.Framework.UnitTests.csproj b/tests/Neo.SmartContract.Framework.UnitTests/Neo.SmartContract.Framework.UnitTests.csproj index e441120b6..fd3a9f671 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Neo.SmartContract.Framework.UnitTests.csproj +++ b/tests/Neo.SmartContract.Framework.UnitTests/Neo.SmartContract.Framework.UnitTests.csproj @@ -6,14 +6,21 @@ - - - + + + + - + + + + + + PreserveNewest + diff --git a/tests/Neo.SmartContract.Framework.UnitTests/UT_OpcodeTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/OpcodeTest.cs similarity index 96% rename from tests/Neo.SmartContract.Framework.UnitTests/UT_OpcodeTest.cs rename to tests/Neo.SmartContract.Framework.UnitTests/OpcodeTest.cs index 70652a4eb..2965e5e6c 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/UT_OpcodeTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/OpcodeTest.cs @@ -7,7 +7,7 @@ namespace Neo.SmartContract.Framework.UnitTests { [TestClass] - public class UT_OpcodeTest + public class OpcodeTest { [TestMethod] public void TestAllOpcodes() diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/AccountTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/AccountTest.cs new file mode 100644 index 000000000..d285e9b20 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/AccountTest.cs @@ -0,0 +1,63 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.Ledger; +using Neo.VM.Types; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class AccountTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(); + _engine.AddEntryScript("./TestClasses/Contract_Account.cs"); + } + + [TestMethod] + public void Test_AccountIsStandard() + { + var noStandard = new byte[20] + { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF + }; + + _engine.Snapshot.Contracts.Add(new UInt160(noStandard), new ContractState() + { + Script = new byte[0] { } + }); + + // Empty + + var result = _engine.ExecuteTestCaseStandard("AccountIsStandard", new ByteArray(new byte[0])); + Assert.AreEqual(VM.VMState.FAULT, _engine.State); + Assert.AreEqual(0, result.Count); + + // Standard + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("AccountIsStandard", new ByteArray(new byte[20])); + Assert.AreEqual(VM.VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.AreEqual(true, item.GetBoolean()); + + // No standard + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("AccountIsStandard", new ByteArray(noStandard)); + Assert.AreEqual(VM.VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.AreEqual(false, item.GetBoolean()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/BlockchainTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/BlockchainTest.cs new file mode 100644 index 000000000..44dad0a85 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/BlockchainTest.cs @@ -0,0 +1,393 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.Ledger; +using Neo.Persistence; +using Neo.VM; +using Neo.VM.Types; +using System.Linq; +using System.Numerics; +using System.Text; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class BlockchainTest + { + private Network.P2P.Payloads.Block _block; + private TestEngine _engine; + private Store _store; + + [TestInitialize] + public void Init() + { + _store = TestBlockchain.GetStore(); + var snapshot = _store.GetSnapshot(); + + _block = Blockchain.GenesisBlock; + _engine = new TestEngine(snapshot: snapshot); + _engine.AddEntryScript("./TestClasses/Contract_Blockchain.cs"); + } + + [TestMethod] + public void Test_GetHeight() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("GetHeight"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(_block.Index, item.GetBigInteger()); + } + + [TestMethod] + public void Test_GetTransactionHeight() + { + // Not found + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("GetTransactionHeight", new ByteArray(UInt256.Zero.ToArray())); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(BigInteger.MinusOne, item.GetBigInteger()); + + // Found + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("GetTransactionHeight", new ByteArray(_block.Transactions[0].Hash.ToArray())); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(_block.Index, item.GetBigInteger()); + } + + [TestMethod] + public void Test_GetBlockByHash() + { + Test_GetBlock("GetBlockByHash", new ByteArray(_block.Hash.ToArray()), new ByteArray(UInt256.Zero.ToArray())); + } + + [TestMethod] + public void Test_GetTxByHash() + { + Test_GetTransaction("GetTxByHash", new StackItem[] { new ByteArray(_block.Transactions[0].Hash.ToArray()) }, + new StackItem[] { new ByteArray(UInt256.Zero.ToArray()) }, + true); + } + + [TestMethod] + public void Test_GetTxByBlockIndex() + { + Test_GetTransaction("GetTxByBlockIndex", new StackItem[] { + new Integer(_block.Index), new Integer(0) }, + new StackItem[] { new Integer(_block.Index), new Integer(_block.Transactions.Length + 1) }, + false); + } + + [TestMethod] + public void Test_GetTxByBlockHash() + { + Test_GetTransaction("GetTxByBlockHash", new StackItem[] { + new ByteArray(_block.Hash.ToArray()), new Integer(0) }, + new StackItem[] { new ByteArray(_block.Hash.ToArray()), new Integer(_block.Transactions.Length + 1) }, + false); + } + + public void Test_GetTransaction(string method, StackItem[] foundArgs, StackItem[] notFoundArgs, bool expectedNullAsNotFound) + { + // Not found + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard(method, Concat(notFoundArgs, new ByteArray(new byte[0]))); + + if (expectedNullAsNotFound) + { + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + Assert.IsInstanceOfType(result.Pop(), typeof(Null)); + } + else + { + Assert.AreEqual(VMState.FAULT, _engine.State); + Assert.AreEqual(0, result.Count); + } + + var tx = _block.Transactions[0]; + + // Hash + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteArray(Encoding.UTF8.GetBytes("Hash")))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + CollectionAssert.AreEqual(tx.Hash.ToArray(), item.GetByteArray()); + + // NetworkFee + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteArray(Encoding.UTF8.GetBytes("NetworkFee")))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(tx.NetworkFee, item.GetBigInteger()); + + // Nonce + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteArray(Encoding.UTF8.GetBytes("Nonce")))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(tx.Nonce, item.GetBigInteger()); + + // SystemFee + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteArray(Encoding.UTF8.GetBytes("SystemFee")))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(tx.SystemFee, item.GetBigInteger()); + + // ValidUntilBlock + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteArray(Encoding.UTF8.GetBytes("ValidUntilBlock")))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(tx.ValidUntilBlock, item.GetBigInteger()); + + // Version + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteArray(Encoding.UTF8.GetBytes("Version")))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(tx.Version, item.GetBigInteger()); + + // Script + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteArray(Encoding.UTF8.GetBytes("Script")))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + CollectionAssert.AreEqual(tx.Script, item.GetByteArray()); + + // Sender + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteArray(Encoding.UTF8.GetBytes("Sender")))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + CollectionAssert.AreEqual(tx.Sender.ToArray(), item.GetByteArray()); + } + + private StackItem[] Concat(StackItem[] a, ByteArray b) + { + return a.Concat(new StackItem[] { b }).ToArray(); + } + + [TestMethod] + public void Test_GetBlockByIndex() + { + Test_GetBlock("GetBlockByIndex", new Integer(_block.Index), new Integer(_block.Index + 100)); + } + + public void Test_GetBlock(string method, StackItem foundArg, StackItem notFoundArg) + { + // Not found + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard(method, notFoundArg, new ByteArray(new byte[0])); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Null)); + + // Hash + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("Hash"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + CollectionAssert.AreEqual(_block.Hash.ToArray(), item.GetByteArray()); + + // Index + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("Index"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(_block.Index, item.GetBigInteger()); + + // MerkleRoot + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("MerkleRoot"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + CollectionAssert.AreEqual(_block.MerkleRoot.ToArray(), item.GetByteArray()); + + // NextConsensus + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("NextConsensus"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + CollectionAssert.AreEqual(_block.NextConsensus.ToArray(), item.GetByteArray()); + + // PrevHash + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("PrevHash"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + CollectionAssert.AreEqual(_block.PrevHash.ToArray(), item.GetByteArray()); + + // Timestamp + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("Timestamp"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(_block.Timestamp, item.GetBigInteger()); + + // TransactionsCount + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("TransactionsCount"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(_block.Transactions.Length, item.GetBigInteger()); + + // Version + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("Version"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(_block.Version, item.GetBigInteger()); + + // Uknown property + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteArray(Encoding.UTF8.GetBytes("ASD"))); + Assert.AreEqual(VMState.FAULT, _engine.State); + } + + [TestMethod] + public void GetContract() + { + var contract = new ContractState() + { + Script = new byte[] { 0x01, 0x02, 0x03 }, + Manifest = new Manifest.ContractManifest() + { + Features = Manifest.ContractFeatures.HasStorage + } + }; + _engine.Snapshot.Contracts.GetOrAdd(contract.ScriptHash, () => contract); + + // Not found + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("GetContract", new ByteArray(UInt160.Zero.ToArray()), new ByteArray(new byte[0])); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Null)); + + // Found + HasStorage + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("GetContract", new ByteArray(contract.ScriptHash.ToArray()), new ByteArray(Encoding.UTF8.GetBytes("HasStorage"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(VM.Types.Boolean)); + Assert.AreEqual(contract.HasStorage, item.GetBoolean()); + + // Found + IsPayable + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("GetContract", new ByteArray(contract.ScriptHash.ToArray()), new ByteArray(Encoding.UTF8.GetBytes("IsPayable"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(VM.Types.Boolean)); + Assert.AreEqual(contract.Payable, item.GetBoolean()); + + // Found + IsPayable + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("GetContract", new ByteArray(contract.ScriptHash.ToArray()), new ByteArray(Encoding.UTF8.GetBytes("Script"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(VM.Types.ByteArray)); + CollectionAssert.AreEqual(contract.Script, item.GetByteArray()); + + // Found + Uknown property + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("GetContract", new ByteArray(contract.ScriptHash.ToArray()), new ByteArray(Encoding.UTF8.GetBytes("ASD"))); + Assert.AreEqual(VMState.FAULT, _engine.State); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs new file mode 100644 index 000000000..4e4db05da --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs @@ -0,0 +1,182 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.SmartContract.Manifest; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class ContractTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(); + _engine.AddEntryScript("./TestClasses/Contract_Contract.cs"); + } + + [TestMethod] + public void Test_CreateCallDestroy() + { + // Create + + byte[] script; + using (var scriptBuilder = new ScriptBuilder()) + { + // Drop arguments + + scriptBuilder.Emit(VM.OpCode.DROP); + scriptBuilder.Emit(VM.OpCode.DROP); + + // Return 123 + + scriptBuilder.EmitPush(123); + script = scriptBuilder.ToArray(); + } + + var manifest = ContractManifest.CreateDefault(script.ToScriptHash()); + + // Check first + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("Call", manifest.Hash.ToArray()); + Assert.AreEqual(VMState.FAULT, _engine.State); + + // Create + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Create", script, manifest.ToJson().ToString()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(InteropInterface)); + Assert.AreEqual(manifest.Hash, + ((InteropInterface)item).GetInterface().ScriptHash); + + // Call + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Call", manifest.Hash.ToArray(), Null.Null, Null.Null); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual(123, item.GetBigInteger()); + + // Destroy + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Destroy"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual(0, item.GetByteLength()); + + // Check again for failures + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Call", manifest.Hash.ToArray()); + Assert.AreEqual(VMState.FAULT, _engine.State); + } + + [TestMethod] + public void Test_Update() + { + // Create + + byte[] scriptUpdate; + using (var scriptBuilder = new ScriptBuilder()) + { + // Drop arguments + + scriptBuilder.Emit(VM.OpCode.DROP); + scriptBuilder.Emit(VM.OpCode.DROP); + + // Return 124 + + scriptBuilder.EmitPush(123); + scriptBuilder.Emit(VM.OpCode.INC); + scriptUpdate = scriptBuilder.ToArray(); + } + + var manifestUpdate = ContractManifest.CreateDefault(scriptUpdate.ToScriptHash()); + + byte[] script; + using (var scriptBuilder = new ScriptBuilder()) + { + // Drop arguments + + scriptBuilder.Emit(VM.OpCode.DROP); + scriptBuilder.Emit(VM.OpCode.DROP); + + // Return 123 + + scriptBuilder.EmitPush(123); + + // Update + + scriptBuilder.EmitSysCall(InteropService.Neo_Contract_Update, scriptUpdate, manifestUpdate.ToJson().ToString()); + script = scriptBuilder.ToArray(); + } + + var manifest = ContractManifest.CreateDefault(script.ToScriptHash()); + + // Check first + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("Call", manifest.Hash.ToArray()); + Assert.AreEqual(VMState.FAULT, _engine.State); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Call", manifestUpdate.Hash.ToArray()); + Assert.AreEqual(VMState.FAULT, _engine.State); + + // Create + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Create", script, manifest.ToJson().ToString()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(InteropInterface)); + Assert.AreEqual(manifest.Hash, + ((InteropInterface)item).GetInterface().ScriptHash); + + // Call & Update + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Call", manifest.Hash.ToArray(), Null.Null, Null.Null); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual(123, item.GetBigInteger()); + + // Call Again + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Call", manifestUpdate.Hash.ToArray(), Null.Null, Null.Null); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(124, item.GetBigInteger()); + + // Check again for failures + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Call", manifest.Hash.ToArray()); + Assert.AreEqual(VMState.FAULT, _engine.State); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/CryptoTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/CryptoTest.cs new file mode 100644 index 000000000..4f06676a1 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/CryptoTest.cs @@ -0,0 +1,147 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.Cryptography; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System.Linq; +using System.Security.Cryptography; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class CryptoTest + { + private KeyPair _key = null; + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(TriggerType.Application, new Transaction() + { + Attributes = new TransactionAttribute[0], + Cosigners = new Cosigner[0], + Script = new byte[0], + Sender = UInt160.Zero, + Witnesses = new Witness[0], + NetworkFee = 1, + Nonce = 2, + SystemFee = 3, + ValidUntilBlock = 4, + Version = 5 + }); + _engine.AddEntryScript("./TestClasses/Contract_Crypto.cs"); + _key = GenerateKey(32); + } + + public static KeyPair GenerateKey(int privateKeyLength) + { + byte[] privateKey = new byte[privateKeyLength]; + using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(privateKey); + } + return new KeyPair(privateKey); + } + + [TestMethod] + public void Test_VerifySignature() + { + byte[] signature = Crypto.Default.Sign(_engine.ScriptContainer.GetHashData(), + _key.PrivateKey, _key.PublicKey.EncodePoint(false).Skip(1).ToArray()); + + // False + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("VerifySignature", + new ByteArray(_key.PublicKey.EncodePoint(true)), new ByteArray(new byte[64])); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.IsFalse(item.GetBoolean()); + + // True + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("VerifySignature", + new ByteArray(_key.PublicKey.EncodePoint(true)), new ByteArray(signature)); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.IsTrue(item.GetBoolean()); + } + + [TestMethod] + public void Test_VerifySignatures() + { + byte[] signature = Crypto.Default.Sign(_engine.ScriptContainer.GetHashData(), + _key.PrivateKey, _key.PublicKey.EncodePoint(false).Skip(1).ToArray()); + + // False + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("VerifySignatures", + new Array(new StackItem[] { new ByteArray(_key.PublicKey.EncodePoint(true)) }), + new Array(new StackItem[] { new ByteArray(new byte[64]) })); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.IsFalse(item.GetBoolean()); + + // True + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("VerifySignatures", + new Array(new StackItem[] { new ByteArray(_key.PublicKey.EncodePoint(true)) }), + new Array(new StackItem[] { new ByteArray(signature) })); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.IsTrue(item.GetBoolean()); + } + + [TestMethod] + public void Test_VerifySignatureWithMessage() + { + byte[] signature = Crypto.Default.Sign(_engine.ScriptContainer.GetHashData(), + _key.PrivateKey, _key.PublicKey.EncodePoint(false).Skip(1).ToArray()); + + // False + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("VerifySignatureWithMessage", + new ByteArray(new byte[0]), + new ByteArray(_key.PublicKey.EncodePoint(true)), new ByteArray(signature)); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.IsFalse(item.GetBoolean()); + + // True + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("VerifySignatureWithMessage", + new ByteArray(_engine.ScriptContainer.GetHashData()), + new ByteArray(_key.PublicKey.EncodePoint(true)), new ByteArray(signature)); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.IsTrue(item.GetBoolean()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs new file mode 100644 index 000000000..1d939fb8e --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs @@ -0,0 +1,93 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class EnumeratorTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(); + _engine.AddEntryScript("./TestClasses/Contract_Enumerator.cs"); + } + + [TestMethod] + public void TestNext() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("TestNext", new Array(new StackItem[] { 1, 2, 3 })); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetBigInteger()); + } + + [TestMethod] + public void TestConcat() + { + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("TestConcat", + new Array(new StackItem[] { 1, 2, 3 }), + new Array(new StackItem[] { 4, 5, 6 }) + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(21, item.GetBigInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcat", + new Array(new StackItem[] { 1, 2, 3 }), + new Array() + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetBigInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcat", + new Array(), + new Array(new StackItem[] { 4, 5, 6 }) + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(15, item.GetBigInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcat", + new Array(), + new Array() + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual(0, item.GetByteLength()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs new file mode 100644 index 000000000..e938ad9ed --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs @@ -0,0 +1,264 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class IteratorTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(); + _engine.AddEntryScript("./TestClasses/Contract_Iterator.cs"); + } + + [TestMethod] + public void TestNextArray() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("TestNextArray", new Array(new StackItem[] { 1, 2, 3 })); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetBigInteger()); + } + + [TestMethod] + public void TestConcatArray() + { + var a = new Array(new StackItem[] { 1, 2, 3 }); + var b = new Array(new StackItem[] { 4, 5, 6 }); + + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("TestConcatArray", a, b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(21, item.GetBigInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatArray", a, new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetBigInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatArray", new Array(), b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(15, item.GetBigInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatArray", new Array(), new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual(0, item.GetByteLength()); + } + + [TestMethod] + public void TestConcatMap() + { + var a = new Map + { + [new Integer(1)] = new Integer(2), + [new Integer(3)] = new Integer(4) + }; + + var b = new Map + { + [new Integer(5)] = new Integer(6), + [new Integer(7)] = new Integer(8) + }; + + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("TestConcatMap", a, b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(36, item.GetBigInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatMap", a, new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(10, item.GetBigInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatMap", new Array(), b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(26, item.GetBigInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatMap", new Array(), new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual(0, item.GetByteLength()); + } + + [TestMethod] + public void TestConcatKeys() + { + var a = new Map + { + [new Integer(1)] = new Integer(2), + [new Integer(3)] = new Integer(4) + }; + + var b = new Map + { + [new Integer(5)] = new Integer(6), + [new Integer(7)] = new Integer(8) + }; + + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("TestConcatKeys", a, b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(16, item.GetBigInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatKeys", a, new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(4, item.GetBigInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatKeys", new Array(), b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(12, item.GetBigInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatKeys", new Array(), new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual(0, item.GetByteLength()); + } + + [TestMethod] + public void TestConcatValues() + { + var a = new Map + { + [new Integer(1)] = new Integer(2), + [new Integer(3)] = new Integer(4) + }; + + var b = new Map + { + [new Integer(5)] = new Integer(6), + [new Integer(7)] = new Integer(8) + }; + + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("TestConcatValues", a, b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(20, item.GetBigInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatValues", a, new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetBigInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatValues", new Array(), b); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(14, item.GetBigInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("TestConcatValues", new Array(), new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual(0, item.GetByteLength()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/JsonTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/JsonTest.cs new file mode 100644 index 000000000..56f72d890 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/JsonTest.cs @@ -0,0 +1,70 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.VM; +using Neo.VM.Types; +using System.Text; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class JsonTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(); + _engine.AddEntryScript("./TestClasses/Contract_Json.cs"); + } + + [TestMethod] + public void Test_SerializeDeserialize() + { + // Empty Serialize + + var result = _engine.ExecuteTestCaseStandard("Serialize"); + Assert.AreEqual(VMState.FAULT, _engine.State); + Assert.AreEqual(0, result.Count); + + // Empty Serialize + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Deserialize"); + Assert.AreEqual(VMState.FAULT, _engine.State); + Assert.AreEqual(0, result.Count); + + // Serialize + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Serialize", new Array(new StackItem[]{ + StackItem.Null, new Boolean(true), new ByteArray(Encoding.ASCII.GetBytes("asd")) + })); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual("[null,true,\"asd\"]", item.GetString()); + + // Deserialize + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("Deserialize", new ByteArray(Encoding.ASCII.GetBytes("[null,true,\"asd\"]"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Array)); + + var entry = ((Array)item)[0]; + Assert.IsInstanceOfType(entry, typeof(Null)); + entry = ((Array)item)[1]; + Assert.IsInstanceOfType(entry, typeof(Boolean)); + Assert.AreEqual(true, entry.GetBoolean()); + entry = ((Array)item)[2]; + Assert.IsInstanceOfType(entry, typeof(ByteArray)); + Assert.AreEqual("asd", entry.GetString()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/NativeTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/NativeTest.cs new file mode 100644 index 000000000..921606371 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/NativeTest.cs @@ -0,0 +1,100 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class NativeTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(); + _engine.AddEntryScript("./TestClasses/Contract_Native.cs"); + ((TestSnapshot)_engine.Snapshot).SetPersistingBlock(new Network.P2P.Payloads.Block() + { + Index = 0, + ConsensusData = new Network.P2P.Payloads.ConsensusData(), + Transactions = new Network.P2P.Payloads.Transaction[0], + Witness = new Network.P2P.Payloads.Witness() + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + }, + NextConsensus = UInt160.Zero, + MerkleRoot = UInt256.Zero, + PrevHash = UInt256.Zero + }); + + // Deploy native contracts + + using (var script = new ScriptBuilder()) + { + script.EmitSysCall(InteropService.Neo_Native_Deploy); + _engine.LoadScript(script.ToArray()); + _engine.Execute(); + } + } + + [TestMethod] + public void Test_NEO() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("NEO_Decimals"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0, item.GetBigInteger()); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("NEO_Name"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual("NEO", item.GetString()); + } + + [TestMethod] + public void Test_GAS() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("GAS_Decimals"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(8, item.GetBigInteger()); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("GAS_Name"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual("GAS", item.GetString()); + } + + [TestMethod] + public void Test_Policy() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("Policy_GetFeePerByte"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(1000L, item.GetBigInteger()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/RuntimeTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/RuntimeTest.cs new file mode 100644 index 000000000..66bd0e8a4 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/RuntimeTest.cs @@ -0,0 +1,256 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using NEOSmartContract = Neo.SmartContract; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class RuntimeTest + { + class DummyVerificable : IVerifiable + { + public Witness[] Witnesses { get; set; } + + public int Size => 0; + + public void Deserialize(BinaryReader reader) { } + + public void DeserializeUnsigned(BinaryReader reader) { } + + public UInt160[] GetScriptHashesForVerifying(Snapshot snapshot) + { + return new UInt160[] + { + UInt160.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") + }; + } + + public void Serialize(BinaryWriter writer) { } + + public void SerializeUnsigned(BinaryWriter writer) { } + } + + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(TriggerType.Application, new DummyVerificable()); + _engine.AddEntryScript("./TestClasses/Contract_Runtime.cs"); + } + + [TestMethod] + public void Test_InvocationCounter() + { + // Build script + + _engine.Reset(); + + var contract = _engine.EntryScriptHash; + _engine.Snapshot.Contracts.Add(contract, new Ledger.ContractState() + { + Script = _engine.InvocationStack.Peek(0).Script, + Manifest = new NEOSmartContract.Manifest.ContractManifest() + { + } + }); + + _engine.InvocationStack.Clear(); + + using (ScriptBuilder sb = new ScriptBuilder()) + { + // First + sb.EmitAppCall(contract, "GetInvocationCounter"); + // Second + sb.EmitAppCall(contract, "GetInvocationCounter"); + + _engine.LoadScript(sb.ToArray()); + } + + // Check + + Assert.AreEqual(VMState.HALT, _engine.Execute()); + Assert.AreEqual(2, _engine.ResultStack.Count); + + var item = _engine.ResultStack.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0x02, item.GetBigInteger()); + + item = _engine.ResultStack.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0x01, item.GetBigInteger()); + } + + [TestMethod] + public void Test_Time() + { + ((TestSnapshot)_engine.Snapshot).SetPersistingBlock(new Block() + { + Index = 123, + Timestamp = 1234, + ConsensusData = new ConsensusData(), + Transactions = new Transaction[0], + Witness = new Witness() + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + }, + NextConsensus = UInt160.Zero, + MerkleRoot = UInt256.Zero, + PrevHash = UInt256.Zero + }); + + var result = _engine.ExecuteTestCaseStandard("GetTime"); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(1234, item.GetBigInteger()); + } + + [TestMethod] + public void Test_Platform() + { + var result = _engine.ExecuteTestCaseStandard("GetPlatform"); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual("NEO", item.GetString()); + } + + [TestMethod] + public void Test_Trigger() + { + var result = _engine.ExecuteTestCaseStandard("GetTrigger"); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual((byte)TriggerType.Application, item.GetBigInteger()); + } + + [TestMethod] + public void Test_Log() + { + var list = new List(); + var method = new EventHandler((s, e) => list.Add(e)); + + ApplicationEngine.Log += method; + var result = _engine.ExecuteTestCaseStandard("Log", new ByteArray(Encoding.UTF8.GetBytes("LogTest"))); + ApplicationEngine.Log -= method; + + Assert.AreEqual(1, list.Count); + + var item = list[0]; + Assert.AreEqual("LogTest", item.Message); + } + + [TestMethod] + public void Test_CheckWitness() + { + // True + + var result = _engine.ExecuteTestCaseStandard("CheckWitness", new ByteArray( + new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, } + )); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(VM.Types.Boolean)); + Assert.IsTrue(item.GetBoolean()); + + // False + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("CheckWitness", new ByteArray( + new byte[] { 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, } + )); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(VM.Types.Boolean)); + Assert.IsFalse(item.GetBoolean()); + } + + [TestMethod] + public void Test_Notify() + { + var list = new List(); + var method = new EventHandler((s, e) => list.Add(e)); + + ApplicationEngine.Notify += method; + var result = _engine.ExecuteTestCaseStandard("Notify", new ByteArray(Encoding.UTF8.GetBytes("NotifyTest"))); + ApplicationEngine.Notify -= method; + + Assert.AreEqual(1, list.Count); + + var item = list[0]; + var array = item.State; + Assert.IsInstanceOfType(array, typeof(VM.Types.Array)); + Assert.AreEqual("NotifyTest", ((VM.Types.Array)array)[0].GetString()); + } + + [TestMethod] + public void Test_GetNotificationsCount() + { + var notifications = ((List)_engine.Notifications); + notifications.Clear(); + notifications.AddRange(new NotifyEventArgs[] + { + new NotifyEventArgs(null, UInt160.Zero, new Integer(0x01)), + new NotifyEventArgs(null, UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), new Integer(0x02)) + }); + + var result = _engine.ExecuteTestCaseStandard("GetNotificationsCount", new ByteArray(UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").ToArray())); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0x01, item.GetBigInteger()); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("GetNotificationsCount", StackItem.Null); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0x02, item.GetBigInteger()); + } + + [TestMethod] + public void Test_GetNotifications() + { + var notifications = ((List)_engine.Notifications); + notifications.Clear(); + notifications.AddRange(new NotifyEventArgs[] + { + new NotifyEventArgs(null, UInt160.Zero, new Integer(0x01)), + new NotifyEventArgs(null, UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), new Integer(0x02)) + }); + + var result = _engine.ExecuteTestCaseStandard("GetNotifications", new ByteArray(UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").ToArray())); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0x02, item.GetBigInteger()); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("GetAllNotifications"); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0x03, item.GetBigInteger()); + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_StorageMap.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StorageTest.cs similarity index 54% rename from tests/Neo.Compiler.MSIL.UnitTests/UnitTest_StorageMap.cs rename to tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StorageTest.cs index 47a8f79be..bbd82b177 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_StorageMap.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StorageTest.cs @@ -1,25 +1,28 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Compiler.MSIL.Utils; using Neo.VM.Types; +using System; +using System.Collections.Generic; using System.Linq; -namespace Neo.Compiler.MSIL +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo { [TestClass] - public class UnitTest_StorageMap + public class StorageTest { private void Put(TestEngine testengine, string method, byte[] prefix, byte[] key, byte[] value) { var result = testengine.ExecuteTestCaseStandard(method, new ByteArray(key), new ByteArray(value)); var rItem = result.Pop(); + Assert.IsInstanceOfType(rItem, typeof(Integer)); Assert.AreEqual(1, rItem.GetBigInteger()); Assert.AreEqual(1, - testengine.Storages + testengine.Snapshot.Storages.GetChangeSet() .Count(a => - a.Key.Key.SequenceEqual(prefix.Concat(key)) && - a.Value.Value.SequenceEqual(value) && - !a.Value.IsConstant + a.Key.Key.SequenceEqual(Concat(prefix, key)) && + a.Item.Value.SequenceEqual(value) && + !a.Item.IsConstant )); } @@ -29,26 +32,47 @@ private byte[] Get(TestEngine testengine, string method, byte[] prefix, byte[] k Assert.AreEqual(1, result.Count); var rItem = result.Pop(); Assert.IsInstanceOfType(rItem, typeof(ByteArray)); - Assert.AreEqual(1, testengine.Storages.Count(a => a.Key.Key.SequenceEqual(prefix.Concat(key)))); + Assert.AreEqual(1, testengine.Snapshot.Storages.GetChangeSet().Count(a => a.Key.Key.SequenceEqual(Concat(prefix, key)))); return rItem.GetByteArray(); } - private bool Delete(TestEngine testengine, string method, byte[] prefix, byte[] key) + private void Delete(TestEngine testengine, string method, byte[] prefix, byte[] key) { var result = testengine.ExecuteTestCaseStandard(method, new ByteArray(key)); Assert.AreEqual(1, result.Count); var rItem = result.Pop(); - Assert.IsInstanceOfType(rItem, typeof(Boolean)); - Assert.AreEqual(0, testengine.Storages.Count(a => a.Key.Key.SequenceEqual(prefix.Concat(key)))); - return rItem.GetBoolean(); + Assert.IsInstanceOfType(rItem, typeof(ByteArray)); + Assert.AreEqual(0, testengine.Snapshot.Storages.GetChangeSet().Count(a => a.Key.Key.SequenceEqual(Concat(prefix, key)))); + } + + private byte[] Concat(byte[] prefix, params byte[] key) + { + var l = new List(prefix); + l.AddRange(key); + + return l.ToArray(); + } + + TestEngine testengine; + + [TestInitialize] + public void Init() + { + testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_Storage.cs"); + testengine.Snapshot.Contracts.Add(testengine.EntryScriptHash, new Ledger.ContractState() + { + Script = testengine.EntryContext.Script, + Manifest = new Manifest.ContractManifest() + { + Features = Manifest.ContractFeatures.HasStorage + } + }); } [TestMethod] public void Test_Byte() { - var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_StorageMap.cs"); - var prefix = new byte[] { 0xAA }; var key = new byte[] { 0x01, 0x02, 0x03 }; var value = new byte[] { 0x04, 0x05, 0x06 }; @@ -59,23 +83,19 @@ public void Test_Byte() // Get + testengine.Reset(); var getVal = Get(testengine, "TestGetByte", prefix, key); CollectionAssert.AreEqual(value, getVal); // Delete - var del = Delete(testengine, "TestDeleteByte", prefix, key); - Assert.IsTrue(del); - del = Delete(testengine, "TestDeleteByte", prefix, key); - Assert.IsFalse(del); + testengine.Reset(); + Delete(testengine, "TestDeleteByte", prefix, key); } [TestMethod] public void Test_ByteArray() { - var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_StorageMap.cs"); - var prefix = new byte[] { 0x00, 0xFF }; var key = new byte[] { 0x01, 0x02, 0x03 }; var value = new byte[] { 0x04, 0x05, 0x06 }; @@ -86,42 +106,52 @@ public void Test_ByteArray() // Get + testengine.Reset(); var getVal = Get(testengine, "TestGetByteArray", prefix, key); CollectionAssert.AreEqual(value, getVal); // Delete - var del = Delete(testengine, "TestDeleteByteArray", prefix, key); - Assert.IsTrue(del); - del = Delete(testengine, "TestDeleteByteArray", prefix, key); - Assert.IsFalse(del); + testengine.Reset(); + Delete(testengine, "TestDeleteByteArray", prefix, key); } [TestMethod] public void Test_String() { - var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_StorageMap.cs"); - var prefix = new byte[] { 0x61, 0x61 }; var key = new byte[] { 0x01, 0x02, 0x03 }; var value = new byte[] { 0x04, 0x05, 0x06 }; // Put + testengine.Reset(); Put(testengine, "TestPutString", prefix, key, value); // Get + testengine.Reset(); var getVal = Get(testengine, "TestGetString", prefix, key); CollectionAssert.AreEqual(value, getVal); // Delete - var del = Delete(testengine, "TestDeleteString", prefix, key); - Assert.IsTrue(del); - del = Delete(testengine, "TestDeleteString", prefix, key); - Assert.IsFalse(del); + testengine.Reset(); + Delete(testengine, "TestDeleteString", prefix, key); + } + + [TestMethod] + public void Test_ReadOnly() + { + var key = new byte[] { 0x01, 0x02, 0x03 }; + var value = new byte[] { 0x04, 0x05, 0x06 }; + + // Put + + testengine.Reset(); + var result = testengine.ExecuteTestCaseStandard("TestPutReadOnly", new ByteArray(key), new ByteArray(value)); + Assert.AreEqual(VM.VMState.FAULT, testengine.State); + Assert.AreEqual(0, result.Count); } } } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/System/ExecutionEngineTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/System/ExecutionEngineTest.cs new file mode 100644 index 000000000..c1eaf3997 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/System/ExecutionEngineTest.cs @@ -0,0 +1,103 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.VM; +using Neo.VM.Types; +using System.IO; + +namespace Neo.Compiler.MSIL.SmartContractFramework.Services.System +{ + [TestClass] + public class ExecutionEngineTest + { + class DummyVerificable : IVerifiable + { + public Witness[] Witnesses { get; set; } + + public int Size => 0; + + public void Deserialize(BinaryReader reader) + { + } + + public void DeserializeUnsigned(BinaryReader reader) + { + } + + public UInt160[] GetScriptHashesForVerifying(Snapshot snapshot) + { + throw new global::System.NotImplementedException(); + } + + public void Serialize(BinaryWriter writer) + { + } + + public void SerializeUnsigned(BinaryWriter writer) + { + } + } + + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(SmartContract.TriggerType.Application, new DummyVerificable()); + _engine.AddEntryScript("./TestClasses/Contract_ExecutionEngine.cs"); + } + + [TestMethod] + public void CallingScriptHashTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("CallingScriptHash"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual("3632c01ec5cc1961ba49d8033798e469f6a6f697", item.GetByteArray().ToHexString()); + } + + [TestMethod] + public void EntryScriptHashTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("EntryScriptHash"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual("3632c01ec5cc1961ba49d8033798e469f6a6f697", item.GetByteArray().ToHexString()); + } + + [TestMethod] + public void ExecutingScriptHashTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("ExecutingScriptHash"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteArray)); + Assert.AreEqual("3632c01ec5cc1961ba49d8033798e469f6a6f697", item.GetByteArray().ToHexString()); + } + + [TestMethod] + public void ScriptContainerTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("ScriptContainer"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(InteropInterface)); + Assert.AreEqual(_engine.ScriptContainer, ((InteropInterface)item).GetInterface()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/SyscallTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/SyscallTest.cs new file mode 100644 index 000000000..88357a0d7 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/SyscallTest.cs @@ -0,0 +1,65 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using System.IO; + +namespace Neo.SmartContract.Framework.UnitTests +{ + [TestClass] + public class SyscallTest + { + [TestMethod] + public void TestAllSyscalls() + { + // Current syscalls + + var list = new List(); + + using (var stream = File.OpenRead(typeof(SmartContract).Assembly.Location)) + { + var expectedType = typeof(SyscallAttribute).FullName; + var module = Mono.Cecil.ModuleDefinition.ReadModule(stream); + + foreach (var type in module.Types) + { + foreach (var method in type.Methods) + { + foreach (var attr in method.CustomAttributes) + { + if (attr.AttributeType.FullName == expectedType) + { + var syscall = attr.ConstructorArguments[0].Value.ToString(); + if (!list.Contains(syscall)) list.Add(syscall); + } + } + } + } + } + + // Neo syscalls + + var notFound = new List(); + + foreach (var syscall in InteropService.SupportedMethods().Values) + { + if (syscall == "Neo.Native.Deploy") continue; + if (syscall == "Neo.Native.Tokens.NEO") continue; + if (syscall == "Neo.Native.Tokens.GAS") continue; + if (syscall == "Neo.Native.Policy") continue; + + if (list.Remove(syscall)) continue; + + notFound.Add(syscall); + } + + if (list.Count > 0) + { + Assert.Fail($"Unknown syscalls: {string.Join("\n-", list)}"); + } + + if (notFound.Count > 0) + { + Assert.Fail($"Not implemented syscalls: {string.Join("\n-", notFound)}"); + } + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestBlockchain.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestBlockchain.cs new file mode 100644 index 000000000..eebf125c5 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestBlockchain.cs @@ -0,0 +1,52 @@ +using Moq; +using Neo.Compiler.MSIL.Utils; +using Neo.Ledger; +using Neo.Persistence; + +namespace Neo.SmartContract.Framework.UnitTests +{ + public static class TestBlockchain + { + private static NeoSystem TheNeoSystem; + private static Mock _Store; + + public static Store GetStore() + { + if (_Store == null) InitializeMockNeoSystem(); + return _Store.Object; + } + + static TestBlockchain() + { + InitializeMockNeoSystem(); + GetStore(); + } + + public static NeoSystem InitializeMockNeoSystem() + { + if (TheNeoSystem == null) + { + var mockSnapshot = new TestSnapshot(); + + _Store = new Mock(); + + _Store.Setup(p => p.GetBlocks()).Returns(mockSnapshot.Blocks); + _Store.Setup(p => p.GetTransactions()).Returns(mockSnapshot.Transactions); + _Store.Setup(p => p.GetContracts()).Returns(mockSnapshot.Contracts); + _Store.Setup(p => p.GetStorages()).Returns(mockSnapshot.Storages); + _Store.Setup(p => p.GetHeaderHashList()).Returns(mockSnapshot.HeaderHashList); + _Store.Setup(p => p.GetBlockHashIndex()).Returns(mockSnapshot.BlockHashIndex); + _Store.Setup(p => p.GetHeaderHashIndex()).Returns(mockSnapshot.HeaderHashIndex); + _Store.Setup(p => p.GetSnapshot()).Returns(mockSnapshot.Clone()); + + TheNeoSystem = new NeoSystem(_Store.Object); + + // Ensure that blockchain is loaded + + var blockchain = Blockchain.Singleton; + } + + return TheNeoSystem; + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Account.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Account.cs new file mode 100644 index 000000000..93daa9da3 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Account.cs @@ -0,0 +1,12 @@ +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Account : SmartContract.Framework.SmartContract + { + public static bool AccountIsStandard(byte[] scripthash) + { + return Account.IsStandard(scripthash); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Blockchain.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Blockchain.cs new file mode 100644 index 000000000..f047f43b2 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Blockchain.cs @@ -0,0 +1,110 @@ +using Neo.SmartContract.Framework.Services.Neo; +using System; +using System.Numerics; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Blockchain : SmartContract.Framework.SmartContract + { + public static uint GetHeight() + { + return Blockchain.GetHeight(); + } + + public static BigInteger GetTransactionHeight(byte[] hash) + { + return Blockchain.GetTransactionHeight(hash); + } + + public static object GetBlockByHash(byte[] hash, string whatReturn) + { + var block = Blockchain.GetBlock(hash); + return GetBlockInfo(block, whatReturn); + } + + public static object GetBlockByIndex(uint index, string whatReturn) + { + var block = Blockchain.GetBlock(index); + return GetBlockInfo(block, whatReturn); + } + + private static object GetBlockInfo(Block block, string whatReturn) + { + if (block == null) + { + Runtime.Log("NULL Block"); + return null; + } + + if (whatReturn == "Hash") return block.Hash; + if (whatReturn == "Index") return block.Index; + if (whatReturn == "MerkleRoot") return block.MerkleRoot; + if (whatReturn == "NextConsensus") return block.NextConsensus; + if (whatReturn == "PrevHash") return block.PrevHash; + if (whatReturn == "Timestamp") return block.Timestamp; + if (whatReturn == "TransactionsCount") return block.TransactionsCount; + if (whatReturn == "Version") return block.Version; + + throw new Exception("Uknown property"); + } + + public static object GetTxByHash(byte[] hash, string whatReturn) + { + var tx = Blockchain.GetTransaction(hash); + return GetTxInfo(tx, whatReturn); + } + + public static object GetTxByBlockHash(byte[] blockHash, int txIndex, string whatReturn) + { + var tx = Blockchain.GetTransactionFromBlock(blockHash, txIndex); + return GetTxInfo(tx, whatReturn); + } + + public static object GetTxByBlockIndex(uint blockIndex, int txIndex, string whatReturn) + { + var tx = Blockchain.GetTransactionFromBlock(blockIndex, txIndex); + return GetTxInfo(tx, whatReturn); + } + + private static object GetTxInfo(Transaction tx, string whatReturn) + { + if (tx == null) + { + Runtime.Log("NULL Tx"); + return null; + } + + if (whatReturn == "Hash") return tx.Hash; + if (whatReturn == "NetworkFee") return tx.NetworkFee; + if (whatReturn == "Nonce") return tx.Nonce; + if (whatReturn == "Script") return tx.Script; + if (whatReturn == "Sender") return tx.Sender; + if (whatReturn == "SystemFee") return tx.SystemFee; + if (whatReturn == "ValidUntilBlock") return tx.ValidUntilBlock; + if (whatReturn == "Version") return tx.Version; + + throw new Exception("Uknown property"); + } + + public static object GetContract(byte[] hash, string whatReturn) + { + var contract = Blockchain.GetContract(hash); + return GetContractInfo(contract, whatReturn); + } + + private static object GetContractInfo(Contract contract, string whatReturn) + { + if (contract == null) + { + Runtime.Log("NULL contract"); + return null; + } + + if (whatReturn == "HasStorage") return contract.HasStorage; + if (whatReturn == "IsPayable") return contract.IsPayable; + if (whatReturn == "Script") return contract.Script; + + throw new Exception("Uknown property"); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Contract.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Contract.cs new file mode 100644 index 000000000..44e397930 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Contract.cs @@ -0,0 +1,27 @@ +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Contract : SmartContract.Framework.SmartContract + { + public static object Call(byte[] scriptHash, string method, object[] arguments) + { + return Contract.Call(scriptHash, method, arguments); + } + + public static object Create(byte[] script, string manifest) + { + return Contract.Create(script, manifest); + } + + public static void Update(byte[] script, string manifest) + { + Contract.Update(script, manifest); + } + + public static void Destroy() + { + Contract.Destroy(); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Crypto.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Crypto.cs new file mode 100644 index 000000000..a1fda86ed --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Crypto.cs @@ -0,0 +1,22 @@ +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Crypto : SmartContract.Framework.SmartContract + { + public static bool VerifySignature(byte[] pubkey, byte[] signature) + { + return Crypto.VerifySignature(pubkey, signature); + } + + public static bool VerifySignatureWithMessage(byte[] message, byte[] pubkey, byte[] signature) + { + return Crypto.VerifySignature(message, pubkey, signature); + } + + public static bool VerifySignatures(byte[][] pubkeys, byte[][] signatures) + { + return Crypto.VerifySignatures(pubkeys, signatures); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs new file mode 100644 index 000000000..64fcdba6b --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs @@ -0,0 +1,35 @@ +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Enumerator : SmartContract.Framework.SmartContract + { + public static int TestNext(byte[] a) + { + int sum = 0; + var enumerator = Enumerator.Create(a); + + while (enumerator.Next()) + { + sum += enumerator.Value; + } + + return sum; + } + + public static int TestConcat(byte[] a, byte[] b) + { + int sum = 0; + var enumeratorA = Enumerator.Create(a); + var enumeratorB = Enumerator.Create(b); + var enumeratorC = enumeratorA.Concat(enumeratorB); + + while (enumeratorC.Next()) + { + sum += enumeratorC.Value; + } + + return sum; + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_ExecutionEngine.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_ExecutionEngine.cs new file mode 100644 index 000000000..b21025ca9 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_ExecutionEngine.cs @@ -0,0 +1,27 @@ +using Neo.SmartContract.Framework.Services.System; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_ExecutionEngine : SmartContract.Framework.SmartContract + { + public static byte[] CallingScriptHash() + { + return ExecutionEngine.CallingScriptHash; + } + + public static byte[] EntryScriptHash() + { + return ExecutionEngine.EntryScriptHash; + } + + public static byte[] ExecutingScriptHash() + { + return ExecutionEngine.ExecutingScriptHash; + } + + public static object ScriptContainer() + { + return ExecutionEngine.ScriptContainer; + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs new file mode 100644 index 000000000..3f38f045e --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs @@ -0,0 +1,84 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Iterator : SmartContract.Framework.SmartContract + { + public static int TestNextArray(byte[] a) + { + int sum = 0; + var iterator = Iterator.Create(a); + + while (iterator.Next()) + { + sum += iterator.Value; + } + + return sum; + } + + public static int TestConcatArray(byte[] a, byte[] b) + { + int sum = 0; + var iteratorA = Iterator.Create(a); + var iteratorB = Iterator.Create(b); + var iteratorC = iteratorA.Concat(iteratorB); + + while (iteratorC.Next()) + { + sum += iteratorC.Value; + } + + return sum; + } + + public static int TestConcatMap(Map a, Map b) + { + int sum = 0; + var iteratorA = Iterator.Create(a); + var iteratorB = Iterator.Create(b); + var iteratorC = iteratorA.Concat(iteratorB); + + while (iteratorC.Next()) + { + sum += iteratorC.Key; + sum += iteratorC.Value; + } + + return sum; + } + + public static int TestConcatKeys(Map a, Map b) + { + int sum = 0; + var iteratorA = Iterator.Create(a); + var iteratorB = Iterator.Create(b); + var iteratorC = iteratorA.Concat(iteratorB); + var enumerator = iteratorC.Keys; + + while (enumerator.Next()) + { + sum += enumerator.Value; + } + + return sum; + } + + public static int TestConcatValues(Map a, Map b) + { + int sum = 0; + var iteratorA = Iterator.Create(a); + var iteratorB = Iterator.Create(b); + var iteratorC = iteratorA.Concat(iteratorB); + var enumerator = iteratorC.Values; + + while (enumerator.Next()) + { + sum += enumerator.Value; + } + + return sum; + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Json.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Json.cs new file mode 100644 index 000000000..23bd5a8a0 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Json.cs @@ -0,0 +1,17 @@ +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Json : SmartContract.Framework.SmartContract + { + public static string Serialize(object obj) + { + return Json.Serialize(obj); + } + + public static object Deserialize(string json) + { + return Json.Deserialize(json); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Native.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Native.cs new file mode 100644 index 000000000..9b4ddfa9d --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Native.cs @@ -0,0 +1,33 @@ +using Neo.SmartContract.Framework.Services.Neo; +using System.Numerics; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Native : SmartContract.Framework.SmartContract + { + public static int NEO_Decimals() + { + return (int)Native.NEO("decimals", new object[0]); + } + + public static string NEO_Name() + { + return (string)Native.NEO("name", new object[0]); + } + + public static int GAS_Decimals() + { + return (int)Native.GAS("decimals", new object[0]); + } + + public static string GAS_Name() + { + return (string)Native.GAS("name", new object[0]); + } + + public static BigInteger Policy_GetFeePerByte() + { + return (BigInteger)Native.Policy("getFeePerByte", new object[0]); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Runtime.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Runtime.cs new file mode 100644 index 000000000..459bb3121 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Runtime.cs @@ -0,0 +1,84 @@ +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Runtime : SmartContract.Framework.SmartContract + { + public static uint GetInvocationCounter() + { + return Runtime.InvocationCounter; + } + + public static ulong GetTime() + { + return Runtime.Time; + } + + public static string GetPlatform() + { + return Runtime.Platform; + } + + public static TriggerType GetTrigger() + { + return Runtime.Trigger; + } + + public static void Log(string message) + { + Runtime.Log(message); + } + + public static void Notify(string message) + { + Runtime.Notify(message); + } + + public static bool CheckWitness(byte[] hashOrPubkey) + { + return Runtime.CheckWitness(hashOrPubkey); + } + + public static int GetNotificationsCount(byte[] hash) + { + var notifications = Runtime.GetNotifications(hash); + return notifications.Length; + } + + public static int GetAllNotifications() + { + int sum = 0; + var notifications = Runtime.GetNotifications(); + + for (int x = 0; x < notifications.Length; x++) + { + var notify = notifications[x]; + sum += (int)notify.State; + } + + return sum; + } + + public static int GetNotifications(byte[] hash) + { + int sum = 0; + var notifications = Runtime.GetNotifications(hash); + + for (int x = 0; x < notifications.Length; x++) + { + var notify = notifications[x]; + + // Check that the hash is working well + + for (int y = 0; y < notify.ScriptHash.Length; y++) + { + if (notify.ScriptHash[y] != hash[y]) return int.MinValue; + } + + sum += (int)notify.State; + } + + return sum; + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_StorageMap.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Storage.cs similarity index 67% rename from tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_StorageMap.cs rename to tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Storage.cs index 37903ac11..fe9866719 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_StorageMap.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Storage.cs @@ -1,8 +1,8 @@ -using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.Neo; namespace Neo.Compiler.MSIL.TestClasses { - class Contract_StorageMap : SmartContract.Framework.SmartContract + class Contract_Storage : SmartContract.Framework.SmartContract { // There is no main here, it can be auto generation. @@ -15,18 +15,16 @@ public static bool TestPutByte(byte[] key, byte[] value) return true; } - public static bool TestDeleteByte(byte[] key) + public static void TestDeleteByte(byte[] key) { var storage = Storage.CurrentContext.CreateMap(0xAA); - var value = storage.Get(key); - var exists = value.Length > 0; storage.Delete(key); - return exists; } public static byte[] TestGetByte(byte[] key) { - var storage = Storage.CurrentContext.CreateMap(0xAA); + var context = Storage.CurrentReadOnlyContext; + var storage = context.CreateMap(0xAA); var value = storage.Get(key); return value; } @@ -43,20 +41,18 @@ public static bool TestPutString(byte[] key, byte[] value) return true; } - public static bool TestDeleteString(byte[] key) + public static void TestDeleteString(byte[] key) { var prefix = "aa"; var storage = Storage.CurrentContext.CreateMap(prefix); - var value = storage.Get(key); - var exists = value.Length > 0; storage.Delete(key); - return exists; } public static byte[] TestGetString(byte[] key) { var prefix = "aa"; - var storage = Storage.CurrentContext.CreateMap(prefix); + var context = Storage.CurrentReadOnlyContext; + var storage = context.CreateMap(prefix); var value = storage.Get(key); return value; } @@ -73,24 +69,31 @@ public static bool TestPutByteArray(byte[] key, byte[] value) return true; } - public static bool TestDeleteByteArray(byte[] key) + public static void TestDeleteByteArray(byte[] key) { var prefix = new byte[] { 0x00, 0xFF }; var storage = Storage.CurrentContext.CreateMap(prefix); - var value = storage.Get(key); - var exists = value.Length > 0; storage.Delete(key); - return exists; } public static byte[] TestGetByteArray(byte[] key) { var prefix = new byte[] { 0x00, 0xFF }; - var storage = Storage.CurrentContext.CreateMap(prefix); + var context = Storage.CurrentContext.AsReadOnly; + var storage = context.CreateMap(prefix); var value = storage.Get(key); return value; } #endregion + + public static bool TestPutReadOnly(byte[] key, byte[] value) + { + var prefix = new byte[] { 0x00, 0xFF }; + var context = Storage.CurrentContext.AsReadOnly; + var storage = context.CreateMap(prefix); + storage.Put(key, value); + return true; + } } }