diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0f680fb8c..6966667f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: @@ -41,7 +41,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: @@ -63,7 +63,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: diff --git a/src/Neo.Compiler.MSIL/Compiler.cs b/src/Neo.Compiler.MSIL/Compiler.cs index ad96a9c8d..0fa61a753 100644 --- a/src/Neo.Compiler.MSIL/Compiler.cs +++ b/src/Neo.Compiler.MSIL/Compiler.cs @@ -162,7 +162,7 @@ public static Assembly CompileVBFiles(string[] filenames, string[] references, b var tree = filenames.Select(u => VisualBasicSyntaxTree.ParseText( File.ReadAllText(u), path: u, - encoding: System.Text.Encoding.UTF8)).ToArray(); + encoding: Utility.StrictUTF8)).ToArray(); var op = new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: releaseMode ? OptimizationLevel.Release : OptimizationLevel.Debug); return Assembly.Create(VisualBasicCompilation.Create("SmartContract", tree, CreateReferences(references), op)); } @@ -179,7 +179,7 @@ public static Assembly CompileCSFiles(string[] filenames, string[] references, b var tree = filenames.Select(u => CSharpSyntaxTree.ParseText( File.ReadAllText(u), path: u, - encoding: System.Text.Encoding.UTF8)).ToArray(); + encoding: Utility.StrictUTF8)).ToArray(); var op = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: releaseMode ? OptimizationLevel.Release : OptimizationLevel.Debug); return Assembly.Create(CSharpCompilation.Create("SmartContract", tree, CreateReferences(references), op)); } diff --git a/src/Neo.Compiler.MSIL/DebugExport.cs b/src/Neo.Compiler.MSIL/DebugExport.cs new file mode 100644 index 000000000..14f34e2a2 --- /dev/null +++ b/src/Neo.Compiler.MSIL/DebugExport.cs @@ -0,0 +1,134 @@ +using Mono.Cecil.Cil; +using Neo.IO.Json; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace Neo.Compiler +{ + public static class DebugExport + { + private static JArray GetSequencePoints(IEnumerable codes, IReadOnlyDictionary docMap, IReadOnlyDictionary addrConvTable) + { + var points = codes + .Where(code => code.sequencePoint != null) + .Select(code => (code.addr, code.sequencePoint)); + + var outjson = new JArray(); + + foreach (var (address, sequencePoint) in points) + { + var value = string.Format("{0}[{1}]{2}:{3}-{4}:{5}", + addrConvTable.TryGetValue(address, out var newAddress) ? newAddress : address, + docMap[sequencePoint.Document.Url], + sequencePoint.StartLine, + sequencePoint.StartColumn, + sequencePoint.EndLine, + sequencePoint.EndColumn); + outjson.Add(value); + } + + return outjson; + } + + private static JArray ConvertParamList(IEnumerable @params) + { + @params ??= Enumerable.Empty(); + var paramsJson = new JArray(); + foreach (var param in @params) + { + var value = string.Format("{0},{1}", param.name, FuncExport.ConvType(param.type)); + paramsJson.Add(value); + } + + return paramsJson; + } + + private static JArray GetMethods(NeoModule module, IReadOnlyDictionary docMap, IReadOnlyDictionary addrConvTable) + { + var outjson = new JArray(); + + foreach (var method in module.mapMethods.Values) + { + if (method.body_Codes.Values.Count == 0) + { + continue; + } + + var name = string.Format("{0},{1}", + method._namespace, method.displayName); + + var range = string.Format("{0}-{1}", + method.body_Codes.Values.First().addr, + method.body_Codes.Values.Last().addr); + + var methodJson = new JObject(); + methodJson["id"] = method.name; + methodJson["name"] = name; + methodJson["range"] = range; + methodJson["params"] = ConvertParamList(method.paramtypes); + methodJson["return"] = FuncExport.ConvType(method.returntype); + methodJson["variables"] = ConvertParamList(method.method?.body_Variables); + methodJson["sequence-points"] = GetSequencePoints(method.body_Codes.Values, docMap, addrConvTable); + outjson.Add(methodJson); + } + return outjson; + } + + private static JArray GetEvents(NeoModule module) + { + var outjson = new JArray(); + foreach (var @event in module.mapEvents.Values) + { + var name = string.Format("{0},{1}", + @event._namespace, @event.displayName); + + var eventJson = new JObject(); + eventJson["id"] = @event.name; + eventJson["name"] = name; + eventJson["params"] = ConvertParamList(@event.paramtypes); + outjson.Add(eventJson); + } + return outjson; + } + + private static IReadOnlyDictionary GetDocumentMap(NeoModule module) + { + return module.mapMethods.Values + .SelectMany(m => m.body_Codes.Values) + .Where(code => code.sequencePoint != null) + .Select(code => code.sequencePoint.Document.Url) + .Distinct() + .Select((d, i) => (d, i)) + .ToDictionary(t => t.d, t => t.i); + } + + private static JArray GetDocuments(IReadOnlyDictionary docMap) + { + var outjson = new JArray(); + foreach (var doc in docMap.OrderBy(kvp => kvp.Value)) + { + Debug.Assert(outjson.Count == doc.Value); + outjson.Add(doc.Key); + } + return outjson; + } + + public static JObject Export(NeoModule module, byte[] script, IReadOnlyDictionary addrConvTable) + { + var docMap = GetDocumentMap(module); + addrConvTable ??= ImmutableDictionary.Empty; + + var outjson = new JObject(); + outjson["hash"] = FuncExport.ComputeHash(script); + // outjson["entrypoint"]= module.mainMethod; + outjson["documents"] = GetDocuments(docMap); + outjson["methods"] = GetMethods(module, docMap, addrConvTable); + outjson["events"] = GetEvents(module); + return outjson; + } + } +} diff --git a/src/Neo.Compiler.MSIL/FuncExport.cs b/src/Neo.Compiler.MSIL/FuncExport.cs index be4e04845..ef0f78739 100644 --- a/src/Neo.Compiler.MSIL/FuncExport.cs +++ b/src/Neo.Compiler.MSIL/FuncExport.cs @@ -1,23 +1,37 @@ -using Neo.Compiler; +using Mono.Cecil; +using Neo.IO.Json; +using Neo.SmartContract.Framework; using System; using System.Collections.Generic; using System.Linq; using System.Text; -namespace vmtool +namespace Neo.Compiler { public class FuncExport { - static string ConvType(string _type) + public static readonly TypeReference Void = new TypeReference("System", "Void", ModuleDefinition.ReadModule(typeof(object).Assembly.Location, new ReaderParameters(ReadingMode.Immediate)), null); + + internal static string ConvType(TypeReference t) { - switch (_type) - { - case "__Signature": - return "Signature"; + if (t is null) return "Null"; - case "System.Boolean": - return "Boolean"; + var type = t.FullName; + + TypeDefinition definition = t.Resolve(); + if (definition != null) + foreach (var i in definition.Interfaces) + { + if (i.InterfaceType.Name == nameof(IApiInterface)) + { + return "IInteropInterface"; + } + } + switch (type) + { + case "System.Boolean": return "Boolean"; + case "System.Char": case "System.Byte": case "System.SByte": case "System.Int16": @@ -26,68 +40,52 @@ static string ConvType(string _type) case "System.UInt32": case "System.Int64": case "System.UInt64": - case "System.Numerics.BigInteger": - return "Integer"; - - case "__Hash160": - return "Hash160"; - - case "__Hash256": - return "Hash256"; - - case "System.Byte[]": - return "ByteArray"; - - case "__PublicKey": - return "PublicKey"; - - case "System.String": - return "String"; - - case "System.Object[]": - return "Array"; - - case "__InteropInterface": - case "IInteropInterface": - return "InteropInterface"; + case "System.Numerics.BigInteger": return "Integer"; + case "System.Byte[]": return "ByteArray"; + case "System.String": return "String"; + case "IInteropInterface": return "InteropInterface"; + case "System.Void": return "Void"; + case "System.Object": return "Any"; + } - case "System.Void": - return "Void"; + if (t.IsArray) return "Array"; - case "System.Object": - return "ByteArray"; - } - if (_type.Contains("[]")) + if (type.StartsWith("System.Action") || type.StartsWith("System.Func") || type.StartsWith("System.Delegate")) + return $"Unknown:Pointers are not allowed to be public '{type}'"; + if (type.StartsWith("System.ValueTuple`") || type.StartsWith("System.Tuple`")) return "Array"; - if (_type.Contains("Neo.SmartContract.Framework.Services.Neo.Enumerator")) - return "InteropInterface"; - return "Unknown:" + _type; + return "Unknown:" + type; } - public static MyJson.JsonNode_Object Export(NeoModule module, byte[] script, Dictionary addrConvTable) + public static string ComputeHash(byte[] script) { var sha256 = System.Security.Cryptography.SHA256.Create(); byte[] hash256 = sha256.ComputeHash(script); var ripemd160 = new Neo.Cryptography.RIPEMD160Managed(); var hash = ripemd160.ComputeHash(hash256); - var outjson = new MyJson.JsonNode_Object(); - - //hash StringBuilder sb = new StringBuilder(); sb.Append("0x"); - foreach (var b in hash.Reverse().ToArray()) + for (int i = hash.Length - 1; i >= 0; i--) { - sb.Append(b.ToString("x02")); + sb.Append(hash[i].ToString("x02")); } - outjson.SetDictValue("hash", sb.ToString()); + return sb.ToString(); + } + + public static JObject Export(NeoModule module, byte[] script, Dictionary addrConvTable) + { + var outjson = new JObject(); + + //hash + outjson["hash"] = ComputeHash(script); //functions - var methods = new MyJson.JsonNode_Array(); + var methods = new JArray(); outjson["methods"] = methods; - List names = new List(); + HashSet names = new HashSet(); foreach (var function in module.mapMethods) { var mm = function.Value; @@ -96,65 +94,134 @@ public static MyJson.JsonNode_Object Export(NeoModule module, byte[] script, Dic if (mm.isPublic == false) continue; - var funcsign = new MyJson.JsonNode_Object(); - methods.Add(funcsign); - funcsign.SetDictValue("name", function.Value.displayName); - if (names.Contains(function.Value.displayName)) + if (!names.Add(function.Value.displayName)) { throw new Exception("abi not allow same name functions"); } - names.Add(function.Value.displayName); + var funcsign = new JObject(); + methods.Add(funcsign); + funcsign["name"] = function.Value.displayName; var offset = addrConvTable?[function.Value.funcaddr] ?? function.Value.funcaddr; - funcsign.SetDictValue("offset", offset.ToString()); - MyJson.JsonNode_Array funcparams = new MyJson.JsonNode_Array(); + funcsign["offset"] = offset.ToString(); + JArray funcparams = new JArray(); funcsign["parameters"] = funcparams; if (mm.paramtypes != null) { foreach (var v in mm.paramtypes) { - var ptype = ConvType(v.type); - var item = new MyJson.JsonNode_Object(); + var item = new JObject(); funcparams.Add(item); - item.SetDictValue("name", v.name); - item.SetDictValue("type", ptype); + item["name"] = v.name; + item["type"] = ConvType(v.type); } } var rtype = ConvType(mm.returntype); - funcsign.SetDictValue("returnType", rtype); + if (rtype.StartsWith("Unknown:")) + { + throw new Exception($"Unknown return type '{mm.returntype}' for method '{function.Value.name}'"); + } + + funcsign["returntype"] = rtype; } //events - var eventsigns = new MyJson.JsonNode_Array(); + var eventsigns = new JArray(); outjson["events"] = eventsigns; foreach (var events in module.mapEvents) { var mm = events.Value; - var funcsign = new MyJson.JsonNode_Object(); + var funcsign = new JObject(); eventsigns.Add(funcsign); - funcsign.SetDictValue("name", events.Value.displayName); - MyJson.JsonNode_Array funcparams = new MyJson.JsonNode_Array(); + funcsign["name"] = events.Value.displayName; + JArray funcparams = new JArray(); funcsign["parameters"] = funcparams; if (mm.paramtypes != null) { foreach (var v in mm.paramtypes) { - var ptype = ConvType(v.type); - var item = new MyJson.JsonNode_Object(); + var item = new JObject(); funcparams.Add(item); - item.SetDictValue("name", v.name); - item.SetDictValue("type", ptype); + item["name"] = v.name; + item["type"] = ConvType(v.type); } } //event do not have returntype in nep3 //var rtype = ConvType(mm.returntype); - //funcsign.SetDictValue("returntype", rtype); + //funcsign["returntype", rtype); } return outjson; } + + private static object BuildSupportedStandards(Mono.Collections.Generic.Collection supportedStandardsAttribute) + { + if (supportedStandardsAttribute == null || supportedStandardsAttribute.Count == 0) + { + return "[]"; + } + + var entry = supportedStandardsAttribute.First(); + string extra = "["; + foreach (var item in entry.Value as CustomAttributeArgument[]) + { + extra += ($"\"{ScapeJson(item.Value.ToString())}\","); + } + extra = extra[0..^1]; + extra += "]"; + + return extra; + } + + private static string BuildExtraAttributes(List> extraAttributes) + { + if (extraAttributes == null || extraAttributes.Count == 0) + { + return "null"; + } + + string extra = "{"; + foreach (var extraAttribute in extraAttributes) + { + var key = ScapeJson(extraAttribute[0].Value.ToString()); + var value = ScapeJson(extraAttribute[1].Value.ToString()); + extra += ($"\"{key}\":\"{value}\","); + } + extra = extra[0..^1]; + extra += "}"; + + return extra; + } + + private static string ScapeJson(string value) + { + return value.Replace("\"", ""); + } + + public static string GenerateManifest(JObject abi, NeoModule module) + { + var sbABI = abi.ToString(false); + + var features = module == null ? ContractFeatures.NoProperty : module.attributes + .Where(u => u.AttributeType.FullName == "Neo.SmartContract.Framework.FeaturesAttribute") + .Select(u => (ContractFeatures)u.ConstructorArguments.FirstOrDefault().Value) + .FirstOrDefault(); + + var extraAttributes = module == null ? new List>() : module.attributes.Where(u => u.AttributeType.FullName == "Neo.SmartContract.Framework.ManifestExtraAttribute").Select(attribute => attribute.ConstructorArguments).ToList(); + var supportedStandardsAttribute = module?.attributes.Where(u => u.AttributeType.FullName == "Neo.SmartContract.Framework.SupportedStandardsAttribute").Select(attribute => attribute.ConstructorArguments).FirstOrDefault(); + + var extra = BuildExtraAttributes(extraAttributes); + var supportedStandards = BuildSupportedStandards(supportedStandardsAttribute); + var storage = features.HasFlag(ContractFeatures.HasStorage).ToString().ToLowerInvariant(); + var payable = features.HasFlag(ContractFeatures.Payable).ToString().ToLowerInvariant(); + + return + @"{""groups"":[],""features"":{""storage"":" + storage + @",""payable"":" + payable + @"},""abi"":" + + sbABI + + @",""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""supportedstandards"":" + supportedStandards + @",""extra"":" + extra + "}"; + } } } diff --git a/src/Neo.Compiler.MSIL/Helper.cs b/src/Neo.Compiler.MSIL/Helper.cs index e9f058223..98ba52b11 100644 --- a/src/Neo.Compiler.MSIL/Helper.cs +++ b/src/Neo.Compiler.MSIL/Helper.cs @@ -67,7 +67,7 @@ public static byte[] OpDataToBytes(string opdata) } catch { - return Encoding.UTF8.GetBytes(opdata); + return Utility.StrictUTF8.GetBytes(opdata); } } } diff --git a/src/Neo.Compiler.MSIL/MSIL/CctorSubVM.cs b/src/Neo.Compiler.MSIL/MSIL/CctorSubVM.cs index 338930e24..52df729f9 100644 --- a/src/Neo.Compiler.MSIL/MSIL/CctorSubVM.cs +++ b/src/Neo.Compiler.MSIL/MSIL/CctorSubVM.cs @@ -1,3 +1,4 @@ +using Neo.Cryptography; using System; using System.Collections.Generic; using System.Linq; @@ -13,29 +14,23 @@ public static object Dup(object src) { if (src.GetType() == typeof(byte[])) { - byte[] _src = (byte[])src; - return _src; + return (byte[])src; } else if (src.GetType() == typeof(int)) { - int v = (int)src; - return v; + return (int)src; } else if (src.GetType() == typeof(string)) { - string v = (string)src; - string v2 = v; - return v2; + return (string)src; } else if (src.GetType() == typeof(Boolean)) { - Boolean v = (Boolean)src; - return v; + return (bool)src; } else if (src.GetType() == typeof(string[])) { - string[] strArrays = (string[])src; - return strArrays; + return (string[])src; } else // TODO support more types { @@ -46,11 +41,12 @@ public static object Dup(object src) public static bool Parse(ILMethod from, NeoModule to) { bool constValue = true; + bool ret = false; calcStack = new Stack(); bool bEnd = false; foreach (var src in from.body_Codes.Values) { - if (bEnd) + if (bEnd || ret) break; switch (src.code) @@ -178,7 +174,6 @@ public static bool Parse(ILMethod from, NeoModule to) { if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.NonemitWithConvertAttribute") { - var text = (string)calcStack.Pop(); var value = (int)attr.ConstructorArguments[0].Value; var type = attr.ConstructorArguments[0].Type.Resolve(); string attrname = ""; @@ -192,21 +187,34 @@ public static bool Parse(ILMethod from, NeoModule to) } if (attrname == "ToScriptHash")//AddressString2ScriptHashBytes to bytes { - var bytes = NEO.AllianceOfThinWallet.Cryptography.Base58.Decode(text); + var text = (string)calcStack.Pop(); + var bytes = Base58.Decode(text); var hash = bytes.Skip(1).Take(20).ToArray(); calcStack.Push(hash); } else if (attrname == "HexToBytes")//HexString2Bytes to bytes[] { + var reverse = (int)calcStack.Pop() != 0; + var text = (string)calcStack.Pop(); var hex = text.HexString2Bytes(); + if (reverse) hex = hex.Reverse().ToArray(); calcStack.Push(hex); } else if (attrname == "ToBigInteger") { + var text = (string)calcStack.Pop(); var n = System.Numerics.BigInteger.Parse(text); calcStack.Push(n); } } + if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.SyscallAttribute") + { + // If there is a syscall in cctor, we should add it into staticfieldsCctor directly. + // Then the initializemethod will handle it. + ret = true; + constValue = false; + break; + } } } } diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Common.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Common.cs index 157ab18ee..4f5257a80 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Common.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Common.cs @@ -78,6 +78,7 @@ private NeoCode Convert1by1(VM.OpCode code, OpCode src, NeoMethod to, byte[] dat _code.debugline = src.debugline; _code.debugILAddr = src.addr; _code.debugILCode = src.code.ToString(); + _code.sequencePoint = src.sequencePoint; } addr++; @@ -141,7 +142,7 @@ private void ConvertPushDataArray(byte[] data, OpCode src, NeoMethod to) private void ConvertPushString(string str, OpCode src, NeoMethod to) { - var data = Encoding.UTF8.GetBytes(str); + var data = Utility.StrictUTF8.GetBytes(str); ConvertPushDataArray(data, src, to); } diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 32f32ea1d..7c2d8fc77 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -146,7 +146,7 @@ public bool IsSysCall(Mono.Cecil.MethodDefinition defs, out string name) } foreach (var attr in defs.CustomAttributes) { - if (attr.AttributeType.Name == "SyscallAttribute") + if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.SyscallAttribute") { var type = attr.ConstructorArguments[0].Type; var value = (string)attr.ConstructorArguments[0].Value; @@ -162,7 +162,7 @@ public bool IsSysCall(Mono.Cecil.MethodDefinition defs, out string name) } */ - public bool IsAppCall(Mono.Cecil.MethodDefinition defs, out byte[] hash) + public bool IsContractCall(Mono.Cecil.MethodDefinition defs, out byte[] hash) { if (defs == null) { @@ -170,9 +170,9 @@ public bool IsAppCall(Mono.Cecil.MethodDefinition defs, out byte[] hash) return false; } - foreach (var attr in defs.CustomAttributes) + foreach (var attr in defs.DeclaringType.CustomAttributes) { - if (attr.AttributeType.Name == "AppcallAttribute") + if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.ContractAttribute") { var type = attr.ConstructorArguments[0].Type; var a = attr.ConstructorArguments[0]; @@ -222,15 +222,15 @@ public bool IsNonCall(Mono.Cecil.MethodDefinition defs) } foreach (var attr in defs.CustomAttributes) { - if (attr.AttributeType.Name == "NonemitAttribute") + if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.NonemitAttribute") { return true; } - if (attr.AttributeType.Name == "NonemitWithConvertAttribute") + if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.NonemitWithConvertAttribute") { throw new Exception("NonemitWithConvert func only used for readonly static field."); } - if (attr.AttributeType.Name == "ScriptAttribute") + if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.ScriptAttribute") { var strv = attr.ConstructorArguments[0].Value as string; if (string.IsNullOrEmpty(strv)) @@ -257,9 +257,9 @@ public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opc foreach (var attr in defs.CustomAttributes) { - if ((attr.AttributeType.Name == "OpCodeAttribute") || - (attr.AttributeType.Name == "SyscallAttribute") || - (attr.AttributeType.Name == "ScriptAttribute")) + if ((attr.AttributeType.FullName == "Neo.SmartContract.Framework.OpCodeAttribute") || + (attr.AttributeType.FullName == "Neo.SmartContract.Framework.SyscallAttribute") || + (attr.AttributeType.FullName == "Neo.SmartContract.Framework.ScriptAttribute")) count_attrs++; } @@ -273,14 +273,14 @@ public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opc foreach (var attr in defs.CustomAttributes) { - if (attr.AttributeType.Name == "OpCodeAttribute") + if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.OpCodeAttribute") { opcodes[i] = (VM.OpCode)attr.ConstructorArguments[0].Value; opdata[i] = (string)attr.ConstructorArguments[1].Value; i++; } - else if (attr.AttributeType.Name == "SyscallAttribute") + else if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.SyscallAttribute") { //var type = attr.ConstructorArguments[0].Type; var val = (string)attr.ConstructorArguments[0].Value; @@ -290,7 +290,7 @@ public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opc i++; } - else if (attr.AttributeType.Name == "ScriptAttribute") + else if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.ScriptAttribute") { //var type = attr.ConstructorArguments[0].Type; var val = (string)attr.ConstructorArguments[0].Value; @@ -301,7 +301,7 @@ public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opc i++; } - if (attr.AttributeType.Name == "ExtensionAttribute") + if (attr.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute") ext++; } @@ -328,7 +328,7 @@ public bool IsOpCall(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opcodes) foreach (var attr in defs.CustomAttributes) { - if (attr.AttributeType.Name == "OpCodeAttribute") + if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.OpCodeAttribute") { var type = attr.ConstructorArguments[0].Type; @@ -462,16 +462,18 @@ private int ConvertCall(OpCode src, NeoMethod to) calltype = 2; } } - else if (IsAppCall(defs, out callhash)) + else if (IsContractCall(defs, out callhash)) { calltype = 4; } else if (this.outModule.mapMethods.ContainsKey(src.tokenMethod)) - {//this is a call + { + //this is a call calltype = 1; } else - {//maybe a syscall // or other + { + //maybe a syscall // or other if (src.tokenMethod.Contains("::op_Explicit(") || src.tokenMethod.Contains("::op_Implicit(")) { //All types of display implicit conversion are ignored @@ -738,7 +740,8 @@ private int ConvertCall(OpCode src, NeoMethod to) //opcode call } else - {// reverse the arguments order + { + // reverse the arguments order //this become very diffcult @@ -798,7 +801,7 @@ private int ConvertCall(OpCode src, NeoMethod to) } else { - bytes = System.Text.Encoding.UTF8.GetBytes(callname); + bytes = System.Text.Utility.StrictUTF8.GetBytes(callname); if (bytes.Length > 252) throw new Exception("string is to long"); } byte[] outbytes = new byte[bytes.Length + 1]; @@ -829,17 +832,28 @@ private int ConvertCall(OpCode src, NeoMethod to) } else if (calltype == 4) { + // Package the arguments into an array. + ConvertPushNumber(pcount, null, to); + Convert1by1(VM.OpCode.PACK, null, to); + + // Push call method name, the first letter should be lowercase. + var methodName = defs.Body.Method.Name; + ConvertPushString(methodName[..1].ToLowerInvariant() + methodName[1..], src, to); + + // Push contract hash. ConvertPushDataArray(callhash, src, to); Insert1(VM.OpCode.SYSCALL, "", to, BitConverter.GetBytes(ApplicationEngine.System_Contract_Call)); + + // If the return type is void, insert a DROP. + if (defs.ReturnType.FullName is "System.Void") + Insert1(VM.OpCode.DROP, "", to); } else if (calltype == 5) { - //var callp = Encoding.UTF8.GetBytes(callname); - ConvertPushString(callname, src, to); - // package the arguments into an array - ConvertPushNumber(pcount + 1, null, to); + ConvertPushNumber(pcount, null, to); Convert1by1(VM.OpCode.PACK, null, to); + ConvertPushString(callname, src, to); //a syscall { @@ -1401,6 +1415,8 @@ private int ConvertNewObj(ILMethod from, OpCode src, NeoMethod to) { throw new Exception("unsupported type:System.Decimal."); } + if (_type.FullName.Contains("Neo.SmartContract.Framework.Map") && _type.FullName.Contains(" u.inSmartContract).Select(u => u.type.attributes.ToArray()).FirstOrDefault(); + var attr = outModule.mapMethods.Values.Where(u => u.inSmartContract).Select(u => u.type?.attributes.ToArray()).FirstOrDefault(); if (attr?.Length > 0) { outModule.attributes.AddRange(attr); @@ -173,7 +158,7 @@ private string InsertInitializeMethod() displayName = "_initialize", inSmartContract = true }; - initialize.returntype = "System.Void"; + initialize.returntype = FuncExport.Void; initialize.funcaddr = 0; if (!FillInitializeMethod(initialize)) { @@ -431,8 +416,8 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) Convert1by1(VM.OpCode.NOP, src, to); break; case CodeEx.Ret: - //return was handled outside - Insert1(VM.OpCode.RET, null, to); + // return was handled outside + Convert1by1(VM.OpCode.RET, src, to); break; case CodeEx.Pop: Convert1by1(VM.OpCode.DROP, src, to); @@ -921,10 +906,13 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) { Convert1by1(VM.OpCode.NOP, src, to); var d = src.tokenUnknown as Mono.Cecil.FieldDefinition; - // If readdonly, pull a const value + // If readonly, pull a const value if ( ((d.Attributes & Mono.Cecil.FieldAttributes.InitOnly) > 0) && - ((d.Attributes & Mono.Cecil.FieldAttributes.Static) > 0) + ((d.Attributes & Mono.Cecil.FieldAttributes.Static) > 0) && + // For a readonly Framework.Services, it can't be a const value, + // we should handle in initializemethod. + (!d.FieldType.FullName.Contains("Neo.SmartContract.Framework.Services")) ) { var fname = d.FullName;// d.DeclaringType.FullName + "::" + d.Name; @@ -965,18 +953,19 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) } //If this code was called by event, just find its name + var findEventFlag = false; if (d.DeclaringType.HasEvents) { foreach (var ev in d.DeclaringType.Events) { - if (ev.Name == d.Name && ev.EventType.FullName == d.FieldType.FullName) + if (ev.FullName == d.FullName && ev.EventType.FullName == d.FieldType.FullName) { - + findEventFlag = true; Mono.Collections.Generic.Collection ca = ev.CustomAttributes; to.lastsfieldname = d.Name; foreach (var attr in ca) { - if (attr.AttributeType.Name == "DisplayNameAttribute") + if (attr.AttributeType.FullName == "System.ComponentModel.DisplayNameAttribute") { to.lastsfieldname = (string)attr.ConstructorArguments[0].Value; } @@ -985,7 +974,7 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) } } } - else + if (!findEventFlag) { var field = this.outModule.mapFields[d.FullName]; Convert1by1(VM.OpCode.LDSFLD, src, to, new byte[] { (byte)field.index }); diff --git a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs index 3acec93e5..68984f6d5 100644 --- a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs +++ b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs @@ -1,3 +1,4 @@ +using Mono.Cecil; using System; using System.Collections.Generic; @@ -99,16 +100,16 @@ public ILType(ILModule module, Mono.Cecil.TypeDefinition type, ILogger logger) public class ILField { public bool isEvent = false; - public string type; + public TypeReference type; public string name; public string displayName; - public string returntype; + public TypeReference returntype; public List paramtypes = new List(); - public Mono.Cecil.FieldDefinition field; + public FieldDefinition field; - public ILField(ILType type, Mono.Cecil.FieldDefinition field) + public ILField(ILType type, FieldDefinition field) { - this.type = field.FieldType.FullName; + this.type = field.FieldType; this.name = field.Name; this.displayName = this.name; this.field = field; @@ -117,7 +118,7 @@ public ILField(ILType type, Mono.Cecil.FieldDefinition field) if (ev.Name == field.Name && ev.EventType.FullName == field.FieldType.FullName) { this.isEvent = true; - Mono.Collections.Generic.Collection ca = ev.CustomAttributes; + Mono.Collections.Generic.Collection ca = ev.CustomAttributes; foreach (var attr in ca) { if (attr.AttributeType.Name == "DisplayNameAttribute") @@ -125,7 +126,7 @@ public ILField(ILType type, Mono.Cecil.FieldDefinition field) this.displayName = (string)attr.ConstructorArguments[0].Value; } } - if (!(field.FieldType is Mono.Cecil.TypeDefinition eventtype)) + if (!(field.FieldType is TypeDefinition eventtype)) { try { @@ -142,47 +143,21 @@ public ILField(ILType type, Mono.Cecil.FieldDefinition field) { if (m.Name == "Invoke") { - this.returntype = m.ReturnType.FullName; - try - { - var _type = m.ReturnType.Resolve(); - foreach (var i in _type.Interfaces) - { - if (i.InterfaceType.Name == "IApiInterface") - { - this.returntype = "IInteropInterface"; - } - } - } - catch - { - } + this.returntype = m.ReturnType; foreach (var src in m.Parameters) { - string paramtype = src.ParameterType.FullName; if (src.ParameterType.IsGenericParameter) { - var gtype = src.ParameterType as Mono.Cecil.GenericParameter; + var gtype = src.ParameterType as GenericParameter; - var srcgtype = field.FieldType as Mono.Cecil.GenericInstanceType; + var srcgtype = field.FieldType as GenericInstanceType; var rtype = srcgtype.GenericArguments[gtype.Position]; - paramtype = rtype.FullName; - try - { - var _type = rtype.Resolve(); - foreach (var i in _type.Interfaces) - { - if (i.InterfaceType.Name == "IApiInterface") - { - paramtype = "IInteropInterface"; - } - } - } - catch - { - } + this.paramtypes.Add(new NeoParam(src.Name, rtype)); + } + else + { + this.paramtypes.Add(new NeoParam(src.Name, src.ParameterType)); } - this.paramtypes.Add(new NeoParam(src.Name, paramtype)); } } } @@ -194,7 +169,7 @@ public ILField(ILType type, Mono.Cecil.FieldDefinition field) public override string ToString() { - return type; + return FuncExport.ConvType(type); } } @@ -209,7 +184,7 @@ public class ILTryInfo { public int addr_Try_Begin = -1; public int addr_Try_End = -1; - public int addr_Try_End_F = -1;//IL try catch,try final is 2 different Block,need to process that. + public int addr_Try_End_F = -1;//IL try catch,try final is 2 different Block,need to process that. public Dictionary catch_Infos = new Dictionary(); public int addr_Finally_Begin = -1; public int addr_Finally_End = -1; @@ -218,8 +193,8 @@ public class ILTryInfo public class ILMethod { public ILType type = null; - public Mono.Cecil.MethodDefinition method; - public string returntype; + public MethodDefinition method; + public TypeReference returntype; public List paramtypes = new List(); public bool hasParam = false; public List body_Variables = new List(); @@ -227,35 +202,20 @@ public class ILMethod public string fail = null; public List tryInfos = new List(); public List tryPositions = new List(); - public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger = null) + public ILMethod(ILType type, MethodDefinition method, ILogger logger = null) { this.type = type; this.method = method; if (method != null) { - returntype = method.ReturnType.FullName; + returntype = method.ReturnType; if (method.HasParameters) { hasParam = true; foreach (var p in method.Parameters) { - string paramtype = p.ParameterType.FullName; - try - { - var _type = p.ParameterType.Resolve(); - foreach (var i in _type.Interfaces) - { - if (i.InterfaceType.Name == "IApiInterface") - { - paramtype = "IInteropInterface"; - } - } - } - catch - { - } - this.paramtypes.Add(new NeoParam(p.Name, paramtype)); + this.paramtypes.Add(new NeoParam(p.Name, p.ParameterType)); } } if (method.HasBody) @@ -265,8 +225,10 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger { foreach (var v in bodyNative.Variables) { - var indexname = v.VariableType.Name + ":" + v.Index; - this.body_Variables.Add(new NeoParam(indexname, v.VariableType.FullName)); + var indexname = method.DebugInformation.TryGetName(v, out var varname) + ? varname + : v.VariableType.Name + ":" + v.Index; + this.body_Variables.Add(new NeoParam(indexname, v.VariableType)); } } for (int i = 0; i < bodyNative.Instructions.Count; i++) @@ -279,10 +241,11 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger }; var sp = method.DebugInformation.GetSequencePoint(code); - if (sp != null) + if (sp != null && !sp.IsHidden) { c.debugcode = sp.Document.Url; c.debugline = sp.StartLine; + c.sequencePoint = sp; } c.InitToken(code.Operand); this.body_Codes.Add(c.addr, c); @@ -720,6 +683,7 @@ public class OpCode public CodeEx code; public int debugline = -1; public string debugcode; + public Mono.Cecil.Cil.SequencePoint sequencePoint; public object tokenUnknown; public int tokenAddr_Index; //public int tokenAddr; diff --git a/src/Neo.Compiler.MSIL/MyJson.cs b/src/Neo.Compiler.MSIL/MyJson.cs deleted file mode 100644 index dad29cfd4..000000000 --- a/src/Neo.Compiler.MSIL/MyJson.cs +++ /dev/null @@ -1,1328 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Neo.Compiler -{ - public class MyJson - { - public static IJsonNode Parse(string json) - { - try - { - ScanObj obj = new ScanObj - { - json = json, - seed = 0 - }; - IJsonNode node = Scan(obj); - return node; - } - catch (Exception err) - { - throw new Exception("parse err:" + json, err); - } - } - - internal static IJsonNode ScanFirst(char c) - { - if (c == ' ' || c == '\n' || c == '\r' || c == '\t') - { - return null; - } - if (c == '{') - { - return new JsonNode_Object(); - } - else if (c == '[') - { - return new JsonNode_Array(); - } - else if (c == '"') - { - return new JsonNode_ValueString(); - } - else - { - return new JsonNode_ValueNumber(); - } - } - - public class ScanObj - { - public string json; - public int seed; - } - - internal static IJsonNode Scan(ScanObj scan) - { - for (int i = 0; i < scan.json.Length; i++) - { - IJsonNode node = ScanFirst(scan.json[i]); - if (node != null) - { - scan.seed = i; - node.Scan(scan); - return node; - } - } - return null; - } - - public enum JsonType - { - Value_Number, - Value_String, - Array, - Object, - } - - public interface IJsonNode - { - JsonType type { get; } - - void ConvertToString(StringBuilder sb); - - void ConvertToStringPhp(StringBuilder sb); - - void ConvertToStringWithFormat(StringBuilder sb, int spacesub); - - void ConvertToStringPhpWithFormat(StringBuilder sb, int spacesub); - - void Scan(MyJson.ScanObj scan); - - IJsonNode Get(string path); - - IJsonNode GetArrayItem(int index); // fast access - - IJsonNode GetDictItem(string key); - - void AddArrayValue(IJsonNode node); - - void AddArrayValue(double value); - - void AddArrayValue(bool value); - - void AddArrayValue(string value); - - void SetArrayValue(int index, IJsonNode node); - - void SetArrayValue(int index, double value); - - void SetArrayValue(int index, bool value); - - void SetArrayValue(int index, string value); - - void SetDictValue(string key, IJsonNode node); - - void SetDictValue(string key, double value); - - void SetDictValue(string key, bool value); - - void SetDictValue(string key, string value); - - void SetValue(double value); - - void SetValue(string value); - - void SetValue(bool value); - - double AsDouble(); - - int AsInt(); - - bool AsBool(); - - bool IsNull(); - - String AsString(); - - IList AsList(); - - IDictionary asDict(); - - bool HaveDictItem(string key); - - int GetListCount(); - } - - public class JsonNode_ValueNumber : IJsonNode - { - public JsonNode_ValueNumber() - { - } - - public JsonNode_ValueNumber(double value) - { - this.value = value; - this.isBool = false; - } - - public JsonNode_ValueNumber(bool value) - { - this.value = value ? 1 : 0; - this.isBool = true; - } - - public double value { get; set; } - public bool isBool { get; private set; } - public bool isNull { get; private set; } - - public void SetNull() - { - this.isNull = true; - this.isBool = false; - } - - public void SetBool(bool v) - { - this.value = v ? 1 : 0; - this.isBool = true; - } - - public override string ToString() - { - if (isBool) - { - return ((bool)this) ? "true" : "false"; - } - else if (isNull) - { - return "null"; - } - else - { - return value.ToString(); - } - } - - public JsonType type - { - get - { - return JsonType.Value_Number; - } - } - - public void ConvertToString(StringBuilder sb) - { - sb.Append(ToString()); - } - - public void ConvertToStringWithFormat(StringBuilder sb, int spacesub) - { - ConvertToString(sb); - } - - public void ConvertToStringPhp(StringBuilder sb) - { - - sb.Append(ToString()); - } - - public void ConvertToStringPhpWithFormat(StringBuilder sb, int spacesub) - { - ConvertToStringPhp(sb); - } - - public void Scan(MyJson.ScanObj scan) - { - string number = ""; - for (int i = scan.seed; i < scan.json.Length; i++) - { - char c = scan.json[i]; - if (c != ',' && c != ']' && c != '}' && c != ' ') - { - if (c != '\n') - number += c; - } - else - { - scan.seed = i; - break; - } - } - - if (number.ToLower() == "true") - { - value = 1; - isBool = true; - } - else if (number.ToLower() == "false") - { - value = 0; - isBool = true; - } - else if (number.ToLower() == "null") - { - value = 0; - isNull = true; - } - else - { - value = double.Parse(number); - isBool = false; - } - } - - public static implicit operator double(JsonNode_ValueNumber m) - { - return m.value; - } - - public static implicit operator float(JsonNode_ValueNumber m) - { - return (float)m.value; - } - - public static implicit operator int(JsonNode_ValueNumber m) - { - return (int)m.value; - } - - public static implicit operator uint(JsonNode_ValueNumber m) - { - return (uint)m.value; - } - - public static implicit operator bool(JsonNode_ValueNumber m) - { - return (uint)m.value != 0; - } - public IJsonNode Get(string path) - { - if (string.IsNullOrEmpty(path)) return this; - - return null; - } - - public IJsonNode GetArrayItem(int index) - { - throw new NotImplementedException(); - } - - public IJsonNode GetDictItem(string key) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(IJsonNode node) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(double value) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(bool value) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(string value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, IJsonNode node) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, double value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, bool value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, string value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, IJsonNode node) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, double value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, bool value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, string value) - { - throw new NotImplementedException(); - } - - public void SetValue(double value) - { - this.value = value; - this.isBool = false; - this.isNull = false; - } - - public void SetValue(string value) - { - throw new NotImplementedException(); - } - - public void SetValue(bool value) - { - this.value = value ? 1 : 0; - this.isBool = true; - this.isNull = false; - } - - public double AsDouble() - { - if (!this.isNull && !this.isBool) - return this.value; - throw new Exception("Different value type"); - } - - public int AsInt() - { - if (!this.isNull && !this.isBool) - return (int)this.value; - throw new Exception("Different value type"); - } - - public bool AsBool() - { - if (this.isBool) - { - return (uint)value != 0; - } - throw new Exception("Different value type"); - } - - public bool IsNull() - { - return isNull; - } - - public string AsString() - { - throw new NotImplementedException(); - } - - public IList AsList() - { - throw new NotImplementedException(); - } - - public IDictionary asDict() - { - throw new NotImplementedException(); - } - - public bool HaveDictItem(string key) - { - throw new NotImplementedException(); - } - - public int GetListCount() - { - throw new NotImplementedException(); - } - } - - public class JsonNode_ValueString : IJsonNode - { - public JsonNode_ValueString() - { - } - - public JsonNode_ValueString(string value) - { - this.value = value; - } - - public string value { get; set; } - - public override string ToString() - { - return value; - } - - public JsonType type - { - get - { - return JsonType.Value_String; - } - } - - public void ConvertToString(StringBuilder sb) - { - sb.Append('\"'); - if (value != null) - { - string v = value.Replace("\\", "\\\\"); - v = v.Replace("\"", "\\\""); - sb.Append(v); - } - sb.Append('\"'); - } - - public void ConvertToStringWithFormat(StringBuilder sb, int spacesub) - { - ConvertToString(sb); - } - - public void ConvertToStringPhp(StringBuilder sb) - { - sb.Append('\"'); - if (value != null) - { - string v = value.Replace("\\", "\\\\"); - v = v.Replace("\"", "\\\""); - sb.Append(v); - } - sb.Append('\"'); - } - - public void ConvertToStringPhpWithFormat(StringBuilder sb, int spacesub) - { - ConvertToStringPhp(sb); - } - - public void Scan(MyJson.ScanObj scan) - { - string _value = ""; - for (int i = scan.seed + 1; i < scan.json.Length; i++) - { - char c = scan.json[i]; - if (c == '\\') - { - i++; - c = scan.json[i]; - _value += c; - } - - else if (c != '\"') - { - - _value += c; - } - - else - { - scan.seed = i + 1; - break; - } - } - value = _value; - } - - public static implicit operator string(JsonNode_ValueString m) - { - return m.value; - } - - public IJsonNode Get(string path) - { - if (string.IsNullOrEmpty(path)) return this; - - return null; - } - - public IJsonNode GetArrayItem(int index) - { - throw new NotImplementedException(); - } - - public IJsonNode GetDictItem(string key) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(IJsonNode node) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(double value) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(bool value) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(string value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, IJsonNode node) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, double value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, bool value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, string value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, IJsonNode node) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, double value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, bool value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, string value) - { - throw new NotImplementedException(); - } - - public void SetValue(double value) - { - throw new NotImplementedException(); - } - - public void SetValue(string value) - { - this.value = value; - } - - public void SetValue(bool value) - { - throw new NotImplementedException(); - } - - public double AsDouble() - { - throw new NotImplementedException(); - } - - public int AsInt() - { - throw new NotImplementedException(); - } - - public bool AsBool() - { - throw new NotImplementedException(); - } - - public bool IsNull() - { - return false; - } - - public string AsString() - { - return value; - } - - public IList AsList() - { - throw new NotImplementedException(); - } - - public IDictionary asDict() - { - throw new NotImplementedException(); - } - - public bool HaveDictItem(string key) - { - throw new NotImplementedException(); - } - - public int GetListCount() - { - throw new NotImplementedException(); - } - } - - public class JsonNode_Array : List, IJsonNode - { - public JsonType type - { - get { return JsonType.Array; } - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - ConvertToString(sb); - return sb.ToString(); - } - - public void ConvertToString(StringBuilder sb) - { - sb.Append('['); - for (int i = 0; i < this.Count; i++) - { - this[i].ConvertToString(sb); - if (i != this.Count - 1) - sb.Append(','); - } - sb.Append(']'); - } - - public void ConvertToStringWithFormat(StringBuilder sb, int spacesub) - { - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - sb.Append("[\n"); - - for (int i = 0; i < this.Count; i++) - { - if (this[i] is MyJson.JsonNode_Object || this[i] is MyJson.JsonNode_Array) - { - - } - else - { - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - } - this[i].ConvertToStringWithFormat(sb, spacesub + 4); - if (i != this.Count - 1) - sb.Append(','); - sb.Append('\n'); - } - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - sb.Append(']'); - } - - public void ConvertToStringPhp(StringBuilder sb) - { - sb.Append("Array("); - for (int i = 0; i < this.Count; i++) - { - this[i].ConvertToStringPhp(sb); - if (i != this.Count - 1) - sb.Append(','); - } - sb.Append(')'); - } - - public void ConvertToStringPhpWithFormat(StringBuilder sb, int spacesub) - { - sb.Append("Array(\n"); - for (int i = 0; i < this.Count; i++) - { - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - - this[i].ConvertToStringPhpWithFormat(sb, spacesub + 4); - if (i != this.Count - 1) - sb.Append(','); - sb.Append('\n'); - } - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - sb.Append(')'); - } - - public void Scan(MyJson.ScanObj scan) - { - for (int i = scan.seed + 1; i < scan.json.Length; i++) - { - char c = scan.json[i]; - if (c == ',') - continue; - if (c == ']') - { - scan.seed = i + 1; - break; - } - IJsonNode node = MyJson.ScanFirst(c); - if (node != null) - { - scan.seed = i; - node.Scan(scan); - i = scan.seed - 1; - this.Add(node); - } - } - } - - public int GetFirstKey02(string path, int start, out string nextpath) - { - int _path = -1; - for (int i = start + 1; i < path.Length; i++) - { - if (path[i] == '[') - { - _path = GetFirstKey02(path, i, out _); - } - if (path[i] == ']') - { - nextpath = path.Substring(i + 1); - if (_path == -1) - { - _path = int.Parse(path.Substring(start + 1, i - start - 1)); - } - return _path; - } - } - nextpath = null; - return -1; - } - - public int GetFirstKey(string path, out string nextpath) - { - nextpath = null; - int istart = 0; - for (int i = 0; i < path.Length; i++) - { - if (path[i] == '.' || path[i] == ' ') - { - istart++; - continue; - } - if (path[i] == '[') - { - return GetFirstKey02(path, i, out nextpath); - } - } - return -1; - } - - public IJsonNode Get(string path) - { - if (path.Length == 0) return this; - int key = GetFirstKey(path, out _); - if (key >= 0 && key < this.Count) - { - return this[key]; - } - else - { - return null; - } - } - - public IJsonNode GetArrayItem(int index) - { - return this[index]; - } - - public IJsonNode GetDictItem(string key) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(IJsonNode node) - { - this.Add(node); - } - - public void AddArrayValue(double value) - { - this.Add(new MyJson.JsonNode_ValueNumber(value)); - } - - public void AddArrayValue(bool value) - { - this.Add(new MyJson.JsonNode_ValueNumber(value)); - } - - public void AddArrayValue(string value) - { - this.Add(new MyJson.JsonNode_ValueString(value)); - } - - public void SetArrayValue(int index, IJsonNode node) - { - this[index] = node; - } - - public void SetArrayValue(int index, double value) - { - this[index] = new MyJson.JsonNode_ValueNumber(value); - } - - public void SetArrayValue(int index, bool value) - { - this[index] = new MyJson.JsonNode_ValueNumber(value); - } - - public void SetArrayValue(int index, string value) - { - this[index] = new MyJson.JsonNode_ValueString(value); - } - - public void SetDictValue(string key, IJsonNode node) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, double value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, bool value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, string value) - { - throw new NotImplementedException(); - } - - public void SetValue(double value) - { - throw new NotImplementedException(); - } - - public void SetValue(string value) - { - throw new NotImplementedException(); - } - - public void SetValue(bool value) - { - throw new NotImplementedException(); - } - - public double AsDouble() - { - throw new NotImplementedException(); - } - - public int AsInt() - { - throw new NotImplementedException(); - } - - public bool AsBool() - { - throw new NotImplementedException(); - } - - public bool IsNull() - { - return false; - } - - public string AsString() - { - throw new NotImplementedException(); - } - - public IList AsList() - { - return this; - } - - public IDictionary asDict() - { - throw new NotImplementedException(); - } - - public bool HaveDictItem(string key) - { - throw new NotImplementedException(); - } - - public int GetListCount() - { - return this.Count; - } - } - - public class JsonNode_Object : Dictionary, IJsonNode - { - public JsonType type - { - get { return JsonType.Object; } - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - ConvertToString(sb); - return sb.ToString(); - } - - public void ConvertToString(StringBuilder sb) - { - sb.Append('{'); - int i = Count; - foreach (var item in this) - { - sb.Append('\"'); - sb.Append(item.Key); - sb.Append("\":"); - item.Value.ConvertToString(sb); - i--; - if (i != 0) sb.Append(','); - } - sb.Append('}'); - } - - public void ConvertToStringWithFormat(StringBuilder sb, int spacesub) - { - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - sb.Append("{\n"); - int i = Count; - foreach (var item in this) - { - for (int _i = 0; _i < spacesub + 4; _i++) - sb.Append(' '); - - sb.Append('\"'); - sb.Append(item.Key); - sb.Append("\":"); - if (item.Value is MyJson.JsonNode_Array || item.Value is MyJson.JsonNode_Object) - sb.Append('\n'); - item.Value.ConvertToStringWithFormat(sb, spacesub + 4); - i--; - if (i != 0) sb.Append(','); - sb.Append('\n'); - } - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - sb.Append('}'); - } - - public void ConvertToStringPhp(StringBuilder sb) - { - sb.Append("Array("); - int i = Count; - foreach (var item in this) - { - sb.Append('\"'); - sb.Append(item.Key); - sb.Append("\"=>"); - item.Value.ConvertToStringPhp(sb); - i--; - if (i != 0) sb.Append(','); - } - sb.Append(')'); - } - - public void ConvertToStringPhpWithFormat(StringBuilder sb, int spacesub) - { - sb.Append("Array(\n"); - int i = Count; - foreach (var item in this) - { - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - - sb.Append('\"'); - sb.Append(item.Key); - sb.Append("\"=>"); - item.Value.ConvertToStringPhpWithFormat(sb, spacesub + 4); - i--; - if (i != 0) sb.Append(','); - sb.Append('\n'); - } - for (int _i = 0; _i < spacesub; _i++) - sb.Append(' '); - sb.Append(')'); - } - - public void Scan(MyJson.ScanObj scan) - { - string key = null; - int keystate = 0; //0 nokey 1scankey 2gotkey - for (int i = scan.seed + 1; i < scan.json.Length; i++) - { - char c = scan.json[i]; - if (keystate != 1 && (c == ',' || c == ':')) - continue; - if (c == '}') - { - scan.seed = i + 1; - break; - } - if (keystate == 0) - { - if (c == '\"') - { - keystate = 1; - key = ""; - } - } - else if (keystate == 1) - { - if (c == '\"') - { - keystate = 2; - continue; - } - else - { - key += c; - } - } - else - { - IJsonNode node = MyJson.ScanFirst(c); - if (node != null) - { - scan.seed = i; - node.Scan(scan); - i = scan.seed - 1; - this.Add(key, node); - keystate = 0; - } - } - } - } - - public string GetFirstKey01(string path, int start, out string nextpath) - { - for (int i = start + 1; i < path.Length; i++) - { - if (path[i] == '\\') continue; - if (path[i] == '\"') - { - nextpath = path.Substring(i + 1); - var _path = path.Substring(start + 1, i - start - 1); - return _path; - } - } - nextpath = null; - return null; - } - - public string GetFirstKey02(string path, int start, out string nextpath) - { - string _path = null; - for (int i = start + 1; i < path.Length; i++) - { - if (path[i] == '[') - { - _path = GetFirstKey02(path, i, out _); - } - if (path[i] == '\"') - { - _path = GetFirstKey01(path, i, out _); - i += _path.Length + 2; - } - if (path[i] == ']') - { - nextpath = path.Substring(i + 1); - if (_path == null) - { - _path = path.Substring(start + 1, i - start - 1); - } - return _path; - } - } - nextpath = null; - return null; - } - - public string GetFirstKey(string path, out string nextpath) - { - nextpath = null; - int istart = 0; - for (int i = 0; i < path.Length; i++) - { - if (path[i] == '.' || path[i] == ' ') - { - istart++; - continue; - } - if (path[i] == '[') - { - return GetFirstKey02(path, i, out nextpath); - } - else if (path[i] == '\"') - { - return GetFirstKey01(path, i, out nextpath); - } - else - { - int iend1 = path.IndexOf('[', i + 1); - if (iend1 == -1) iend1 = path.Length; - int iend2 = path.IndexOf('.', i + 1); - if (iend2 == -1) iend2 = path.Length; - int iss = Math.Min(iend1, iend2); - - var _path = path.Substring(istart, iss - istart); - nextpath = path.Substring(iss); - return _path; - } - } - return null; - } - - public IJsonNode Get(string path) - { - if (path.Length == 0) return this; - string key = GetFirstKey(path, out string nextpath); - if (!this.ContainsKey(key)) return null; - - return this[key].Get(nextpath); - } - - public IJsonNode GetArrayItem(int index) - { - throw new NotImplementedException(); - } - - public IJsonNode GetDictItem(string key) - { - return this[key]; - } - - public void AddArrayValue(IJsonNode node) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(double value) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(bool value) - { - throw new NotImplementedException(); - } - - public void AddArrayValue(string value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, IJsonNode node) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, double value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, bool value) - { - throw new NotImplementedException(); - } - - public void SetArrayValue(int index, string value) - { - throw new NotImplementedException(); - } - - public void SetDictValue(string key, IJsonNode node) - { - this[key] = node; - } - - public void SetDictValue(string key, double value) - { - this[key] = new JsonNode_ValueNumber(value); - } - - public void SetDictValue(string key, bool value) - { - this[key] = new JsonNode_ValueNumber(value); - } - - public void SetDictValue(string key, string value) - { - this[key] = new JsonNode_ValueString(value); - } - - public void SetValue(double value) - { - throw new NotImplementedException(); - } - - public void SetValue(string value) - { - throw new NotImplementedException(); - } - - public void SetValue(bool value) - { - throw new NotImplementedException(); - } - - public double AsDouble() - { - throw new NotImplementedException(); - } - - public int AsInt() - { - throw new NotImplementedException(); - } - - public bool AsBool() - { - throw new NotImplementedException(); - } - - public bool IsNull() - { - return false; - } - - public string AsString() - { - throw new NotImplementedException(); - } - - public IList AsList() - { - throw new NotImplementedException(); - } - - public IDictionary asDict() - { - return this; - } - - public bool HaveDictItem(string key) - { - return ContainsKey(key); - } - - public int GetListCount() - { - throw new NotImplementedException(); - } - } - } -} diff --git a/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj b/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj index 78a8b89f0..c19286e6f 100644 --- a/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj +++ b/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj @@ -3,12 +3,10 @@ 2015-2020 The Neo Project Neo.Compiler.MSIL - 3.0.0-preview2 + 3.0.0-preview3 The Neo Project - netcoreapp3.1;netstandard2.1 Exe neon - Neo.Compiler.MSIL NEO;Blockchain;Smart Contract;Compiler https://github.com/neo-project/neo-devpack-dotnet MIT @@ -21,12 +19,30 @@ true + + + + Exe + Neo.Neon + true + netcoreapp3.1 + + + + Neo.Compiler.MSIL + netstandard2.1 + + - + diff --git a/src/Neo.Compiler.MSIL/NeoModule.cs b/src/Neo.Compiler.MSIL/NeoModule.cs index 887b91433..f778b2aff 100644 --- a/src/Neo.Compiler.MSIL/NeoModule.cs +++ b/src/Neo.Compiler.MSIL/NeoModule.cs @@ -1,5 +1,6 @@ using Mono.Cecil; using Neo.Compiler.MSIL; +using Neo.IO.Json; using System; using System.Collections.Generic; using System.ComponentModel; @@ -37,11 +38,11 @@ public byte[] Build() public string GenJson() { - MyJson.JsonNode_Object json = new MyJson.JsonNode_Object(); - json["__name__"] = new MyJson.JsonNode_ValueString("neomodule."); + JObject json = new JObject(); + json["__name__"] = "neomodule."; //code - var jsoncode = new MyJson.JsonNode_Array(); + var jsoncode = new JArray(); json["code"] = jsoncode; foreach (var c in this.totalCodes.Values) { @@ -54,34 +55,17 @@ public string GenJson() { codestr += c.ToString("X02"); } - json.SetDictValue("codebin", codestr); + json["codebin"] = codestr; //calls - MyJson.JsonNode_Object methodinfo = new MyJson.JsonNode_Object(); + JObject methodinfo = new JObject(); json["call"] = methodinfo; foreach (var m in this.mapMethods) { methodinfo[m.Key] = m.Value.GenJson(); } - StringBuilder sb = new StringBuilder(); - json.ConvertToStringWithFormat(sb, 4); - return sb.ToString(); - } - - internal void ConvertFuncAddr() - { - foreach (var method in this.mapMethods.Values) - { - foreach (var code in method.body_Codes.Values) - { - if (code.code != VM.OpCode.NOP) - { - method.funcaddr = code.addr; - break; - } - } - } + return json.ToString(true); } } @@ -96,7 +80,7 @@ public class NeoMethod public string name; public string displayName; public List paramtypes = new List(); - public string returntype; + public TypeReference returntype; public bool isPublic = true; public bool inSmartContract; public ILMethod method; @@ -106,19 +90,19 @@ public class NeoMethod public SortedDictionary body_Codes = new SortedDictionary(); // Temporary records and will be merged later public int funcaddr; - public MyJson.JsonNode_Object GenJson() + public JObject GenJson() { - MyJson.JsonNode_Object json = new MyJson.JsonNode_Object(); - json.SetDictValue("name", this.name); - json.SetDictValue("returntype", this.returntype); - json.SetDictValue("paramcount", this.paramtypes.Count); - MyJson.JsonNode_Array jsonparams = new MyJson.JsonNode_Array(); - json.SetDictValue("params", jsonparams); + JObject json = new JObject(); + json["name"] = this.name; + json["returntype"] = FuncExport.ConvType(this.returntype); + json["paramcount"] = this.paramtypes.Count; + JArray jsonparams = new JArray(); + json["params"] = jsonparams; for (var i = 0; i < this.paramtypes.Count; i++) { - MyJson.JsonNode_Object item = new MyJson.JsonNode_Object(); - item.SetDictValue("name", this.paramtypes[i].name); - item.SetDictValue("type", this.paramtypes[i].type); + JObject item = new JObject(); + item["name"] = this.paramtypes[i].name; + item["type"] = FuncExport.ConvType(this.paramtypes[i].type); jsonparams.Add(item); } return json; @@ -134,7 +118,7 @@ public NeoMethod(ILMethod method) _namespace = method.method.DeclaringType.FullName; name = method.method.FullName; displayName = method.method.Name[..1].ToLowerInvariant() + method.method.Name[1..]; - inSmartContract = method.method.DeclaringType.BaseType.Name == "SmartContract"; + inSmartContract = method.method.DeclaringType.BaseType.FullName == "Neo.SmartContract.Framework.SmartContract"; isPublic = method.method.IsPublic; foreach (var attr in method.method.CustomAttributes) @@ -170,7 +154,7 @@ public NeoEvent(ILField value) displayName = value.displayName; paramtypes = value.paramtypes; - if (value.returntype != "System.Void") + if (FuncExport.ConvType(value.returntype) != "Void") { throw new NotSupportedException($"NEP-3 does not support return types for events. Expected: `System.Void`, Detected: `{value.returntype}`"); } @@ -191,6 +175,7 @@ public class NeoCode public int srcaddr; public int[] srcaddrswitch; public string srcfunc; + public Mono.Cecil.Cil.SequencePoint sequencePoint; public override string ToString() { @@ -216,7 +201,7 @@ public override string ToString() return info; } - public MyJson.JsonNode_ValueString GenJson() + public string GenJson() { string info = "" + addr.ToString("X04") + " " + code.ToString(); for (var j = 0; j < 16 - code.ToString().Length; j++) @@ -241,7 +226,7 @@ public MyJson.JsonNode_ValueString GenJson() { info += "//" + debugcode + "(" + debugline + ")"; } - return new MyJson.JsonNode_ValueString(info); + return info; } } @@ -249,7 +234,7 @@ public class NeoField : NeoParam { public int index { get; private set; } - public NeoField(string name, string type, int index) : base(name, type) + public NeoField(string name, TypeReference type, int index) : base(name, type) { this.index = index; } @@ -258,9 +243,9 @@ public NeoField(string name, string type, int index) : base(name, type) public class NeoParam { public string name { get; private set; } - public string type { get; private set; } + public TypeReference type { get; private set; } - public NeoParam(string name, string type) + public NeoParam(string name, TypeReference type) { this.name = name; this.type = type; @@ -268,7 +253,7 @@ public NeoParam(string name, string type) public override string ToString() { - return type + " " + name; + return FuncExport.ConvType(type) + " " + name; } } } diff --git a/src/Neo.Compiler.MSIL/Optimizer/NefOptimizer.cs b/src/Neo.Compiler.MSIL/Optimizer/NefOptimizer.cs index 9b5b659a6..1723cf34b 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/NefOptimizer.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/NefOptimizer.cs @@ -70,19 +70,19 @@ public void Optimize() /// Entry points public void LoadNef(Stream stream, int[] entryPoints) { - //read all Instruction to listInst + // Read all Instruction to listInst. var listInst = new List(); - //read all Address to listAddr + // Read all Address to listAddr. var mapLabel = new Dictionary(); int labelindex = 1; - //insert EntryPointLabel + // Insert EntryPoint Label. for (var i = 0; i < entryPoints.Length; i++) { if (i > 0 && entryPoints[i - 1] == entryPoints[i]) { - //不允许出现一样的EntryPoint - throw new Exception("now allow same EntryPoint."); + // Same EntryPoints are not allowed + throw new Exception("Same EntryPoints are not allowed."); } if (!mapLabel.ContainsKey(entryPoints[i])) { @@ -116,7 +116,6 @@ public void LoadNef(Stream stream, int[] entryPoints) labelindex++; var label = new NefLabel(labelname, addr); mapLabel.Add(addr, label); - } inst.Labels[i] = mapLabel[addr].Name; @@ -124,8 +123,7 @@ public void LoadNef(Stream stream, int[] entryPoints) } } while (inst != null); - - //Add Labels and split to Methods + // Add Labels and split to Methods Methods = new List(); var curMethod = new NefMethod(); diff --git a/src/Neo.Compiler.MSIL/Optimizer/OptimizerExtensions.cs b/src/Neo.Compiler.MSIL/Optimizer/OptimizerExtensions.cs index af08c796b..afbd5ecce 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/OptimizerExtensions.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/OptimizerExtensions.cs @@ -31,6 +31,19 @@ public static bool IsValidValue(this BigInteger value) return true; } + public static bool IsPushOrNull(this NefInstruction ins, out BigInteger? value) + { + if (ins.OpCode == OpCode.PUSHNULL) + { + value = null; + return true; + } + + var ret = IsPush(ins, out var retval); + value = retval; + return ret; + } + public static bool IsPush(this NefInstruction ins, out BigInteger value) { switch (ins.OpCode) @@ -82,5 +95,22 @@ public static bool IsPush(this NefInstruction ins, out BigInteger value) value = 0; return false; } + + public static bool IsPushData(this NefInstruction ins, out byte[] value) + { + switch (ins.OpCode) + { + case OpCode.PUSHDATA1: + case OpCode.PUSHDATA2: + case OpCode.PUSHDATA4: + { + value = ins.Data; + return true; + } + } + + value = null; + return false; + } } } diff --git a/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteConstExecution.cs b/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteConstExecution.cs index c398d4e61..8edece09d 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteConstExecution.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteConstExecution.cs @@ -60,7 +60,7 @@ public void Parse(List items) { if (items[x - 1] is NefInstruction p1) { - if (p1.IsPush(out _) || (p1.OpCode == OpCode.PUSHNULL)) + if (p1.IsPushOrNull(out _)) { items.RemoveRange(x - 1, 2); OptimizedCount++; @@ -233,6 +233,30 @@ public void Parse(List items) } break; } + + // Three stack items + + case OpCode.ROT: + { + if (x >= 3 && + items[x - 1] is NefInstruction p1 && + items[x - 2] is NefInstruction p2 && + items[x - 3] is NefInstruction p3 && + (p1.IsPushOrNull(out _) || p1.IsPushData(out _)) && + (p2.IsPushOrNull(out _) || p2.IsPushData(out _)) && + (p3.IsPushOrNull(out _) || p3.IsPushData(out _)) + ) + { + items[x - 3] = p2; + items[x - 2] = p1; + items[x - 1] = p3; + + items.RemoveRange(x, 1); + OptimizedCount++; + x -= 3; + } + break; + } } } } diff --git a/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs b/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs index 45698f75a..2f93ea087 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs @@ -1,5 +1,6 @@ using Neo.VM; using System.Collections.Generic; + namespace Neo.Compiler.Optimizer { class Parser_DeleteDeadCode : IOptimizeParser @@ -16,9 +17,8 @@ public void Init() public void Parse(List items) { - List reachableAddrs = new List(); + var reachableAddrs = new HashSet(); Touch(items, reachableAddrs, 0); - reachableAddrs.Sort(); // Remove useless instructions like JPMIF false xxx // If the previous instruction of JMPIF is PUSH, we can tell whether JMPIF is useful in advance @@ -35,7 +35,7 @@ public void Parse(List items) } } - private static void Touch(List items, List reachableAddrs, int beginAddr) + private static void Touch(List items, HashSet reachableAddrs, int beginAddr) { for (int i = 0; i < items.Count; i++) { @@ -43,10 +43,7 @@ private static void Touch(List items, List reachableAddrs, int be if (inst.Offset < beginAddr) continue; if (inst.OpCode == OpCode.NOP) continue; // NOP never touch - if (!reachableAddrs.Contains(inst.Offset)) - { - reachableAddrs.Add(inst.Offset); - } + reachableAddrs.Add(inst.Offset); // Try is not linear. If encounter a try, skip to the catch and finally segments to scan. // If encounter endtry, will also skip to finally segment to scan @@ -56,9 +53,8 @@ private static void Touch(List items, List reachableAddrs, int be for (var j = 0; j < inst.AddressCountInData; j++) { var addr = inst.GetAddressInData(j) + inst.Offset; - if (!reachableAddrs.Contains(addr)) + if (reachableAddrs.Add(addr)) { - reachableAddrs.Add(addr); Touch(items, reachableAddrs, addr); // goto the JMP/call/... new address } } diff --git a/src/Neo.Compiler.MSIL/Program.cs b/src/Neo.Compiler.MSIL/Program.cs index 3f0ab9d9a..31cd8f2c6 100644 --- a/src/Neo.Compiler.MSIL/Program.cs +++ b/src/Neo.Compiler.MSIL/Program.cs @@ -2,11 +2,13 @@ using Mono.Cecil; using Neo.Compiler.MSIL; using Neo.Compiler.Optimizer; +using Neo.IO.Json; using Neo.SmartContract; using Neo.SmartContract.Manifest; using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Reflection; using System.Text; @@ -29,12 +31,12 @@ public static void Main(string[] args) Parser.Default.ParseArguments(args).WithParsed(o => Environment.ExitCode = Compile(o)); } - public static int Compile(Options options) + public static int Compile(Options options, ILogger log = null) { // Set console Console.OutputEncoding = Encoding.UTF8; - var log = new DefLogger(); - log.Log("Neo.Compiler.MSIL console app v" + Assembly.GetEntryAssembly().GetName().Version); + log ??= new DefLogger(); + log.Log("Neo.Compiler.MSIL console app v" + Assembly.GetAssembly(typeof(Program)).GetName().Version); var fileInfo = new FileInfo(options.File); @@ -149,10 +151,11 @@ public static int Compile(Options options) log.Log("LoadModule Error:" + err.ToString()); return -1; } + JObject abi; byte[] bytes; int bSucc = 0; - string jsonstr = null; - NeoModule module = null; + string debugstr = null; + NeoModule module; // Convert and build try @@ -165,14 +168,10 @@ public static int Compile(Options options) Dictionary addrConvTable = null; if (options.Optimize) { - module.ConvertFuncAddr(); - List entryPoints = new List(); - + HashSet entryPoints = new HashSet(); foreach (var func in module.mapMethods) { - int srcaddr = func.Value.funcaddr; - if (entryPoints.Contains(srcaddr) == false) - entryPoints.Add(srcaddr); + entryPoints.Add(func.Value.funcaddr); } var optimize = NefOptimizeTool.Optimize(bytes, entryPoints.ToArray(), out addrConvTable); log.Log("optimization succ " + (((bytes.Length / (optimize.Length + 0.0)) * 100.0) - 100).ToString("0.00 '%'")); @@ -181,10 +180,7 @@ public static int Compile(Options options) try { - var outjson = vmtool.FuncExport.Export(module, bytes, addrConvTable); - StringBuilder sb = new StringBuilder(); - outjson.ConvertToStringWithFormat(sb, 0); - jsonstr = sb.ToString(); + abi = FuncExport.Export(module, bytes, addrConvTable); log.Log("gen abi succ"); } catch (Exception err) @@ -192,6 +188,17 @@ public static int Compile(Options options) log.Log("gen abi Error:" + err.ToString()); return -1; } + + try + { + var outjson = DebugExport.Export(module, bytes, addrConvTable); + debugstr = outjson.ToString(false); + log.Log("gen debug succ"); + } + catch (Exception err) + { + log.Log("gen debug Error:" + err.ToString()); + } } catch (Exception err) { @@ -207,7 +214,7 @@ public static int Compile(Options options) var nef = new NefFile { Compiler = "neon", - Version = Version.Parse(((AssemblyFileVersionAttribute)Assembly.GetExecutingAssembly() + Version = Version.Parse(((AssemblyFileVersionAttribute)Assembly.GetAssembly(typeof(Program)) .GetCustomAttribute(typeof(AssemblyFileVersionAttribute))).Version), Script = bytes, ScriptHash = bytes.ToScriptHash() @@ -231,10 +238,11 @@ public static int Compile(Options options) try { + var sbABI = abi.ToString(false); string abiname = onlyname + ".abi.json"; File.Delete(abiname); - File.WriteAllText(abiname, jsonstr); + File.WriteAllText(abiname, sbABI.ToString()); log.Log("write:" + abiname); bSucc++; } @@ -246,22 +254,31 @@ public static int Compile(Options options) try { - var features = module == null ? ContractFeatures.NoProperty : module.attributes - .Where(u => u.AttributeType.Name == "FeaturesAttribute") - .Select(u => (ContractFeatures)u.ConstructorArguments.FirstOrDefault().Value) - .FirstOrDefault(); - - var extraAttributes = module == null ? new List>() : module.attributes.Where(u => u.AttributeType.Name == "ManifestExtraAttribute").Select(attribute => attribute.ConstructorArguments).ToList(); - - var extra = BuildExtraAttributes(extraAttributes); - var storage = features.HasFlag(ContractFeatures.HasStorage).ToString().ToLowerInvariant(); - var payable = features.HasFlag(ContractFeatures.Payable).ToString().ToLowerInvariant(); + string debugname = onlyname + ".debug.json"; + string debugzip = onlyname + ".nefdbgnfo"; + + var tempName = Path.GetTempFileName(); + File.Delete(tempName); + File.WriteAllText(tempName, debugstr); + File.Delete(debugzip); + using (var archive = ZipFile.Open(debugzip, ZipArchiveMode.Create)) + { + archive.CreateEntryFromFile(tempName, Path.GetFileName(debugname)); + } + File.Delete(tempName); + log.Log("write:" + debugzip); + bSucc++; + } + catch (Exception err) + { + log.Log("Write debug Error:" + err.ToString()); + return -1; + } + try + { string manifest = onlyname + ".manifest.json"; - string defManifest = - @"{""groups"":[],""features"":{""storage"":" + storage + @",""payable"":" + payable + @"},""abi"":" + - jsonstr + - @",""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safeMethods"":[],""extra"":" + extra + "}"; + var defManifest = FuncExport.GenerateManifest(abi, module); File.Delete(manifest); File.WriteAllText(manifest, defManifest); @@ -284,7 +301,7 @@ public static int Compile(Options options) { } - if (bSucc == 3) + if (bSucc == 4) { log.Log("SUCC"); return 0; @@ -292,25 +309,5 @@ public static int Compile(Options options) return -1; } - - private static string BuildExtraAttributes(List> extraAttributes) - { - if (extraAttributes.Count == 0) - { - return "null"; - } - - string extra = "{"; - foreach (var extraAttribute in extraAttributes) - { - var key = extraAttribute[0].Value; - var value = extraAttribute[1].Value; - extra += ($"\"{key}\":\"{value}\","); - } - extra = extra.Substring(0, extra.Length - 1); - extra += "}"; - - return extra; - } } } diff --git a/src/Neo.Compiler.MSIL/Properties/AssemblyInfo.cs b/src/Neo.Compiler.MSIL/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..adc7f40b0 --- /dev/null +++ b/src/Neo.Compiler.MSIL/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Neo.Compiler.MSIL.UnitTests")] diff --git a/src/Neo.Compiler.MSIL/Utility.cs b/src/Neo.Compiler.MSIL/Utility.cs new file mode 100644 index 000000000..02857b8f4 --- /dev/null +++ b/src/Neo.Compiler.MSIL/Utility.cs @@ -0,0 +1,16 @@ +using System.Text; + +namespace Neo.Compiler +{ + internal static class Utility + { + public static Encoding StrictUTF8 { get; } + + static Utility() + { + StrictUTF8 = (Encoding)Encoding.UTF8.Clone(); + StrictUTF8.DecoderFallback = DecoderFallback.ExceptionFallback; + StrictUTF8.EncoderFallback = EncoderFallback.ExceptionFallback; + } + } +} diff --git a/src/Neo.Compiler.MSIL/base58.cs b/src/Neo.Compiler.MSIL/base58.cs deleted file mode 100644 index 09414cc12..000000000 --- a/src/Neo.Compiler.MSIL/base58.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Linq; -using System.Numerics; -using System.Text; - -namespace NEO.AllianceOfThinWallet.Cryptography -{ - public static class Base58 - { - /// - /// Base58 encode alphabet - /// - public const string Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - - /// - /// Decode - /// - /// The string to decode - /// Returns the decoded byte array - public static byte[] Decode(string input) - { - BigInteger bi = BigInteger.Zero; - for (int i = input.Length - 1; i >= 0; i--) - { - int index = Alphabet.IndexOf(input[i]); - if (index == -1) - throw new FormatException(); - bi += index * BigInteger.Pow(58, input.Length - 1 - i); - } - byte[] bytes = bi.ToByteArray(); - Array.Reverse(bytes); - bool stripSignByte = bytes.Length > 1 && bytes[0] == 0 && bytes[1] >= 0x80; - int leadingZeros = 0; - for (int i = 0; i < input.Length && input[i] == Alphabet[0]; i++) - { - leadingZeros++; - } - byte[] tmp = new byte[bytes.Length - (stripSignByte ? 1 : 0) + leadingZeros]; - Array.Copy(bytes, stripSignByte ? 1 : 0, tmp, leadingZeros, tmp.Length - leadingZeros); - return tmp; - } - - /// - /// Encode - /// - /// The bytearray to encode - /// Returns the encoded string - public static string Encode(byte[] input) - { - BigInteger value = new BigInteger(new byte[1].Concat(input).Reverse().ToArray()); - StringBuilder sb = new StringBuilder(); - while (value >= 58) - { - BigInteger mod = value % 58; - sb.Insert(0, Alphabet[(int)mod]); - value /= 58; - } - sb.Insert(0, Alphabet[(int)value]); - foreach (byte b in input) - { - if (b == 0) - sb.Insert(0, Alphabet[0]); - else - break; - } - return sb.ToString(); - } - } -} diff --git a/src/Neo.SmartContract.Framework/AppcallAttribute.cs b/src/Neo.SmartContract.Framework/AppcallAttribute.cs deleted file mode 100644 index 2ee89255d..000000000 --- a/src/Neo.SmartContract.Framework/AppcallAttribute.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Globalization; - -namespace Neo.SmartContract.Framework -{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor)] - public class AppcallAttribute : Attribute - { - public byte[] ScriptHash { get; } - - public AppcallAttribute(byte[] scriptHash) - { - if (scriptHash == null) throw new ArgumentNullException(); - if (scriptHash.Length != 20) throw new ArgumentException(); - this.ScriptHash = 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++) - this.ScriptHash[i] = byte.Parse(scriptHash.Substring(i * 2, 2), NumberStyles.AllowHexSpecifier); - } - } -} diff --git a/src/Neo.SmartContract.Framework/ContractAttribute.cs b/src/Neo.SmartContract.Framework/ContractAttribute.cs new file mode 100644 index 000000000..1eb7fd21f --- /dev/null +++ b/src/Neo.SmartContract.Framework/ContractAttribute.cs @@ -0,0 +1,33 @@ +using System; +using System.Globalization; + +namespace Neo.SmartContract.Framework +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class ContractAttribute : Attribute + { + public byte[] Hash { get; } + + public ContractAttribute(byte[] hash) + { + if (hash == null) throw new ArgumentNullException(); + if (hash.Length != 20) throw new ArgumentException(); + Hash = hash; + } + + public ContractAttribute(string hash) + { + if (hash == null) throw new ArgumentNullException(); + + if (hash.StartsWith("0x")) + { + hash = hash.Remove(0, 2); + } + + if (hash.Length != 40) throw new ArgumentException(); + Hash = new byte[hash.Length / 2]; + for (int i = 0; i < Hash.Length; i++) + Hash[i] = byte.Parse(hash.Substring(i * 2, 2), NumberStyles.AllowHexSpecifier); + } + } +} diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index f2074d206..b4863237f 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -6,6 +6,7 @@ namespace Neo.SmartContract.Framework public static class Helper { internal const string StackItemType_Integer = "0x21"; + internal const string StackItemType_ByteString = "0x28"; internal const string StackItemType_Buffer = "0x30"; /// @@ -23,10 +24,21 @@ public static class Helper /// /// Converts byte[] to BigInteger. No guarantees are assumed regarding BigInteger working range. + /// If it's null it will return 0 /// Examples: [0x0a] -> 10; [0x80] -> -128; [] -> 0; [0xff00] -> 255 /// + [OpCode(OpCode.DUP)] + [OpCode(OpCode.ISNULL)] + [OpCode(OpCode.JMPIFNOT, "0x05")] + [OpCode(OpCode.PUSH0)] + [OpCode(OpCode.SWAP)] + [OpCode(OpCode.DROP)] [OpCode(OpCode.CONVERT, StackItemType_Integer)] public extern static BigInteger ToBigInteger(this byte[] source); + //{ + // if (value == null) return 0; + // return value.ToBigInteger(); + //} /// /// Converts string to byte[]. Examples: "hello" -> [0x68656c6c6f]; "" -> []; "Neo" -> [0x4e656f] @@ -37,8 +49,8 @@ public static class Helper /// /// Converts byte[] to string. Examples: [0x68656c6c6f] -> "hello"; [] -> ""; [0x4e656f] -> "Neo" /// - [Script] - public extern static string AsString(this byte[] source); + [OpCode(OpCode.CONVERT, StackItemType_ByteString)] + public extern static string ToByteString(this byte[] source); /// /// Returns true iff a <= x && x < b. Examples: x=5 a=5 b=15 is true; x=15 a=5 b=15 is false @@ -152,7 +164,7 @@ public static byte ToByte(this int source) public extern static byte[] Concat(this byte[] first, byte[] second); [NonemitWithConvert(ConvertMethod.HexToBytes)] - public extern static byte[] HexToBytes(this string hex); + public extern static byte[] HexToBytes(this string hex, bool reverse = false); [OpCode(OpCode.SUBSTR)] public extern static byte[] Range(this byte[] source, int index, int count); diff --git a/src/Neo.SmartContract.Framework/ManifestExtraAttribute.cs b/src/Neo.SmartContract.Framework/ManifestExtraAttribute.cs index c7dc5e4d5..e3053a7ea 100644 --- a/src/Neo.SmartContract.Framework/ManifestExtraAttribute.cs +++ b/src/Neo.SmartContract.Framework/ManifestExtraAttribute.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace Neo.SmartContract.Framework { diff --git a/src/Neo.SmartContract.Framework/Neo.SmartContract.Framework.csproj b/src/Neo.SmartContract.Framework/Neo.SmartContract.Framework.csproj index 0ec57013f..3e36e5f33 100644 --- a/src/Neo.SmartContract.Framework/Neo.SmartContract.Framework.csproj +++ b/src/Neo.SmartContract.Framework/Neo.SmartContract.Framework.csproj @@ -4,7 +4,7 @@ 2016-2019 The Neo Project Neo.SmartContract.Framework 3.0.0 - preview2 + preview3 The Neo Project netstandard2.1 Neo.SmartContract.Framework diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Contract.cs b/src/Neo.SmartContract.Framework/Services/Neo/Contract.cs index 02c26b35a..e5ee44652 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Contract.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Contract.cs @@ -7,6 +7,11 @@ public class Contract /// public readonly byte[] Script; + /// + /// Manifest + /// + public readonly string Manifest; + /// /// Has storage /// diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Enumerator.cs b/src/Neo.SmartContract.Framework/Services/Neo/Enumerator.cs index 70c62437d..7dfb3ee60 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Enumerator.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Enumerator.cs @@ -2,7 +2,7 @@ namespace Neo.SmartContract.Framework.Services.Neo { - public class Enumerator + public class Enumerator : IApiInterface { [Syscall("System.Enumerator.Create")] public static extern Enumerator Create(IEnumerable entry); diff --git a/src/Neo.SmartContract.Framework/Services/Neo/GAS.cs b/src/Neo.SmartContract.Framework/Services/Neo/GAS.cs new file mode 100644 index 000000000..52a74e44f --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/Neo/GAS.cs @@ -0,0 +1,16 @@ +#pragma warning disable CS0626 + +using System.Numerics; + +namespace Neo.SmartContract.Framework.Services.Neo +{ + [Contract("0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc")] + public class GAS + { + public static extern string Name(); + public static extern string Symbol(); + public static extern byte Decimals(); + public static extern BigInteger TotalSupply(); + public static extern BigInteger BalanceOf(byte[] account); + } +} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Iterator.cs b/src/Neo.SmartContract.Framework/Services/Neo/Iterator.cs index 604264155..b1952b0cf 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Iterator.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Iterator.cs @@ -2,7 +2,7 @@ namespace Neo.SmartContract.Framework.Services.Neo { - public class Iterator + public class Iterator : IApiInterface { [Syscall("System.Iterator.Create")] public static extern Iterator Create(Map entry); diff --git a/src/Neo.SmartContract.Framework/Services/Neo/NEO.cs b/src/Neo.SmartContract.Framework/Services/Neo/NEO.cs new file mode 100644 index 000000000..6df9992b5 --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/Neo/NEO.cs @@ -0,0 +1,27 @@ +#pragma warning disable CS0626 + +using System; +using System.Numerics; + +namespace Neo.SmartContract.Framework.Services.Neo +{ + [Contract("0xde5f57d430d3dece511cf975a8d37848cb9e0525")] + public class NEO + { + public static extern string Name(); + public static extern string Symbol(); + public static extern BigInteger Decimals(); + public static extern BigInteger TotalSupply(); + public static extern BigInteger BalanceOf(byte[] account); + + public static extern BigInteger UnclaimedGas(byte[] account, uint end); + + public static extern bool RegisterCandidate(byte[] pubkey); + public static extern bool UnRegisterCandidate(byte[] pubkey); + public static extern bool Vote(byte[] account, byte[] voteTo); + public static extern (string, BigInteger)[] GetCandidates(); + public static extern string[] GetValidators(); + public static extern string[] GetCommittee(); + public static extern string[] GetNextBlockValidators(); + } +} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Native.cs b/src/Neo.SmartContract.Framework/Services/Neo/Native.cs deleted file mode 100644 index 96d573586..000000000 --- a/src/Neo.SmartContract.Framework/Services/Neo/Native.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Neo.SmartContract.Framework.Services.Neo -{ - public class Native - { - [Appcall("0xde5f57d430d3dece511cf975a8d37848cb9e0525")] - public static extern object NEO(string method, object[] arguments); - - [Appcall("0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc")] - public static extern object GAS(string method, object[] arguments); - - [Appcall("0xce06595079cd69583126dbfd1d2e25cca74cffe9")] - public static extern object Policy(string method, object[] arguments); - } -} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Notification.cs b/src/Neo.SmartContract.Framework/Services/Neo/Notification.cs index 05aaa6564..498ad6ad3 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Notification.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Notification.cs @@ -7,9 +7,14 @@ public class Notification : IApiInterface /// public readonly byte[] ScriptHash; + /// + /// Notification's name + /// + public readonly string EventName; + /// /// Notification's state /// - public readonly object State; + public readonly object[] State; } } diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Policy.cs b/src/Neo.SmartContract.Framework/Services/Neo/Policy.cs new file mode 100644 index 000000000..e6ba014fd --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/Neo/Policy.cs @@ -0,0 +1,24 @@ +#pragma warning disable CS0626 + +using System; +using System.Numerics; + +namespace Neo.SmartContract.Framework.Services.Neo +{ + [Contract("0xce06595079cd69583126dbfd1d2e25cca74cffe9")] + public class Policy + { + public static extern string Name(); + public static extern uint GetMaxTransactionsPerBlock(); + public static extern uint GetMaxBlockSize(); + public static extern long GetMaxBlockSystemFee(); + public static extern BigInteger GetFeePerByte(); + public static extern string[] GetBlockedAccounts(); + public static extern bool SetMaxBlockSize(uint value); + public static extern bool SetMaxTransactionsPerBlock(uint value); + public static extern bool SetMaxBlockSystemFee(long value); + public static extern bool SetFeePerByte(long value); + public static extern bool BlockAccount(byte[] account); + public static extern bool UnblockAccount(byte[] account); + } +} diff --git a/src/Neo.SmartContract.Framework/Services/Neo/Runtime.cs b/src/Neo.SmartContract.Framework/Services/Neo/Runtime.cs index 0f03ab628..4d124c44e 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/Runtime.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/Runtime.cs @@ -45,9 +45,6 @@ public static extern long GasLeft [Syscall("System.Runtime.CheckWitness")] public static extern bool CheckWitness(byte[] hashOrPubkey); - [Syscall("System.Runtime.Notify")] - public static extern void Notify(params object[] state); - [Syscall("System.Runtime.Log")] public static extern void Log(string message); } diff --git a/src/Neo.SmartContract.Framework/Services/Neo/StorageContext.cs b/src/Neo.SmartContract.Framework/Services/Neo/StorageContext.cs index 6b2bae292..83721681d 100644 --- a/src/Neo.SmartContract.Framework/Services/Neo/StorageContext.cs +++ b/src/Neo.SmartContract.Framework/Services/Neo/StorageContext.cs @@ -1,6 +1,6 @@ namespace Neo.SmartContract.Framework.Services.Neo { - public class StorageContext + public class StorageContext : IApiInterface { /// /// Returns current StorageContext as ReadOnly diff --git a/src/Neo.SmartContract.Framework/Services/System/Binary.cs b/src/Neo.SmartContract.Framework/Services/System/Binary.cs new file mode 100644 index 000000000..2414293ec --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/System/Binary.cs @@ -0,0 +1,17 @@ +namespace Neo.SmartContract.Framework.Services.System +{ + public class Binary + { + [Syscall("System.Binary.Base64Decode")] + public static extern byte[] Base64Decode(string input); + + [Syscall("System.Binary.Base64Encode")] + public static extern string Base64Encode(byte[] input); + + [Syscall("System.Binary.Base58Decode")] + public static extern byte[] Base58Decode(string input); + + [Syscall("System.Binary.Base58Encode")] + public static extern string Base58Encode(byte[] input); + } +} diff --git a/src/Neo.SmartContract.Framework/Services/System/Callback.cs b/src/Neo.SmartContract.Framework/Services/System/Callback.cs new file mode 100644 index 000000000..0e4ee18a4 --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/System/Callback.cs @@ -0,0 +1,103 @@ +using System; + +namespace Neo.SmartContract.Framework.Services.System +{ + public class Callback + { + [Syscall("System.Callback.Invoke")] + public extern object Invoke(object[] args); + + // Static + + [OpCode(OpCode.PUSH0)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH1)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH2)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH3)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH4)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH5)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH6)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH7)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH8)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH9)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH10)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH11)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH12)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH13)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH14)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH15)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [OpCode(OpCode.PUSH16)] + [OpCode(OpCode.SWAP)] + [Syscall("System.Callback.Create")] + public static extern Callback Create(Func func); + + [Syscall("System.Callback.CreateFromMethod")] + public static extern Callback CreateFromMethod(byte[] hash, string method); + + [Syscall("System.Callback.CreateFromSyscall")] + public static extern Callback CreateFromSyscall(SyscallCallback method); + } +} diff --git a/src/Neo.SmartContract.Framework/Services/System/SyscallCallback.cs b/src/Neo.SmartContract.Framework/Services/System/SyscallCallback.cs new file mode 100644 index 000000000..dd5db9951 --- /dev/null +++ b/src/Neo.SmartContract.Framework/Services/System/SyscallCallback.cs @@ -0,0 +1,39 @@ +namespace Neo.SmartContract.Framework.Services.System +{ + public enum SyscallCallback : uint + { + System_Binary_Serialize = 0x24011c3f, + System_Binary_Deserialize = 0xdfd07c52, + System_Binary_Base64Encode = 0x7653bfac, + System_Binary_Base64Decode = 0xc384a3db, + System_Binary_Base58Encode = 0x67b0573f, + System_Binary_Base58Decode = 0x3792f76d, + System_Blockchain_GetHeight = 0x1f72f57e, + System_Blockchain_GetBlock = 0x2d924783, + System_Blockchain_GetTransaction = 0x488d55e6, + System_Blockchain_GetTransactionHeight = 0xb188324a, + System_Blockchain_GetTransactionFromBlock = 0x69fd567e, + System_Blockchain_GetContract = 0x414bc5a9, + System_Contract_IsStandard = 0x859d6bd7, + System_Contract_CreateStandardAccount = 0x28799cf, + Neo_Crypto_RIPEMD160 = 0xd2d6d126, + Neo_Crypto_SHA256 = 0x1174acd7, + Neo_Crypto_VerifyWithECDsaSecp256r1 = 0x780d4495, + Neo_Crypto_VerifyWithECDsaSecp256k1 = 0xb7533c7e, + Neo_Crypto_CheckMultisigWithECDsaSecp256r1 = 0xafef8d13, + Neo_Crypto_CheckMultisigWithECDsaSecp256k1 = 0xb2efc657, + System_Json_Serialize = 0x4b268d24, + System_Json_Deserialize = 0xe479ca7, + System_Runtime_Platform = 0xf6fc79b2, + System_Runtime_GetTrigger = 0xa0387de9, + System_Runtime_GetTime = 0x388c3b7, + System_Runtime_GetScriptContainer = 0x3008512d, + System_Runtime_GetExecutingScriptHash = 0x74a8fedb, + System_Runtime_GetCallingScriptHash = 0x3c6e5339, + System_Runtime_GetEntryScriptHash = 0x38e2b4f9, + System_Runtime_CheckWitness = 0x8cec27f8, + System_Runtime_GetInvocationCounter = 0x43112784, + System_Runtime_GetNotifications = 0xf1354327, + System_Runtime_GasLeft = 0xced88814 + } +} diff --git a/src/Neo.SmartContract.Framework/SupportedStandardsAttribute.cs b/src/Neo.SmartContract.Framework/SupportedStandardsAttribute.cs new file mode 100644 index 000000000..bb51cf320 --- /dev/null +++ b/src/Neo.SmartContract.Framework/SupportedStandardsAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Neo.SmartContract.Framework +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class SupportedStandardsAttribute : Attribute + { + public string[] Value { get; set; } + + public SupportedStandardsAttribute(params string[] supportedStandards) + { + Value = supportedStandards; + } + } +} diff --git a/templates/Template.CSharp/Contract1.cs b/templates/Template.CSharp/Contract1.cs index 44cae59ad..51ffa80d5 100644 --- a/templates/Template.CSharp/Contract1.cs +++ b/templates/Template.CSharp/Contract1.cs @@ -11,7 +11,7 @@ namespace $safeprojectname$ [Features(ContractFeatures.HasStorage)] public class Contract1 : SmartContract { - public static bool Main(string operation, object[] args) + public static bool Main() { Storage.Put("Hello", "World"); return true; diff --git a/templates/Template.CSharp/ProjectTemplate.csproj b/templates/Template.CSharp/ProjectTemplate.csproj index 1beaf87c9..74533c27c 100644 --- a/templates/Template.CSharp/ProjectTemplate.csproj +++ b/templates/Template.CSharp/ProjectTemplate.csproj @@ -5,7 +5,7 @@ - + diff --git a/templates/Template.NEP5.CSharp/NEP5.Admin.cs b/templates/Template.NEP5.CSharp/NEP5.Admin.cs deleted file mode 100644 index a64fca5d3..000000000 --- a/templates/Template.NEP5.CSharp/NEP5.Admin.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Neo.SmartContract.Framework; -using Neo.SmartContract.Framework.Services.Neo; -using System; - -namespace Template.NEP5.CSharp -{ - public partial class NEP5 : SmartContract - { - public static bool Deploy() - { - if (!Runtime.CheckWitness(Owner)) - { - return false; - } - - StorageMap contract = Storage.CurrentContext.CreateMap(StoragePrefixContract); - if (contract.Get("totalSupply") != null) - throw new Exception("Contract already deployed"); - - StorageMap balances = Storage.CurrentContext.CreateMap(StoragePrefixBalance); - balances.Put(Owner, InitialSupply); - contract.Put("totalSupply", InitialSupply); - - OnTransfer(null, Owner, InitialSupply); - return true; - } - - public static bool Migrate(byte[] script, string manifest) - { - if (!Runtime.CheckWitness(Owner)) - { - return false; - } - if (script.Length == 0 || manifest.Length == 0) - { - return false; - } - Contract.Update(script, manifest); - return true; - } - - public static bool Destroy() - { - if (!Runtime.CheckWitness(Owner)) - { - return false; - } - - Contract.Destroy(); - return true; - } - } -} diff --git a/templates/Template.NEP5.CSharp/NEP5.Crowdsale.cs b/templates/Template.NEP5.CSharp/NEP5.Crowdsale.cs index ca9a3efbe..0b8367bcf 100644 --- a/templates/Template.NEP5.CSharp/NEP5.Crowdsale.cs +++ b/templates/Template.NEP5.CSharp/NEP5.Crowdsale.cs @@ -8,29 +8,27 @@ namespace Template.NEP5.CSharp { public partial class NEP5 : SmartContract { - private static BigInteger GetTransactionAmount(object state) + private static BigInteger GetTransactionAmount(Notification notification) { - var notification = (object[])state; - // Checks notification format - if (notification.Length != 4) return 0; // Only allow Transfer notifications - if ((string)notification[0] != "Transfer") return 0; + if (notification.EventName != "Transfer") return 0; + var state = notification.State; + // Checks notification format + if (state.Length != 3) return 0; // Check dest - if ((byte[])notification[2] != ExecutionEngine.ExecutingScriptHash) return 0; + if ((byte[])state[1] != ExecutionEngine.ExecutingScriptHash) return 0; // Amount - var amount = (BigInteger)notification[3]; + var amount = (BigInteger)state[2]; if (amount < 0) return 0; return amount; } public static bool Mint() { - if (Runtime.InvocationCounter != 1) - throw new Exception(); + if (Runtime.InvocationCounter != 1) throw new Exception("InvocationCounter must be 1."); var notifications = Runtime.GetNotifications(); - if (notifications.Length == 0) - throw new Exception("Contribution transaction not found"); + if (notifications.Length == 0) throw new Exception("Contribution transaction not found."); BigInteger neo = 0; BigInteger gas = 0; @@ -41,35 +39,28 @@ public static bool Mint() if (notification.ScriptHash == NeoToken) { - neo += GetTransactionAmount(notification.State); + neo += GetTransactionAmount(notification); } else if (notification.ScriptHash == GasToken) { - gas += GetTransactionAmount(notification.State); + gas += GetTransactionAmount(notification); } } - StorageMap contract = Storage.CurrentContext.CreateMap(StoragePrefixContract); - var supply = contract.Get("totalSupply"); - if (supply == null) - throw new Exception("Contract not deployed"); + var totalSupply = TotalSupplyStorage.Get(); + if (totalSupply <= 0) throw new Exception("Contract not deployed."); - var current_supply = supply.ToBigInteger(); - var avaliable_supply = MaxSupply - current_supply; + var avaliable_supply = MaxSupply - totalSupply; var contribution = (neo * TokensPerNEO) + (gas * TokensPerGAS); - if (contribution <= 0) - throw new Exception(); - if (contribution > avaliable_supply) - throw new Exception(); + if (contribution <= 0) throw new Exception("Contribution cannot be zero."); + if (contribution > avaliable_supply) throw new Exception("Insufficient supply for mint tokens."); - StorageMap balances = Storage.CurrentContext.CreateMap(StoragePrefixBalance); Transaction tx = (Transaction)ExecutionEngine.ScriptContainer; - var balance = balances.Get(tx.Sender)?.ToBigInteger() ?? 0; - balances.Put(tx.Sender, balance + contribution); - contract.Put("totalSupply", current_supply + contribution); + AssetStorage.Increase(tx.Sender, contribution); + TotalSupplyStorage.Increase(contribution); - OnTransfer(null, tx.Sender, balance + contribution); + OnTransfer(null, tx.Sender, contribution); return true; } } diff --git a/templates/Template.NEP5.CSharp/NEP5.Helpers.cs b/templates/Template.NEP5.CSharp/NEP5.Helpers.cs index 347313c59..e1d141176 100644 --- a/templates/Template.NEP5.CSharp/NEP5.Helpers.cs +++ b/templates/Template.NEP5.CSharp/NEP5.Helpers.cs @@ -5,19 +5,8 @@ namespace Template.NEP5.CSharp { public partial class NEP5 : SmartContract { - private static bool ValidateAddress(byte[] address) - { - if (address.Length != 20) - return false; - if (address.ToBigInteger() == 0) - return false; - return true; - } + private static bool ValidateAddress(byte[] address) => address.Length == 20 && address.ToBigInteger() != 0; - private static bool IsPayable(byte[] address) - { - var c = Blockchain.GetContract(address); - return c == null || c.IsPayable; - } + private static bool IsPayable(byte[] address) => Blockchain.GetContract(address)?.IsPayable ?? true; } } diff --git a/templates/Template.NEP5.CSharp/NEP5.Methods.cs b/templates/Template.NEP5.CSharp/NEP5.Methods.cs index a6933c114..cf1e039f0 100644 --- a/templates/Template.NEP5.CSharp/NEP5.Methods.cs +++ b/templates/Template.NEP5.CSharp/NEP5.Methods.cs @@ -1,5 +1,6 @@ using Neo.SmartContract.Framework; using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.System; using System; using System.Numerics; @@ -7,45 +8,25 @@ namespace Template.NEP5.CSharp { public partial class NEP5 : SmartContract { - public static BigInteger TotalSupply() - { - StorageMap contract = Storage.CurrentContext.CreateMap(StoragePrefixContract); - return contract.Get("totalSupply")?.ToBigInteger() ?? 0; - } + public static BigInteger TotalSupply() => TotalSupplyStorage.Get(); public static BigInteger BalanceOf(byte[] account) { - if (!ValidateAddress(account)) throw new FormatException("The parameter 'account' SHOULD be 20-byte addresses."); - - StorageMap balances = Storage.CurrentContext.CreateMap(StoragePrefixBalance); - return balances.Get(account)?.ToBigInteger() ?? 0; + if (!ValidateAddress(account)) throw new Exception("The parameters account SHOULD be 20-byte addresses."); + return AssetStorage.Get(account); } public static bool Transfer(byte[] from, byte[] to, BigInteger amount) { - if (!ValidateAddress(from)) throw new FormatException("The parameter 'from' SHOULD be 20-byte addresses."); - if (!ValidateAddress(to)) throw new FormatException("The parameters 'to' SHOULD be 20-byte addresses."); - if (!IsPayable(to)) return false; - if (amount <= 0) throw new InvalidOperationException("The parameter amount MUST be greater than 0."); - if (!Runtime.CheckWitness(from)) return false; - - StorageMap balances = Storage.CurrentContext.CreateMap(StoragePrefixBalance); - BigInteger fromAmount = balances.Get(from).ToBigInteger(); - - if (fromAmount < amount) return false; - if (amount == 0 || from == to) return true; - - if (fromAmount == amount) - { - balances.Delete(from); - } - else - { - balances.Put(from, fromAmount - amount); - } - - BigInteger toAmount = balances.Get(to)?.ToBigInteger() ?? 0; - balances.Put(to, toAmount + amount); + if (!ValidateAddress(from) || !ValidateAddress(to)) throw new Exception("The parameters from and to SHOULD be 20-byte addresses."); + if (amount <= 0) throw new Exception("The parameter amount MUST be greater than 0."); + if (!IsPayable(to)) throw new Exception("Receiver cannot receive."); + if (!Runtime.CheckWitness(from) && !from.Equals(ExecutionEngine.CallingScriptHash)) throw new Exception("No authorization."); + if (AssetStorage.Get(from) < amount) throw new Exception("Insufficient balance."); + if (from == to) return true; + + AssetStorage.Reduce(from, amount); + AssetStorage.Increase(to, amount); OnTransfer(from, to, amount); return true; diff --git a/templates/Template.NEP5.CSharp/NEP5.Owner.cs b/templates/Template.NEP5.CSharp/NEP5.Owner.cs new file mode 100644 index 000000000..03fe9af32 --- /dev/null +++ b/templates/Template.NEP5.CSharp/NEP5.Owner.cs @@ -0,0 +1,40 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.System; +using System; + +namespace Template.NEP5.CSharp +{ + public partial class NEP5 : SmartContract + { + public static bool Deploy() + { + if (!IsOwner()) throw new Exception("No authorization."); + if (TotalSupplyStorage.Get() > 0) throw new Exception("Contract has been deployed."); + + TotalSupplyStorage.Increase(InitialSupply); + AssetStorage.Increase(Owner, InitialSupply); + + OnTransfer(null, Owner, InitialSupply); + return true; + } + + public static bool Update(byte[] script, string manifest) + { + if (!IsOwner()) throw new Exception("No authorization."); + // Check empty + if (script.Length == 0 && manifest.Length == 0) return false; + Contract.Update(script, manifest); + return true; + } + + public static bool Destroy() + { + if (!IsOwner()) throw new Exception("No authorization."); + Contract.Destroy(); + return true; + } + + private static bool IsOwner() => Runtime.CheckWitness(Owner); + } +} diff --git a/templates/Template.NEP5.CSharp/NEP5.cs b/templates/Template.NEP5.CSharp/NEP5.cs index ec20324c6..107569dbd 100644 --- a/templates/Template.NEP5.CSharp/NEP5.cs +++ b/templates/Template.NEP5.CSharp/NEP5.cs @@ -1,5 +1,4 @@ using Neo.SmartContract.Framework; -using Neo.SmartContract.Framework.Services.Neo; using System; using System.ComponentModel; using System.Numerics; @@ -9,17 +8,18 @@ namespace Template.NEP5.CSharp [ManifestExtra("Author", "Neo")] [ManifestExtra("Email", "dev@neo.org")] [ManifestExtra("Description", "This is a NEP5 example")] + [SupportedStandards("NEP5", "NEP10")] [Features(ContractFeatures.HasStorage | ContractFeatures.Payable)] public partial class NEP5 : SmartContract { #region Token Settings static readonly ulong MaxSupply = 10_000_000_000_000_000; static readonly ulong InitialSupply = 2_000_000_000_000_000; - static readonly byte[] Owner = new byte[] { 0xf6, 0x64, 0x43, 0x49, 0x8d, 0x38, 0x78, 0xd3, 0x2b, 0x99, 0x4e, 0x4e, 0x12, 0x83, 0xc6, 0x93, 0x44, 0x21, 0xda, 0xfe }; + static readonly byte[] Owner = "NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB".ToScriptHash(); static readonly ulong TokensPerNEO = 1_000_000_000; static readonly ulong TokensPerGAS = 1; - static readonly byte[] NeoToken = new byte[] { 0x89, 0x77, 0x20, 0xd8, 0xcd, 0x76, 0xf4, 0xf0, 0x0a, 0xbf, 0xa3, 0x7c, 0x0e, 0xdd, 0x88, 0x9c, 0x20, 0x8f, 0xde, 0x9b }; - static readonly byte[] GasToken = new byte[] { 0x3b, 0x7d, 0x37, 0x11, 0xc6, 0xf0, 0xcc, 0xf9, 0xb1, 0xdc, 0xa9, 0x03, 0xd1, 0xbf, 0xa1, 0xd8, 0x96, 0xf1, 0x23, 0x8c }; + static readonly byte[] NeoToken = "0xde5f57d430d3dece511cf975a8d37848cb9e0525".HexToBytes(true); + static readonly byte[] GasToken = "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc".HexToBytes(true); #endregion #region Notifications @@ -27,36 +27,15 @@ public partial class NEP5 : SmartContract public static event Action OnTransfer; #endregion - #region Storage key prefixes - static readonly byte[] StoragePrefixBalance = new byte[] { 0x01, 0x01 }; - static readonly byte[] StoragePrefixContract = new byte[] { 0x02, 0x02 }; - #endregion - // When this contract address is included in the transaction signature, // this method will be triggered as a VerificationTrigger to verify that the signature is correct. - public static bool Verify() - { - return Runtime.CheckWitness(Owner); - } - - public static string Name() - { - return "Token Name"; - } + // For example, this method needs to be called when withdrawing token from the contract. + public static bool Verify() => IsOwner(); - public static string Symbol() - { - return "TokenSymbol"; - } + public static string Name() => "Token Name"; - public static ulong Decimals() - { - return 8; - } + public static string Symbol() => "TokenSymbol"; - public static string[] SupportedStandards() - { - return new string[] { "NEP-5", "NEP-10" }; - } + public static ulong Decimals() => 8; } } diff --git a/templates/Template.NEP5.CSharp/Storage/AssetStorage.cs b/templates/Template.NEP5.CSharp/Storage/AssetStorage.cs new file mode 100644 index 000000000..9e5de31d3 --- /dev/null +++ b/templates/Template.NEP5.CSharp/Storage/AssetStorage.cs @@ -0,0 +1,28 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; +using System.Numerics; + +namespace Template.NEP5.CSharp +{ + public static class AssetStorage + { + public static readonly string mapName = "asset"; + + public static void Increase(byte[] key, BigInteger value) => Put(key, Get(key) + value); + + public static void Reduce(byte[] key, BigInteger value) + { + var oldValue = Get(key); + if (oldValue == value) + Remove(key); + else + Put(key, oldValue - value); + } + + public static void Put(byte[] key, BigInteger value) => Storage.CurrentContext.CreateMap(mapName).Put(key, value); + + public static BigInteger Get(byte[] key) => Storage.CurrentContext.CreateMap(mapName).Get(key).ToBigInteger(); + + public static void Remove(byte[] key) => Storage.CurrentContext.CreateMap(mapName).Delete(key); + } +} diff --git a/templates/Template.NEP5.CSharp/Storage/TotalSupplyStorage.cs b/templates/Template.NEP5.CSharp/Storage/TotalSupplyStorage.cs new file mode 100644 index 000000000..bd8722144 --- /dev/null +++ b/templates/Template.NEP5.CSharp/Storage/TotalSupplyStorage.cs @@ -0,0 +1,22 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; +using System.Numerics; + +namespace Template.NEP5.CSharp +{ + public static class TotalSupplyStorage + { + public static readonly string mapName = "contract"; + + public static readonly string key = "totalSupply"; + + public static void Increase(BigInteger value) => Put(Get() + value); + + public static void Reduce(BigInteger value) => Put(Get() - value); + + public static void Put(BigInteger value) => Storage.CurrentContext.CreateMap(mapName).Put(key, value); + + public static BigInteger Get() => Storage.CurrentContext.CreateMap(mapName).Get(key).ToBigInteger(); + + } +} diff --git a/templates/Template.NEP5.CSharp/Template.NEP5.CSharp.sln b/templates/Template.NEP5.CSharp/Template.NEP5.CSharp.sln deleted file mode 100644 index 0f66d4952..000000000 --- a/templates/Template.NEP5.CSharp/Template.NEP5.CSharp.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29025.244 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Template.NEP5.CSharp", "Template.NEP5.CSharp.csproj", "{A97D1F8D-1181-489D-893C-F25C019D75FF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A97D1F8D-1181-489D-893C-F25C019D75FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A97D1F8D-1181-489D-893C-F25C019D75FF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A97D1F8D-1181-489D-893C-F25C019D75FF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A97D1F8D-1181-489D-893C-F25C019D75FF}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {517EB11D-73F9-4594-88B0-0D7C0E9290C1} - EndGlobalSection -EndGlobal diff --git a/templates/Template.VB/Contract1.vb b/templates/Template.VB/Contract1.vb index af1624bfa..d6bf34301 100644 --- a/templates/Template.VB/Contract1.vb +++ b/templates/Template.VB/Contract1.vb @@ -4,7 +4,7 @@ Imports System Imports System.Numerics Public Class $itemname$ : Inherits SmartContract - Public Shared Function Main(ByVal operation As String, ByVal args() As Object) As Boolean + Public Shared Function Main() As Boolean Storage.Put("Hello", "World") Return True End Function diff --git a/templates/Template.VB/ProjectTemplate.vbproj b/templates/Template.VB/ProjectTemplate.vbproj index 250398400..68fc466a0 100644 --- a/templates/Template.VB/ProjectTemplate.vbproj +++ b/templates/Template.VB/ProjectTemplate.vbproj @@ -6,7 +6,7 @@ - + diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract1.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract1.cs index 6b186879a..eb7b61337 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract1.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract1.cs @@ -8,5 +8,16 @@ public static byte[] unitTest_001() return nb; } + public static void testVoid() + { + var nb = new byte[] { 1, 2, 3, 4 }; + } + + public static byte[] testArgs(byte a) + { + var nb = new byte[] { 1, 2, 3, 3 }; + nb[3] = a; + return nb; + } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract2.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract2.cs index 89667191d..6dc56991f 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract2.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract2.cs @@ -1,11 +1,17 @@ +using System; +using System.ComponentModel; + namespace Neo.Compiler.MSIL.UnitTests.TestClasses { public class Contract2 : SmartContract.Framework.SmartContract { + [DisplayName("event")] + public static event Action notify; + public static byte UnitTest_002(object arg1, object arg2) { - Neo.SmartContract.Framework.Services.Neo.Runtime.Notify(arg1); - Neo.SmartContract.Framework.Services.Neo.Runtime.Notify(arg2); + notify(arg1); + notify(arg2); var nb = new byte[] { 1, 2, 3, 4 }; return nb[2]; } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_ContractCall.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_ContractCall.cs new file mode 100644 index 000000000..c35ba2844 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_ContractCall.cs @@ -0,0 +1,24 @@ +using Neo.SmartContract.Framework; + +namespace Neo.Compiler.MSIL.UnitTests.TestClasses +{ + [Contract("0102030405060708090A0102030405060708090A")] + public class Contract1 + { + public static extern byte[] testArgs(byte a); + public static extern void testVoid(); + } + + public class Contract_ContractCall : SmartContract.Framework.SmartContract + { + public static byte[] testContractCall() + { + return Contract1.testArgs((byte)4); + } + + public static void testContractCallVoid() + { + Contract1.testVoid(); + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_InvokeCsNef.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_InvokeCsNef.cs new file mode 100644 index 000000000..1ce188db2 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_InvokeCsNef.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Text; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace Neo.Compiler.MSIL.UnitTests.TestClasses +{ + class Contract_InvokeCsNef : SmartContract.Framework.SmartContract + { + /// + /// One return + /// + public static int returnInteger() + { + return 42; + } + + public static int Main() + { + return 22; + } + + public static string returnString() + { + return "hello world"; + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_NULL.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_NULL.cs index 3c4077bd0..67cebb67f 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_NULL.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_NULL.cs @@ -44,23 +44,23 @@ public static string NullCollation(string code) public static bool IfNull(object obj) { - if ((bool)obj) - { - return true; + if ((bool)obj) + { + return true; } return false; - } - + } + public static object NullCollationAndCollation(string code) { - return Storage.Get(code)?.ToBigInteger() ?? 123; + return Storage.Get(code) ?? new byte[] { 123 }; } public static object NullCollationAndCollation2(string code) { Storage.Put(code, "111"); - return Storage.Get(code)?.ToBigInteger() ?? 123; + return Storage.Get(code) ?? new byte[] { 123 }; } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_OptimizationTest.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_OptimizationTest.cs new file mode 100644 index 000000000..8d195d51f --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_OptimizationTest.cs @@ -0,0 +1,15 @@ +using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_OptimizationTest : SmartContract.Framework.SmartContract + { + private static byte[] Owner = "Ne9ipxm2sPUaetvh3ZvjhyCzRZqP355dTZ".ToScriptHash(); + + public static bool Verify() + { + return Runtime.CheckWitness(Owner); + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_StaticByteArray.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_StaticByteArray.cs new file mode 100644 index 000000000..3ae6f5898 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_StaticByteArray.cs @@ -0,0 +1,19 @@ +using System; +using System.ComponentModel; +using System.Numerics; + +namespace Neo.Compiler.MSIL.TestClasses +{ + class Contract_StaticByteArray : SmartContract.Framework.SmartContract + { + [DisplayName("TestEvent")] + public static event Action OnEvent; + + static byte[] NeoToken = new byte[] { 0x89, 0x77, 0x20, 0xd8, 0xcd, 0x76, 0xf4, 0xf0, 0x0a, 0xbf, 0xa3, 0x7c, 0x0e, 0xdd, 0x88, 0x9c, 0x20, 0x8f, 0xde, 0x9b }; + + public static byte[] TestStaticByteArray() + { + return NeoToken; + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types.cs index 452e67a97..70cdb9cc7 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types.cs @@ -43,26 +43,27 @@ public struct DummyStruct public static object[] checkArrayObj() { return new object[] { "neo" }; } public static BigInteger checkBigInteger() { return (BigInteger)5; } public static byte[] checkByteArray() { return new byte[] { 1, 2, 3 }; } - public static EDummy checkEnum() { return EDummy.test; } - public static enumDel checkDelegate() + public static object checkEnum() { return EDummy.test; } + private static EDummy icheckEnum() { return EDummy.test; } + public static object checkDelegate() { - return new enumDel(checkEnum); + return new enumDel(icheckEnum); } - public static Func checkLambda() + public static object checkLambda() { - return checkEnum; + return new Func(icheckEnum); } public static void checkEvent() { dummyEvent("neo"); } - public static DummyClass checkClass() + public static object checkClass() { var ret = new DummyClass(); ret.Value = "neo"; return ret; } - public static DummyStruct checkStruct() + public static object checkStruct() { var ret = new DummyStruct(); ret.Value = "neo"; @@ -77,5 +78,9 @@ public static (string value1, string value2) checkTuple2() var tuple = ("neo", "smart economy"); return tuple; } + public static Tuple checkTuple3() + { + return new Tuple("neo", "smart economy"); + } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_appcall.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_appcall.cs deleted file mode 100644 index ea9dd5487..000000000 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_appcall.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Neo.SmartContract.Framework; - -namespace Neo.Compiler.MSIL.UnitTests.TestClasses -{ - class Contract_syscall : SmartContract.Framework.SmartContract - { - //这个appcall的地址,在testcase中可以配置 - //[Appcall("0102030405060708090A0102030405060708090A")] - [Syscall("System.Contract.Call")] - static extern object unittest001(byte[] scriptHash, string method, object[] arguments); - - public static object testAppCall() - { - var scriptHash = new byte[] { 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }; - var methodName = "unitTest_001"; - object[] arguments = new object[0] { }; - return unittest001(scriptHash, methodName, arguments); - } - } -} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_shift.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_shift.cs index 10a5e4a98..66d57d4a2 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_shift.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_shift.cs @@ -1,7 +1,13 @@ +using System; +using System.ComponentModel; + namespace Neo.Compiler.MSIL.UnitTests.TestClasses { class Contract_shift : SmartContract.Framework.SmartContract { + [DisplayName("event")] + public static event Action notify; + public static object Main() { int v = 8; @@ -9,10 +15,10 @@ public static object Main() var v2 = v << -1; var v3 = v >> 1; var v4 = v >> -1; - SmartContract.Framework.Services.Neo.Runtime.Notify(v1); - SmartContract.Framework.Services.Neo.Runtime.Notify(v2); - SmartContract.Framework.Services.Neo.Runtime.Notify(v3); - SmartContract.Framework.Services.Neo.Runtime.Notify(v4); + notify(v1); + notify(v2); + notify(v3); + notify(v4); return false; } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_shift_bigint.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_shift_bigint.cs index 336c75008..4205b6fe7 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_shift_bigint.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_shift_bigint.cs @@ -1,7 +1,13 @@ +using System; +using System.ComponentModel; + namespace Neo.Compiler.MSIL.UnitTests.TestClasses { class Contract_shift_bigint : SmartContract.Framework.SmartContract { + [DisplayName("event")] + public static event Action notify; + public static object Main() { System.Numerics.BigInteger v = 8; @@ -9,10 +15,10 @@ public static object Main() var v2 = v << 1; var v3 = v >> 1; var v4 = v >> 2; - SmartContract.Framework.Services.Neo.Runtime.Notify(v1); - SmartContract.Framework.Services.Neo.Runtime.Notify(v2); - SmartContract.Framework.Services.Neo.Runtime.Notify(v3); - SmartContract.Framework.Services.Neo.Runtime.Notify(v4); + notify(v1); + notify(v2); + notify(v3); + notify(v4); return false; } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest1.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest1.cs index 241dd8ed4..293b71a64 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest1.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest1.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.VM; using Neo.VM.Types; using System; @@ -70,10 +71,8 @@ public void Test_ByteArrayPick() testengine.AddEntryScript("./TestClasses/Contract2.cs"); var result = testengine.GetMethod("unitTest_002").Run("hello", 1); - StackItem wantresult = 3; - var bequal = wantresult.Equals(result); - Assert.IsTrue(bequal); + Assert.AreEqual(3, result.GetInteger()); } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ABI_Event.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ABI_Event.cs index 946513130..3a8517541 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ABI_Event.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ABI_Event.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.IO.Json; using System; namespace Neo.Compiler.MSIL.UnitTests @@ -12,9 +13,9 @@ public void Test_Good() { var testengine = new TestEngine(); testengine.AddEntryScript("./TestClasses/Contract_Event.cs"); - var abi = testengine.ScriptEntry.finialABI; + var abi = testengine.ScriptEntry.finalABI; Console.WriteLine("abi=" + abi.ToString()); - var events = abi["events"].AsList()[0].ToString(); + var events = (abi["events"] as JArray)[0].ToString(); Console.WriteLine("event abi info =" + events); string expecteventabi = @"{""name"":""transfer"",""parameters"":[{""name"":""arg1"",""type"":""ByteArray""},{""name"":""arg2"",""type"":""ByteArray""},{""name"":""arg3"",""type"":""Integer""}]}"; diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ABI_Offset.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ABI_Offset.cs index da561acb4..b7432a2b3 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ABI_Offset.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ABI_Offset.cs @@ -1,7 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.IO.Json; using Neo.VM.Types; -using System; namespace Neo.Compiler.MSIL.UnitTests { @@ -12,28 +12,28 @@ public class UnitTest_ABI_Offset public void UnitTest_TestABIOffsetWithoutOptimizer() { var buildScript = NeonTestTool.BuildScript("./TestClasses/Contract_ABIOffset.cs", true, false); - var abi = buildScript.finialABI; + var abi = buildScript.finalABI; - var methodsABI = abi["methods"].AsList(); - Assert.AreEqual("0", methodsABI[0].GetDictItem("offset").ToString()); - Assert.AreEqual("6", methodsABI[1].GetDictItem("offset").ToString()); - Assert.AreEqual("38", methodsABI[2].GetDictItem("offset").ToString()); + var methodsABI = abi["methods"] as JArray; + Assert.AreEqual("0", methodsABI[0]["offset"].AsString()); + Assert.AreEqual("6", methodsABI[1]["offset"].AsString()); + Assert.AreEqual("38", methodsABI[2]["offset"].AsString()); // _initialize() - Assert.AreEqual("49", methodsABI[3].GetDictItem("offset").ToString()); + Assert.AreEqual("49", methodsABI[3]["offset"].AsString()); } [TestMethod] public void UnitTest_TestABIOffsetWithOptimizer() { var buildScript = NeonTestTool.BuildScript("./TestClasses/Contract_ABIOffset.cs", true, true); - var abi = buildScript.finialABI; + var abi = buildScript.finalABI; - var methodsABI = abi["methods"].AsList(); - Assert.AreEqual("0", methodsABI[0].GetDictItem("offset").ToString()); - Assert.AreEqual("5", methodsABI[1].GetDictItem("offset").ToString()); - Assert.AreEqual("30", methodsABI[2].GetDictItem("offset").ToString()); + var methodsABI = abi["methods"] as JArray; + Assert.AreEqual("0", methodsABI[0]["offset"].AsString()); + Assert.AreEqual("5", methodsABI[1]["offset"].AsString()); + Assert.AreEqual("30", methodsABI[2]["offset"].AsString()); // _initialize() - Assert.AreEqual("36", methodsABI[3].GetDictItem("offset").ToString()); + Assert.AreEqual("36", methodsABI[3]["offset"].AsString()); } [TestMethod] diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Appcall.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Appcall.cs deleted file mode 100644 index 1d7ebbaeb..000000000 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Appcall.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Compiler.MSIL.UnitTests.Utils; -using Neo.IO.Json; -using Neo.SmartContract.Manifest; -using Neo.VM.Types; - -namespace Neo.Compiler.MSIL.UnitTests -{ - [TestClass] - public class UnitTest_AppCall - { - [TestMethod] - public void Test_Appcall() - { - var hash = UInt160.Parse("0102030405060708090A0102030405060708090A"); - var testengine = new TestEngine(); - testengine.Snapshot.Contracts.Add(hash, new Ledger.ContractState() - { - //Manifest = new SmartContract.Manifest.ContractManifest(), - Script = testengine.Build("./TestClasses/Contract1.cs").finalNEF, - Manifest = ContractManifest.FromJson(JObject.Parse(testengine.Build("./TestClasses/Contract1.cs").finalManifest)), - }); - - //will appcall 0102030405060708090A0102030405060708090A - testengine.AddEntryScript("./TestClasses/Contract_appcall.cs"); - - var result = testengine.GetMethod("testAppCall").Run().ConvertTo(StackItemType.ByteString); - StackItem wantresult = new byte[] { 1, 2, 3, 4 }; - - var bequal = wantresult.Equals(result); - Assert.IsTrue(bequal); - } - } -} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Array.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Array.cs index eda5d9c5e..3e75b9fd7 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Array.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Array.cs @@ -16,8 +16,8 @@ public void Test_IntArray() var result = testengine.ExecuteTestCaseStandard("testIntArray"); //test 0,1,2 - Assert.IsTrue(result.TryPop(out Array arr)); - CollectionAssert.AreEqual(new int[] { 0, 1, 2 }, arr.Cast().Select(u => (int)u.ToBigInteger()).ToArray()); + var arr = result.Pop(); + CollectionAssert.AreEqual(new int[] { 0, 1, 2 }, arr.Cast().Select(u => (int)u.GetInteger()).ToArray()); } [TestMethod] @@ -28,8 +28,8 @@ public void Test_IntArrayInit() var result = testengine.ExecuteTestCaseStandard("testIntArrayInit"); //test 1,4,5 - Assert.IsTrue(result.TryPop(out Array arr)); - CollectionAssert.AreEqual(new int[] { 1, 4, 5 }, arr.Cast().Select(u => (int)u.ToBigInteger()).ToArray()); + var arr = result.Pop(); + CollectionAssert.AreEqual(new int[] { 1, 4, 5 }, arr.Cast().Select(u => (int)u.GetInteger()).ToArray()); } /* TODO: We should uncomment this when NEWARRAY_T was done @@ -41,7 +41,7 @@ public void Test_DefaultArray() var result = testengine.ExecuteTestCaseStandard("TestDefaultArray"); //test true - Assert.IsTrue(result.TryPop(out Boolean b) && b.ToBoolean()); + Assert.IsTrue(result.TryPop(out Boolean b) && b.GetBoolean()); } */ diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ContractCall.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ContractCall.cs new file mode 100644 index 000000000..5c10863f9 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_ContractCall.cs @@ -0,0 +1,49 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.IO.Json; +using Neo.SmartContract.Manifest; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.Compiler.MSIL.UnitTests +{ + [TestClass] + public class UnitTest_ContractCall + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + var hash = UInt160.Parse("0102030405060708090A0102030405060708090A"); + _engine = new TestEngine(); + _engine.Snapshot.Contracts.Add(hash, new Ledger.ContractState() + { + Script = _engine.Build("./TestClasses/Contract1.cs").finalNEF, + Manifest = ContractManifest.FromJson(JObject.Parse(_engine.Build("./TestClasses/Contract1.cs").finalManifest)), + }); + + //will ContractCall 0102030405060708090A0102030405060708090A + _engine.AddEntryScript("./TestClasses/Contract_ContractCall.cs"); + } + + [TestMethod] + public void Test_ContractCall() + { + var result = _engine.GetMethod("testContractCall").Run().ConvertTo(StackItemType.ByteString); + Assert.AreEqual(VMState.HALT, _engine.State); + + StackItem wantresult = new byte[] { 1, 2, 3, 4 }; + var bequal = wantresult.Equals(result); + Assert.IsTrue(bequal); + } + + [TestMethod] + public void Test_ContractCall_Void() + { + var result = _engine.ExecuteTestCaseStandard("testContractCallVoid"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(0, result.Count); + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_DebugInfo.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_DebugInfo.cs new file mode 100644 index 000000000..d2317f63c --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_DebugInfo.cs @@ -0,0 +1,33 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.IO.Json; +using System.Linq; + +namespace Neo.Compiler.MSIL +{ + [TestClass] + public class UnitTest_DebugInfo + { + [TestMethod] + public void Test_DebugInfo() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_Event.cs"); + var debugInfo = testengine.ScriptEntry.debugInfo; + Assert.IsTrue(debugInfo.ContainsProperty("hash")); + Assert.IsInstanceOfType(debugInfo["hash"], typeof(JString)); + Assert.IsTrue(debugInfo.ContainsProperty("documents")); + Assert.IsInstanceOfType(debugInfo["documents"], typeof(JArray)); + Assert.AreEqual((debugInfo["documents"] as JArray).Count, 1); + Assert.IsTrue((debugInfo["documents"] as JArray).All(n => n is JString)); + Assert.IsTrue(debugInfo.ContainsProperty("methods")); + Assert.IsInstanceOfType(debugInfo["methods"], typeof(JArray)); + Assert.AreEqual((debugInfo["methods"] as JArray).Count, 1); + Assert.AreEqual((debugInfo["methods"] as JArray)[0]["name"].AsString(), "Neo.Compiler.MSIL.UnitTests.TestClasses.Contract_Event,main"); + Assert.IsTrue(debugInfo.ContainsProperty("events")); + Assert.IsInstanceOfType(debugInfo["events"], typeof(JArray)); + Assert.AreEqual((debugInfo["events"] as JArray).Count, 1); + Assert.AreEqual((debugInfo["events"] as JArray)[0]["name"].AsString(), "Neo.Compiler.MSIL.UnitTests.TestClasses.Contract_Event,transfer"); + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_FuncExport.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_FuncExport.cs new file mode 100644 index 000000000..44a484bb9 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_FuncExport.cs @@ -0,0 +1,45 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mono.Cecil; +using System; +using System.Numerics; + +namespace Neo.Compiler.MSIL.UnitTests +{ + [TestClass] + public class UnitTest_FuncExport + { + [TestMethod] + public void ConvTypeTest() + { + Assert.AreEqual("Null", FuncExport.ConvType(null)); + Assert.AreEqual("Void", FuncExport.ConvType(FuncExport.Void)); + Assert.AreEqual("String", FuncExport.ConvType(Convert(typeof(string)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(BigInteger)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(char)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(byte)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(sbyte)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(short)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(ushort)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(int)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(uint)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(long)))); + Assert.AreEqual("Integer", FuncExport.ConvType(Convert(typeof(ulong)))); + Assert.AreEqual("Boolean", FuncExport.ConvType(Convert(typeof(bool)))); + Assert.AreEqual("ByteArray", FuncExport.ConvType(Convert(typeof(byte[])))); + Assert.AreEqual("Any", FuncExport.ConvType(Convert(typeof(object)))); + Assert.AreEqual("Array", FuncExport.ConvType(Convert(typeof(object[])))); + Assert.AreEqual("Array", FuncExport.ConvType(Convert(typeof(int[])))); + Assert.AreEqual("Array", FuncExport.ConvType(Convert(typeof(bool[])))); + Assert.IsTrue(FuncExport.ConvType(Convert(typeof(Action))).StartsWith("Unknown:Pointers are not allowed to be public 'System.Action`1")); + Assert.IsTrue(FuncExport.ConvType(Convert(typeof(Func))).StartsWith("Unknown:Pointers are not allowed to be public 'System.Func`2")); + Assert.AreEqual("Array", FuncExport.ConvType(Convert(typeof(Tuple)))); + Assert.AreEqual("Array", FuncExport.ConvType(Convert(typeof(Tuple[])))); + } + + private TypeReference Convert(Type type) + { + var a = AssemblyDefinition.ReadAssembly(type.Assembly.Location); + return a.MainModule.ImportReference(type); + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Invoke.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Invoke.cs new file mode 100644 index 000000000..c56d95894 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Invoke.cs @@ -0,0 +1,60 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.VM.Types; +using System.IO; + +namespace Neo.Compiler.MSIL.UnitTests +{ + [TestClass] + public class UnitTest_Invoke + { + private TestEngine testengine; + + [TestInitialize] + public void Init() + { + string path = Directory.GetCurrentDirectory(); + var option = new Program.Options() + { + File = path + "/TestClasses/Contract_InvokeCsNef.cs" + }; + Program.Compile(option); + + testengine = new TestEngine(); + testengine.AddEntryScript(path + "/TestClasses/Contract_InvokeCsNef.nef"); + + //Compile changes the path, reseting so that other UT won't break + Directory.SetCurrentDirectory(path); + } + + [TestMethod] + public void Test_Return_Integer() + { + testengine.Reset(); + var result = testengine.GetMethod("returnInteger").Run(); + + Integer wantresult = 42; + Assert.IsTrue(wantresult.Equals(result)); + } + + [TestMethod] + public void Test_Return_String() + { + testengine.Reset(); + var result = testengine.GetMethod("returnString").Run(); + + ByteString wantresult = "hello world"; + Assert.IsTrue(wantresult.Equals(result)); + } + + [TestMethod] + public void Test_Main() + { + testengine.Reset(); + var result = testengine.GetMethod("main").Run(); + + Integer wantresult = 22; + Assert.IsTrue(wantresult.Equals(result)); + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NULL.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NULL.cs index a1ddf6835..3100902d8 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NULL.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NULL.cs @@ -27,7 +27,7 @@ public void IsNull() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); // False @@ -36,7 +36,7 @@ public void IsNull() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); } [TestMethod] @@ -47,7 +47,7 @@ public void IfNull() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); } [TestMethod] @@ -102,6 +102,7 @@ public void NullCollation() Assert.IsTrue(str == "linux"); } } + [TestMethod] public void NullCollationAndCollation() { @@ -115,13 +116,12 @@ public void NullCollationAndCollation() Features = ContractFeatures.HasStorage } }); - { - var result = _testengine.ExecuteTestCaseStandard("nullCollationAndCollation", "nes"); - var item = result.Pop() as Integer; - var num = item.ToBigInteger(); - Assert.IsTrue(num == 123); - } + + var result = _testengine.ExecuteTestCaseStandard("nullCollationAndCollation", "nes"); + var item = result.Pop() as Buffer; + Assert.AreEqual(123, item.GetSpan()[0]); } + [TestMethod] public void NullCollationAndCollation2() { @@ -135,15 +135,15 @@ public void NullCollationAndCollation2() Features = ContractFeatures.HasStorage } }); - { - var result = _testengine.ExecuteTestCaseStandard("nullCollationAndCollation2", "nes"); - var item = result.Pop() as Integer; - var bts = System.Text.Encoding.ASCII.GetBytes("111"); - var num = new System.Numerics.BigInteger(bts); - Assert.IsTrue(item.ToBigInteger() == num); - } + var result = _testengine.ExecuteTestCaseStandard("nullCollationAndCollation2", "nes"); + var item = result.Pop() as ByteString; + var bts = System.Text.Encoding.ASCII.GetBytes("111"); + var num = new System.Numerics.BigInteger(bts); + + Assert.AreEqual(num, item.GetInteger()); } + [TestMethod] public void EqualNull() { @@ -154,7 +154,7 @@ public void EqualNull() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); // False @@ -163,7 +163,7 @@ public void EqualNull() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); // True @@ -172,7 +172,7 @@ public void EqualNull() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); // False @@ -181,7 +181,7 @@ public void EqualNull() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); } [TestMethod] @@ -194,7 +194,7 @@ public void EqualNotNull() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); // False @@ -203,7 +203,7 @@ public void EqualNotNull() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); // True @@ -212,7 +212,7 @@ public void EqualNotNull() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); // False @@ -221,7 +221,7 @@ public void EqualNotNull() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NefOptimizer.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NefOptimizer.cs index 802186280..e18a66f1b 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NefOptimizer.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_NefOptimizer.cs @@ -1,5 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; using Neo.Compiler.Optimizer; +using Neo.IO.Json; using Neo.VM; using System; using System.Buffers.Binary; @@ -10,6 +12,16 @@ namespace Neo.Compiler.MSIL [TestClass] public class UnitTest_NefOptimizer { + [TestMethod] + public void Test_OptimizerNopEntryPoint() + { + var testengine = new TestEngine(); + var build = testengine.Build("./TestClasses/Contract_OptimizationTest.cs", false, true); + + Assert.AreEqual((build.finalABI["methods"] as JArray)[0]["name"].AsString(), "verify"); + Assert.AreEqual((build.finalABI["methods"] as JArray)[0]["offset"].AsString(), "0"); + } + [TestMethod] public void Test_Optimize_RemoveNOPS() { @@ -602,6 +614,60 @@ public void Test_Optimize_StaticMath_MUL() } } + [TestMethod] + public void Test_Optimize_ConstExecution_ROT() + { + using (var scriptBefore = new ScriptBuilder()) + { + scriptBefore.Emit(VM.OpCode.PUSH1); + scriptBefore.Emit(VM.OpCode.PUSH2); + scriptBefore.Emit(VM.OpCode.PUSH3); + scriptBefore.Emit(VM.OpCode.ROT); + + using (var scriptAfter = new ScriptBuilder()) + { + scriptAfter.Emit(VM.OpCode.PUSH2); + scriptAfter.Emit(VM.OpCode.PUSH3); + scriptAfter.Emit(VM.OpCode.PUSH1); + + var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty(), OptimizeParserType.DELETE_CONST_EXECUTION); + CollectionAssert.AreEqual(scriptAfter.ToArray(), optimized); + } + } + + using (var scriptBefore = new ScriptBuilder()) + { + scriptBefore.Emit(VM.OpCode.PUSH1); + scriptBefore.Emit(VM.OpCode.PUSH2); + scriptBefore.Emit(VM.OpCode.PUSHNULL); + scriptBefore.Emit(VM.OpCode.ROT); + + using (var scriptAfter = new ScriptBuilder()) + { + scriptAfter.Emit(VM.OpCode.PUSH2); + scriptAfter.Emit(VM.OpCode.PUSHNULL); + scriptAfter.Emit(VM.OpCode.PUSH1); + + var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty(), OptimizeParserType.DELETE_CONST_EXECUTION); + CollectionAssert.AreEqual(scriptAfter.ToArray(), optimized); + } + } + + using (var scriptBefore = new ScriptBuilder()) + { + scriptBefore.Emit(VM.OpCode.PUSH5); + scriptBefore.Emit(VM.OpCode.PUSH4); + scriptBefore.EmitJump(VM.OpCode.JMP, 3); + scriptBefore.Emit(VM.OpCode.PUSH1); + scriptBefore.Emit(VM.OpCode.PUSH2); + scriptBefore.Emit(VM.OpCode.PUSH3); + scriptBefore.Emit(VM.OpCode.ROT); + + var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty(), OptimizeParserType.DELETE_CONST_EXECUTION); + CollectionAssert.AreEqual(scriptBefore.ToArray(), optimized); + } + } + [TestMethod] public void Test_Optimize_Recalculate_BoolEqualTrue() { diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Returns.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Returns.cs index 3574efc14..b1f8a1ed5 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Returns.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Returns.cs @@ -43,7 +43,7 @@ public void Test_DoubleReturnB() Assert.AreEqual(1, result.Count); - Assert.IsTrue(result.TryPop(out Integer r1)); + var r1 = result.Pop(); Assert.AreEqual(-3, r1); } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Shift.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Shift.cs index b3cfc97e3..342a68529 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Shift.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Shift.cs @@ -14,7 +14,7 @@ public class UnitTest_Shift public void Test_Shift() { var list = new List(); - var method = new EventHandler((sender, e) => list.Add(((VM.Types.Integer)((VM.Types.Array)e.State)[0]).ToBigInteger())); + var method = new EventHandler((sender, e) => list.Add(((VM.Types.Integer)((VM.Types.Array)e.State)[0]).GetInteger())); ApplicationEngine.Notify += method; var testengine = new TestEngine(); @@ -30,7 +30,7 @@ public void Test_Shift() public void Test_Shift_BigInteger() { var list = new List(); - var method = new EventHandler((sender, e) => list.Add(((VM.Types.Integer)((VM.Types.Array)e.State)[0]).ToBigInteger())); + var method = new EventHandler((sender, e) => list.Add(((VM.Types.Integer)((VM.Types.Array)e.State)[0]).GetInteger())); ApplicationEngine.Notify += method; var testengine = new TestEngine(); diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_StaticByteArray.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_StaticByteArray.cs new file mode 100644 index 000000000..9c2103605 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_StaticByteArray.cs @@ -0,0 +1,19 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; + +namespace Neo.Compiler.MSIL.UnitTests +{ + [TestClass] + public class UnitTest_StaticByteArray + { + [TestMethod] + public void TestStaticByteArray() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_StaticByteArray.cs"); + var result = testengine.ExecuteTestCaseStandard("testStaticByteArray").Pop(); + var wantResult = new byte[] { 0x89, 0x77, 0x20, 0xd8, 0xcd, 0x76, 0xf4, 0xf0, 0x0a, 0xbf, 0xa3, 0x7c, 0x0e, 0xdd, 0x88, 0x9c, 0x20, 0x8f, 0xde, 0x9b }; + Assert.AreEqual(wantResult, result); + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Switch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Switch.cs index a24200282..8f655d8fc 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Switch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Switch.cs @@ -23,14 +23,14 @@ public void Test_SwitchLong() { testengine.Reset(); result = testengine.ExecuteTestCaseStandard("main", x.ToString()); - Assert.AreEqual(result.Pop().GetBigInteger(), x + 1); + Assert.AreEqual(result.Pop().GetInteger(), x + 1); } // Test default testengine.Reset(); result = testengine.ExecuteTestCaseStandard("main", 21.ToString()); - Assert.AreEqual(result.Pop().GetBigInteger(), 99); + Assert.AreEqual(result.Pop().GetInteger(), 99); } [TestMethod] @@ -62,13 +62,13 @@ public void Test_SwitchLongLong() // Test default - Assert.AreEqual(resulta.GetBigInteger(), awant); - Assert.AreEqual(resultb.GetBigInteger(), bwant); - Assert.AreEqual(resultc.GetBigInteger(), cwant); - Assert.AreEqual(resultd.GetBigInteger(), dwant); - Assert.AreEqual(resulte.GetBigInteger(), ewant); - Assert.AreEqual(resultf.GetBigInteger(), fwant); - Assert.AreEqual(resultg.GetBigInteger(), gwant); + Assert.AreEqual(resulta.GetInteger(), awant); + Assert.AreEqual(resultb.GetInteger(), bwant); + Assert.AreEqual(resultc.GetInteger(), cwant); + Assert.AreEqual(resultd.GetInteger(), dwant); + Assert.AreEqual(resulte.GetInteger(), ewant); + Assert.AreEqual(resultf.GetInteger(), fwant); + Assert.AreEqual(resultg.GetInteger(), gwant); } [TestMethod] @@ -91,10 +91,10 @@ public void Test_SwitchInteger() // Test default - Assert.AreEqual(result1.GetBigInteger(), onewant); - Assert.AreEqual(result2.GetBigInteger(), twowant); - Assert.AreEqual(result3.GetBigInteger(), threewant); - Assert.AreEqual(result0.GetBigInteger(), zerowant); + Assert.AreEqual(result1.GetInteger(), onewant); + Assert.AreEqual(result2.GetInteger(), twowant); + Assert.AreEqual(result3.GetInteger(), threewant); + Assert.AreEqual(result0.GetInteger(), zerowant); } [TestMethod] @@ -110,14 +110,14 @@ public void Test_SwitchLong_Release() { testengine.Reset(); result = testengine.ExecuteTestCaseStandard("main", x.ToString()); - Assert.AreEqual(result.Pop().GetBigInteger(), x + 1); + Assert.AreEqual(result.Pop().GetInteger(), x + 1); } // Test default testengine.Reset(); result = testengine.ExecuteTestCaseStandard("main", 21.ToString()); - Assert.AreEqual(result.Pop().GetBigInteger(), 99); + Assert.AreEqual(result.Pop().GetInteger(), 99); } [TestMethod] @@ -133,14 +133,14 @@ public void Test_Switch6() { testengine.Reset(); result = testengine.ExecuteTestCaseStandard("main", x.ToString()); - Assert.AreEqual(result.Pop().GetBigInteger(), x + 1); + Assert.AreEqual(result.Pop().GetInteger(), x + 1); } // Test default testengine.Reset(); result = testengine.ExecuteTestCaseStandard("main", 6.ToString()); - Assert.AreEqual(result.Pop().GetBigInteger(), 99); + Assert.AreEqual(result.Pop().GetInteger(), 99); } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index 30c4b06e1..8ac5785ae 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -18,8 +18,8 @@ public void Test_TryCatch_Succ() var value = result.Pop(); Console.WriteLine("result:" + value.Type + " " + value.ToString()); var num = value as Neo.VM.Types.Integer; - Console.WriteLine("result = " + num.ToBigInteger().ToString()); - Assert.AreEqual(num.ToBigInteger(), 3); + Console.WriteLine("result = " + num.GetInteger().ToString()); + Assert.AreEqual(num.GetInteger(), 3); } [TestMethod] @@ -33,8 +33,8 @@ public void Test_TryCatch_ThrowByCall() var value = result.Pop(); Console.WriteLine("result:" + value.Type + " " + value.ToString()); var num = value as Neo.VM.Types.Integer; - Console.WriteLine("result = " + num.ToBigInteger().ToString()); - Assert.AreEqual(num.ToBigInteger(), 4); + Console.WriteLine("result = " + num.GetInteger().ToString()); + Assert.AreEqual(num.GetInteger(), 4); } [TestMethod] @@ -48,8 +48,8 @@ public void Test_TryCatch_Throw() var value = result.Pop(); Console.WriteLine("result:" + value.Type + " " + value.ToString()); var num = value as Neo.VM.Types.Integer; - Console.WriteLine("result = " + num.ToBigInteger().ToString()); - Assert.AreEqual(num.ToBigInteger(), 4); + Console.WriteLine("result = " + num.GetInteger().ToString()); + Assert.AreEqual(num.GetInteger(), 4); } [TestMethod] @@ -63,8 +63,8 @@ public void Test_TryNest() var value = result.Pop(); Console.WriteLine("result:" + value.Type + " " + value.ToString()); var num = value as Neo.VM.Types.Integer; - Console.WriteLine("result = " + num.ToBigInteger().ToString()); - Assert.AreEqual(num.ToBigInteger(), 4); + Console.WriteLine("result = " + num.GetInteger().ToString()); + Assert.AreEqual(num.GetInteger(), 4); } [TestMethod] @@ -78,8 +78,8 @@ public void Test_TryFinally() var value = result.Pop(); Console.WriteLine("result:" + value.Type + " " + value.ToString()); var num = value as Neo.VM.Types.Integer; - Console.WriteLine("result = " + num.ToBigInteger().ToString()); - Assert.AreEqual(num.ToBigInteger(), 3); + Console.WriteLine("result = " + num.GetInteger().ToString()); + Assert.AreEqual(num.GetInteger(), 3); } [TestMethod] @@ -104,8 +104,8 @@ public void Test_TryCatch() var value = result.Pop(); Console.WriteLine("result:" + value.Type + " " + value.ToString()); var num = value as Neo.VM.Types.Integer; - Console.WriteLine("result = " + num.ToBigInteger().ToString()); - Assert.AreEqual(num.ToBigInteger(), 3); + Console.WriteLine("result = " + num.GetInteger().ToString()); + Assert.AreEqual(num.GetInteger(), 3); } [TestMethod] @@ -119,8 +119,8 @@ public void Test_TryWithTwoFinally() var value = result.Pop(); Console.WriteLine("result:" + value.Type + " " + value.ToString()); var num = value as Neo.VM.Types.Integer; - Console.WriteLine("result = " + num.ToBigInteger().ToString()); - Assert.AreEqual(num.ToBigInteger(), 9); + Console.WriteLine("result = " + num.GetInteger().ToString()); + Assert.AreEqual(num.GetInteger(), 9); } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TypeConvert.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TypeConvert.cs index 6c4729a15..a9684a982 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TypeConvert.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TypeConvert.cs @@ -15,22 +15,22 @@ public void UnitTest_TestTypeConvert() var result = testengine.ExecuteTestCaseStandard("testType"); //test 0,1,2 - Assert.IsTrue(result.TryPop(out Array arr)); + var arr = result.Pop(); Assert.IsTrue(arr[0].Type == StackItemType.Integer); Assert.IsTrue(arr[1].Type == StackItemType.Buffer); - Assert.IsTrue((arr[1].ConvertTo(StackItemType.ByteString) as PrimitiveType).ToBigInteger() == (arr[0] as PrimitiveType).ToBigInteger()); + Assert.IsTrue((arr[1].ConvertTo(StackItemType.ByteString) as PrimitiveType).GetInteger() == (arr[0] as PrimitiveType).GetInteger()); Assert.IsTrue(arr[2].Type == StackItemType.Integer); Assert.IsTrue(arr[3].Type == StackItemType.Buffer); - Assert.IsTrue((arr[3].ConvertTo(StackItemType.ByteString) as PrimitiveType).ToBigInteger() == (arr[2] as PrimitiveType).ToBigInteger()); + Assert.IsTrue((arr[3].ConvertTo(StackItemType.ByteString) as PrimitiveType).GetInteger() == (arr[2] as PrimitiveType).GetInteger()); Assert.IsTrue(arr[4].Type == StackItemType.Buffer); Assert.IsTrue(arr[5].Type == StackItemType.Integer); - Assert.IsTrue((arr[4].ConvertTo(StackItemType.ByteString) as PrimitiveType).ToBigInteger() == (arr[5] as PrimitiveType).ToBigInteger()); + Assert.IsTrue((arr[4].ConvertTo(StackItemType.ByteString) as PrimitiveType).GetInteger() == (arr[5] as PrimitiveType).GetInteger()); Assert.IsTrue(arr[6].Type == StackItemType.Buffer); Assert.IsTrue(arr[7].Type == StackItemType.Integer); - Assert.IsTrue((arr[6].ConvertTo(StackItemType.ByteString) as PrimitiveType).ToBigInteger() == (arr[7] as PrimitiveType).ToBigInteger()); + Assert.IsTrue((arr[6].ConvertTo(StackItemType.ByteString) as PrimitiveType).GetInteger() == (arr[7] as PrimitiveType).GetInteger()); } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs index 6be55768d..f5b134a0c 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs @@ -52,7 +52,7 @@ public void null_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkNull"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Null)); } @@ -63,16 +63,16 @@ public void bool_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkBoolTrue"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(1, ((Integer)item).ToBigInteger()); + Assert.AreEqual(1, ((Integer)item).GetInteger()); testengine.Reset(); result = testengine.ExecuteTestCaseStandard("checkBoolFalse"); - Assert.IsTrue(result.TryPop(out item)); + item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, ((Integer)item).ToBigInteger()); + Assert.AreEqual(0, ((Integer)item).GetInteger()); } [TestMethod] @@ -82,9 +82,9 @@ public void sbyte_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkSbyte"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -94,9 +94,9 @@ public void byte_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkByte"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -106,9 +106,9 @@ public void short_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkShort"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -118,9 +118,9 @@ public void ushort_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkUshort"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -130,9 +130,9 @@ public void int_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkInt"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -142,9 +142,9 @@ public void uint_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkUint"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -154,9 +154,9 @@ public void long_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkLong"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -166,9 +166,9 @@ public void ulong_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkUlong"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -178,9 +178,9 @@ public void bigInteger_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkBigInteger"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -190,7 +190,7 @@ public void byteArray_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkByteArray"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Buffer)); CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, ((Buffer)item).GetSpan().ToArray()); } @@ -202,9 +202,9 @@ public void char_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkChar"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual((int)'n', ((Integer)item).ToBigInteger()); + Assert.AreEqual((int)'n', ((Integer)item).GetInteger()); } [TestMethod] @@ -214,7 +214,7 @@ public void string_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkString"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(ByteString)); Assert.AreEqual("neo", ((ByteString)item).GetString()); } @@ -226,7 +226,7 @@ public void arrayObj_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkArrayObj"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Array)); Assert.AreEqual(1, ((Array)item).Count); Assert.AreEqual("neo", (((Array)item)[0] as ByteString).GetString()); @@ -239,9 +239,9 @@ public void enum_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkEnum"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(5, ((Integer)item).ToBigInteger()); + Assert.AreEqual(5, ((Integer)item).GetInteger()); } [TestMethod] @@ -251,7 +251,7 @@ public void class_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkClass"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Array)); Assert.AreEqual(1, ((Array)item).Count); Assert.AreEqual("neo", (((Array)item)[0] as ByteString).GetString()); @@ -264,7 +264,7 @@ public void struct_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkStruct"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Struct)); Assert.AreEqual(1, ((Struct)item).Count); Assert.AreEqual("neo", (((Struct)item)[0] as ByteString).GetString()); @@ -277,7 +277,7 @@ public void tuple_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkTuple"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Array)); Assert.AreEqual(2, ((Array)item).Count); Assert.AreEqual("neo", (((Array)item)[0] as ByteString).GetString()); @@ -291,12 +291,27 @@ public void tuple2_Test() testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); var result = testengine.ExecuteTestCaseStandard("checkTuple2"); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Array)); Assert.AreEqual(2, ((Array)item).Count); Assert.AreEqual("neo", (((Array)item)[0] as ByteString).GetString()); Assert.AreEqual("smart economy", (((Array)item)[1] as ByteString).GetString()); } + + [TestMethod] + public void tuple3_Test() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_Types.cs"); + var result = testengine.ExecuteTestCaseStandard("checkTuple3"); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Array)); + Assert.AreEqual(2, ((Array)item).Count); + Assert.AreEqual("neo", (((Array)item)[0] as ByteString).GetString()); + Assert.AreEqual("smart economy", (((Array)item)[1] as ByteString).GetString()); + } + [TestMethod] public void event_Test() { @@ -306,12 +321,11 @@ public void event_Test() Assert.AreEqual(0, result.Count); Assert.AreEqual(1, testengine.Notifications.Count); - var item = testengine.Notifications.First().State; + var item = testengine.Notifications.First(); - Assert.IsInstanceOfType(item, typeof(Array)); - Assert.AreEqual(2, ((Array)item).Count); - Assert.AreEqual("dummyEvent", (((Array)item)[0] as ByteString).GetString()); - Assert.AreEqual("neo", (((Array)item)[1] as ByteString).GetString()); + Assert.AreEqual(1, item.State.Count); + Assert.AreEqual("dummyEvent", item.EventName); + Assert.AreEqual("neo", (item.State[0] as ByteString).GetString()); } [TestMethod] @@ -322,7 +336,7 @@ public void lambda_Test() var result = testengine.ExecuteTestCaseStandard("checkLambda"); Assert.AreEqual(1, result.Count); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Pointer)); } @@ -334,7 +348,7 @@ public void delegate_Test() var result = testengine.ExecuteTestCaseStandard("checkDelegate"); Assert.AreEqual(1, result.Count); - Assert.IsTrue(result.TryPop(out StackItem item)); + var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Pointer)); } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildNEF.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildNEF.cs new file mode 100644 index 000000000..8ce791f5f --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildNEF.cs @@ -0,0 +1,21 @@ +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.IO.Json; +using Neo.SmartContract; + +namespace Neo.Compiler.MSIL.Utils +{ + class BuildNEF : BuildScript + { + public BuildNEF(NefFile nefFile, string manifestFile) : base() + { + IsBuild = true; + UseOptimizer = false; + Error = null; + finalNEF = nefFile.Script; + JObject manifestAbi = JObject.Parse(manifestFile); + var abi = manifestAbi["abi"] as JObject; + finalABI = abi; + finalManifest = manifestFile; + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildScript.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildScript.cs index 97c6b737a..d91317a69 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildScript.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/BuildScript.cs @@ -1,23 +1,22 @@ -using Mono.Cecil; using Neo.Compiler.Optimizer; -using Neo.SmartContract.Manifest; +using Neo.IO.Json; using System; using System.Collections.Generic; using System.IO; -using System.Linq; namespace Neo.Compiler.MSIL.UnitTests.Utils { public class BuildScript { - public bool IsBuild { get; private set; } - public bool UseOptimizer { get; private set; } - public Exception Error { get; private set; } + public bool IsBuild { get; protected set; } + public bool UseOptimizer { get; protected set; } + public Exception Error { get; protected set; } public ILModule modIL { get; private set; } public ModuleConverter converterIL { get; private set; } - public byte[] finalNEF { get; private set; } - public MyJson.JsonNode_Object finialABI { get; private set; } - public string finalManifest { get; private set; } + public byte[] finalNEF { get; protected set; } + public JObject finalABI { get; protected set; } + public string finalManifest { get; protected set; } + public JObject debugInfo { get; private set; } public BuildScript() { @@ -57,7 +56,7 @@ public void Build(Stream fs, Stream fspdb, bool optimizer) List entryPoints = new List(); foreach (var f in converterIL.outModule.mapMethods.Values) { - if (entryPoints.Contains(f.funcaddr) == false) + if (!entryPoints.Contains(f.funcaddr)) entryPoints.Add(f.funcaddr); } var opbytes = NefOptimizeTool.Optimize(finalNEF, entryPoints.ToArray(), out addrConvTable); @@ -77,7 +76,7 @@ public void Build(Stream fs, Stream fspdb, bool optimizer) #endif try { - finialABI = vmtool.FuncExport.Export(converterIL.outModule, finalNEF, addrConvTable); + finalABI = FuncExport.Export(converterIL.outModule, finalNEF, addrConvTable); } catch (Exception err) { @@ -88,23 +87,24 @@ public void Build(Stream fs, Stream fspdb, bool optimizer) try { - var features = converterIL.outModule == null ? ContractFeatures.NoProperty : converterIL.outModule.attributes - .Where(u => u.AttributeType.Name == "FeaturesAttribute") - .Select(u => (ContractFeatures)u.ConstructorArguments.FirstOrDefault().Value) - .FirstOrDefault(); - - var extraAttributes = converterIL.outModule == null ? new List>() - : converterIL.outModule.attributes.Where(u => u.AttributeType.Name == "ManifestExtraAttribute").Select(attribute => attribute.ConstructorArguments).ToList(); - var storage = features.HasFlag(ContractFeatures.HasStorage).ToString().ToLowerInvariant(); - var payable = features.HasFlag(ContractFeatures.Payable).ToString().ToLowerInvariant(); - - finalManifest = - @"{""groups"":[],""features"":{""storage"":" + storage + @",""payable"":" + payable + @"},""abi"":" + - finialABI + - @",""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safeMethods"":[],""extra"":[]" + "}"; + debugInfo = DebugExport.Export(converterIL.outModule, finalNEF, addrConvTable); } - catch + catch (Exception err) + { + log.Log("Gen debugInfo Error:" + err.ToString()); + this.Error = err; + return; + } + + try + { + finalManifest = FuncExport.GenerateManifest(finalABI, converterIL.outModule); + } + catch (Exception err) { + log.Log("Gen Manifest Error:" + err.ToString()); + this.Error = err; + return; } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/NeonTestTool.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/NeonTestTool.cs index 832b4b997..9260ceb74 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/NeonTestTool.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/NeonTestTool.cs @@ -1,9 +1,11 @@ using Neo.VM; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; +[assembly: InternalsVisibleTo("Neo.SmartContract.Framework.UnitTests")] namespace Neo.Compiler.MSIL.UnitTests.Utils { internal static class NeonTestTool diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestDataCache.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestDataCache.cs index 6e205bdab..1f6da2962 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestDataCache.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestDataCache.cs @@ -28,7 +28,7 @@ protected override void AddInternal(TKey key, TValue value) dic.Add(key, value); } - protected override IEnumerable<(TKey Key, TValue Value)> FindInternal(byte[] key_prefix) + protected override IEnumerable<(TKey Key, TValue Value)> SeekInternal(byte[] keyOrPrefix, SeekDirection direction) { return dic.Select(u => (u.Key, u.Value)); } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs index b2588899a..ebc138812 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs @@ -1,3 +1,5 @@ +using Neo.Compiler.MSIL.Utils; +using Neo.IO.Json; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; @@ -5,16 +7,13 @@ using Neo.VM.Types; using System; using System.Collections.Generic; +using System.IO; namespace Neo.Compiler.MSIL.UnitTests.Utils { public class TestEngine : ApplicationEngine { - protected override bool PreExecuteInstruction() - { - return true; - } - + public const long TestGas = 2000_000_000; public static InteropDescriptor Native_Deploy; static TestEngine() @@ -31,7 +30,7 @@ static TestEngine() public BuildScript ScriptEntry { get; private set; } public TestEngine(TriggerType trigger = TriggerType.Application, IVerifiable verificable = null, StoreView snapshot = null) - : base(trigger, verificable, snapshot ?? new TestSnapshot(), 0, true) + : base(trigger, verificable, snapshot ?? new TestSnapshot(), TestGas) { Scripts = new Dictionary(); } @@ -42,7 +41,23 @@ public BuildScript Build(string filename, bool releaseMode = false, bool optimiz if (!contains || (contains && scriptsAll[filename].UseOptimizer != optimizer)) { - scriptsAll[filename] = NeonTestTool.BuildScript(filename, releaseMode, optimizer); + if (Path.GetExtension(filename).ToLowerInvariant() == ".nef") + { + var fileNameManifest = filename; + using (BinaryReader reader = new BinaryReader(File.OpenRead(filename))) + { + NefFile neffile = new NefFile(); + neffile.Deserialize(reader); + fileNameManifest = fileNameManifest.Replace(".nef", ".manifest.json"); + string manifestFile = File.ReadAllText(fileNameManifest); + BuildScript buildScriptNef = new BuildNEF(neffile, manifestFile); + scriptsAll[filename] = buildScriptNef; + } + } + else + { + scriptsAll[filename] = NeonTestTool.BuildScript(filename, releaseMode, optimizer); + } } return scriptsAll[filename]; @@ -114,13 +129,14 @@ public ContractMethod GetMethod(string methodname) public int GetMethodEntryOffset(string methodname) { if (this.ScriptEntry is null) return -1; - var methods = this.ScriptEntry.finialABI.GetDictItem("methods") as MyJson.JsonNode_Array; + var methods = this.ScriptEntry.finalABI["methods"] as JArray; foreach (var item in methods) { - var method = item as MyJson.JsonNode_Object; - if (method.GetDictItem("name").ToString() == methodname) - return int.Parse(method.GetDictItem("offset").ToString()); + var method = item as JObject; + if (method["name"].AsString() == methodname) + return int.Parse(method["offset"].AsString()); } + return -1; } @@ -133,12 +149,15 @@ public EvaluationStack ExecuteTestCaseStandard(string methodname, params StackIt public EvaluationStack ExecuteTestCaseStandard(int offset, params StackItem[] args) { - this.InvocationStack.Peek().InstructionPointer = offset; + var context = InvocationStack.Pop(); + LoadContext(context.Clone(offset)); for (var i = args.Length - 1; i >= 0; i--) this.Push(args[i]); var initializeOffset = GetMethodEntryOffset("_initialize"); if (initializeOffset != -1) - this.LoadClonedContext(initializeOffset); + { + LoadContext(CurrentContext.Clone(initializeOffset)); + } while (true) { var bfault = (this.State & VMState.FAULT) > 0; @@ -153,10 +172,19 @@ public EvaluationStack ExecuteTestCaseStandard(int offset, params StackItem[] ar return this.ResultStack; } + protected override void OnFault(Exception e) + { + base.OnFault(e); + Console.WriteLine(e.ToString()); + } + public EvaluationStack ExecuteTestCase(params StackItem[] args) { - //var engine = new ExecutionEngine(); - this.InvocationStack.Peek().InstructionPointer = 0; + if (CurrentContext.InstructionPointer != 0) + { + var context = InvocationStack.Pop(); + LoadContext(context.Clone(0)); + } if (args != null) { for (var i = args.Length - 1; i >= 0; i--) @@ -179,9 +207,20 @@ public EvaluationStack ExecuteTestCase(params StackItem[] args) return this.ResultStack; } + public void SendTestNotification(UInt160 hash, string eventName, VM.Types.Array state) + { + typeof(ApplicationEngine).GetMethod("SendNotification", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + .Invoke(this, new object[] { hash, eventName, state }); + } + static Dictionary callmethod; - protected override bool OnSysCall(uint method) + public void ClearNotifications() + { + typeof(ApplicationEngine).GetField("notifications", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(this, null); + } + + protected override void OnSysCall(uint method) { if (callmethod == null) { @@ -191,16 +230,16 @@ protected override bool OnSysCall(uint method) }; foreach (var m in ApplicationEngine.Services) { - callmethod[m] = m; + callmethod[m.Key] = m.Value; } } if (callmethod.ContainsKey(method) == false) { - throw new Exception($"Syscall not found: {method.ToString("X2")} (using base call)"); + throw new Exception($"Syscall not found: {method:X2} (using base call)"); } else { - return base.OnSysCall(method); + base.OnSysCall(method); } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/base58.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/base58.cs deleted file mode 100644 index b4c75f8e1..000000000 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/base58.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Linq; -using System.Numerics; -using System.Text; - -namespace Neo.Compiler.MSIL.UnitTests.Utils -{ - public static class Base58 - { - /// - /// base58编码的字母表 - /// - public const string Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - - /// - /// 解码 - /// - /// 要解码的字符串 - /// 返回解码后的字节数组 - public static byte[] Decode(string input) - { - BigInteger bi = BigInteger.Zero; - for (int i = input.Length - 1; i >= 0; i--) - { - int index = Alphabet.IndexOf(input[i]); - if (index == -1) - throw new FormatException(); - bi += index * BigInteger.Pow(58, input.Length - 1 - i); - } - byte[] bytes = bi.ToByteArray(); - Array.Reverse(bytes); - bool stripSignByte = bytes.Length > 1 && bytes[0] == 0 && bytes[1] >= 0x80; - int leadingZeros = 0; - for (int i = 0; i < input.Length && input[i] == Alphabet[0]; i++) - { - leadingZeros++; - } - byte[] tmp = new byte[bytes.Length - (stripSignByte ? 1 : 0) + leadingZeros]; - Array.Copy(bytes, stripSignByte ? 1 : 0, tmp, leadingZeros, tmp.Length - leadingZeros); - return tmp; - } - - /// - /// 编码 - /// - /// 要编码的字节数组 - /// 返回编码后的字符串 - public static string Encode(byte[] input) - { - BigInteger value = new BigInteger(new byte[1].Concat(input).Reverse().ToArray()); - StringBuilder sb = new StringBuilder(); - while (value >= 58) - { - BigInteger mod = value % 58; - sb.Insert(0, Alphabet[(int)mod]); - value /= 58; - } - sb.Insert(0, Alphabet[(int)value]); - foreach (byte b in input) - { - if (b == 0) - sb.Insert(0, Alphabet[0]); - else - break; - } - return sb.ToString(); - } - } -} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/FeatureTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/FeatureTest.cs index 19fbd3611..7fc60332e 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/FeatureTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/FeatureTest.cs @@ -20,7 +20,7 @@ public void TestFeature() // Check that was the SmartContract Feature Assert.AreEqual(ContractFeatures.Payable, testengine.ScriptEntry.converterIL.outModule.attributes - .Where(u => u.AttributeType.Name == "FeaturesAttribute") + .Where(u => u.AttributeType.FullName == "Neo.SmartContract.Framework.FeaturesAttribute") .Select(u => (ContractFeatures)u.ConstructorArguments.FirstOrDefault().Value) .FirstOrDefault()); } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/HelperTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/HelperTest.cs index 0844f1d63..592115821 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/HelperTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/HelperTest.cs @@ -28,7 +28,42 @@ public void TestHexToBytes() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(ByteString)); - Assert.AreEqual("0a0b0c0d0e0f", (item as ByteString).Span.ToHexString()); + Assert.AreEqual("0a0b0c0d0e0f", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestToBigInteger() + { + // 0 + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testToBigInteger", StackItem.Null); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0, item.GetInteger()); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testToBigInteger", new ByteString(new byte[0])); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0, item.GetInteger()); + + // Value + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testToBigInteger", new ByteString(new byte[] { 123 })); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(123, item.GetInteger()); } [TestMethod] @@ -41,7 +76,7 @@ public void TestAssert() Assert.AreEqual(1, result.Count); var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(item.GetBigInteger(), 5); + Assert.AreEqual(item.GetInteger(), 5); _engine.Reset(); result = _engine.ExecuteTestCaseStandard("assertCall", new Boolean(false)); diff --git a/tests/Neo.SmartContract.Framework.UnitTests/MapTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/MapTest.cs new file mode 100644 index 000000000..fa423dee5 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/MapTest.cs @@ -0,0 +1,137 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.SmartContract.Framework.UnitTests +{ + [TestClass] + public class MapTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + _engine = new TestEngine(); + _engine.AddEntryScript("./TestClasses/Contract_Map.cs"); + } + + [TestMethod] + public void TestByteArrayMap() + { + Assert.ThrowsException(() => _engine.AddEntryScript("./TestClasses/Contract_MapException.cs")); + } + + [TestMethod] + public void TestByteArray() + { + _engine.Reset(); + StackItem key = System.Text.Encoding.ASCII.GetBytes("a"); + var result = _engine.ExecuteTestCaseStandard("testByteArray", key); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"a":"teststring2"} + Assert.AreEqual("7b2261223a2274657374737472696e6732227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestByteArray2() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testByteArray2"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"\u0001\u0001":"\u0022\u0022"} + Assert.AreEqual("7b225c75303030315c7530303031223a225c75303032325c7530303232227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestUnicode() + { + _engine.Reset(); + StackItem key = Utility.StrictUTF8.GetBytes("中"); + var result = _engine.ExecuteTestCaseStandard("testUnicode", key); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"\u4E2D":"129840test10022939"} + Assert.AreEqual("7b225c7534453244223a22313239383430746573743130303232393339227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestUnicodeValue() + { + _engine.Reset(); + StackItem value = Utility.StrictUTF8.GetBytes("文"); + var result = _engine.ExecuteTestCaseStandard("testUnicodeValue", value); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"ab":"\u6587"} + Assert.AreEqual("7b226162223a225c7536353837227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestUnicodeKeyValue() + { + _engine.Reset(); + StackItem key = Utility.StrictUTF8.GetBytes("中"); + StackItem value = Utility.StrictUTF8.GetBytes("文"); + var result = _engine.ExecuteTestCaseStandard("testUnicodeKeyValue", key, value); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + // Except: {"\u4E2D":"\u6587"} + Assert.AreEqual("7b225c7534453244223a225c7536353837227d", (item as ByteString).GetSpan().ToHexString()); + } + + [TestMethod] + public void TestInt() + { + _engine.Reset(); + StackItem key = 1; + _engine.ExecuteTestCaseStandard("testInt", key); + // Int cannot be used as the key for serializing Map + Assert.AreEqual(VMState.FAULT, _engine.State); + } + + [TestMethod] + public void TestBool() + { + _engine.Reset(); + StackItem key = true; + _engine.ExecuteTestCaseStandard("testBool", key); + // Bool cannot be used as the key for serializing Map + Assert.AreEqual(VMState.FAULT, _engine.State); + } + + [TestMethod] + public void TestDeserialize() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testDeserialize", "a"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Map)); + var map = item as Map; + Assert.AreEqual(1, map.Count); + Assert.IsTrue(map.ContainsKey("a")); + Assert.AreEqual((ByteString)"testdeserialize", map["a"]); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/AccountTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/AccountTest.cs index 993817378..da057d09f 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/AccountTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/AccountTest.cs @@ -37,7 +37,7 @@ public void Test_AccountIsStandard() Assert.AreEqual(VM.VMState.FAULT, _engine.State); Assert.AreEqual(0, result.Count); - // Standard + // No standard _engine.Reset(); result = _engine.ExecuteTestCaseStandard("accountIsStandard", new ByteString(new byte[20])); @@ -46,9 +46,7 @@ public void Test_AccountIsStandard() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.AreEqual(true, item.ToBoolean()); - - // No standard + Assert.AreEqual(false, item.GetBoolean()); _engine.Reset(); result = _engine.ExecuteTestCaseStandard("accountIsStandard", new ByteString(noStandard)); @@ -57,7 +55,7 @@ public void Test_AccountIsStandard() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.AreEqual(false, item.ToBoolean()); + 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 index 69462902b..2d6e7b48b 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/BlockchainTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/BlockchainTest.cs @@ -37,7 +37,7 @@ public void Test_GetHeight() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(_block.Index, item.GetBigInteger()); + Assert.AreEqual(_block.Index, item.GetInteger()); } [TestMethod] @@ -52,7 +52,7 @@ public void Test_GetTransactionHeight() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(BigInteger.MinusOne, item.GetBigInteger()); + Assert.AreEqual(BigInteger.MinusOne, item.GetInteger()); // Found @@ -63,7 +63,7 @@ public void Test_GetTransactionHeight() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(_block.Index, item.GetBigInteger()); + Assert.AreEqual(_block.Index, item.GetInteger()); } [TestMethod] @@ -122,7 +122,7 @@ public void Test_GetTransaction(string method, StackItem[] foundArgs, StackItem[ // Hash _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Encoding.UTF8.GetBytes("Hash")))); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Utility.StrictUTF8.GetBytes("Hash")))); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -133,62 +133,62 @@ public void Test_GetTransaction(string method, StackItem[] foundArgs, StackItem[ // NetworkFee _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Encoding.UTF8.GetBytes("NetworkFee")))); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(tx.NetworkFee, item.GetInteger()); // Nonce _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Encoding.UTF8.GetBytes("Nonce")))); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(tx.Nonce, item.GetInteger()); // SystemFee _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Encoding.UTF8.GetBytes("SystemFee")))); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(tx.SystemFee, item.GetInteger()); // ValidUntilBlock _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Encoding.UTF8.GetBytes("ValidUntilBlock")))); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(tx.ValidUntilBlock, item.GetInteger()); // Version _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Encoding.UTF8.GetBytes("Version")))); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(tx.Version, item.GetInteger()); // Script _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Encoding.UTF8.GetBytes("Script")))); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Utility.StrictUTF8.GetBytes("Script")))); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -199,7 +199,7 @@ public void Test_GetTransaction(string method, StackItem[] foundArgs, StackItem[ // Sender _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Encoding.UTF8.GetBytes("Sender")))); + result = _engine.ExecuteTestCaseStandard(method, Concat(foundArgs, new ByteString(Utility.StrictUTF8.GetBytes("Sender")))); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -234,7 +234,7 @@ public void Test_GetBlock(string method, StackItem foundArg, StackItem notFoundA // Hash _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("Hash"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.GetBytes("Hash"))); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -245,18 +245,18 @@ public void Test_GetBlock(string method, StackItem foundArg, StackItem notFoundA // Index _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("Index"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(_block.Index, item.GetInteger()); // MerkleRoot _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("MerkleRoot"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.GetBytes("MerkleRoot"))); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -267,7 +267,7 @@ public void Test_GetBlock(string method, StackItem foundArg, StackItem notFoundA // NextConsensus _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("NextConsensus"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.GetBytes("NextConsensus"))); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -278,7 +278,7 @@ public void Test_GetBlock(string method, StackItem foundArg, StackItem notFoundA // PrevHash _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("PrevHash"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.GetBytes("PrevHash"))); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); @@ -289,40 +289,40 @@ public void Test_GetBlock(string method, StackItem foundArg, StackItem notFoundA // Timestamp _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("Timestamp"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(_block.Timestamp, item.GetInteger()); // TransactionsCount _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("TransactionsCount"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(_block.Transactions.Length, item.GetInteger()); // Version _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("Version"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.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()); + Assert.AreEqual(_block.Version, item.GetInteger()); // Uknown property _engine.Reset(); - result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Encoding.UTF8.GetBytes("ASD"))); + result = _engine.ExecuteTestCaseStandard(method, foundArg, new ByteString(Utility.StrictUTF8.GetBytes("ASD"))); Assert.AreEqual(VMState.FAULT, _engine.State); } @@ -334,7 +334,18 @@ public void GetContract() Script = new byte[] { 0x01, 0x02, 0x03 }, Manifest = new Manifest.ContractManifest() { - Features = Manifest.ContractFeatures.HasStorage + Features = Manifest.ContractFeatures.HasStorage, + SupportedStandards = new string[0], + Groups = new Manifest.ContractGroup[0], + Trusts = Manifest.WildcardContainer.Create(), + Permissions = new Manifest.ContractPermission[0], + SafeMethods = Manifest.WildcardContainer.Create(), + Abi = new Manifest.ContractAbi() + { + Methods = new Manifest.ContractMethodDescriptor[0], + Events = new Manifest.ContractEventDescriptor[0], + Hash = new byte[] { 0x01, 0x02, 0x03 }.ToScriptHash() + }, } }; _engine.Snapshot.Contracts.GetOrAdd(contract.ScriptHash, () => contract); @@ -342,50 +353,61 @@ public void GetContract() // Not found _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(UInt160.Zero.ToArray()), new ByteString(new byte[0])); + var result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(UInt160.Zero.ToArray()), new ByteString(new byte[20])); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Null)); + // Found + Manifest + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Utility.StrictUTF8.GetBytes("Manifest"))); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(ByteString)); + Assert.AreEqual(contract.Manifest.ToString(), item.GetString()); + // Found + HasStorage _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Encoding.UTF8.GetBytes("HasStorage"))); + result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Utility.StrictUTF8.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.ToBoolean()); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.AreEqual(contract.HasStorage, item.GetBoolean()); // Found + IsPayable _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Encoding.UTF8.GetBytes("IsPayable"))); + result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Utility.StrictUTF8.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.ToBoolean()); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.AreEqual(contract.Payable, item.GetBoolean()); // Found + IsPayable _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Encoding.UTF8.GetBytes("Script"))); + result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Utility.StrictUTF8.GetBytes("Script"))); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(VM.Types.ByteString)); + Assert.IsInstanceOfType(item, typeof(ByteString)); CollectionAssert.AreEqual(contract.Script, item.GetSpan().ToArray()); // Found + Uknown property _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Encoding.UTF8.GetBytes("ASD"))); + result = _engine.ExecuteTestCaseStandard("getContract", new ByteString(contract.ScriptHash.ToArray()), new ByteString(Utility.StrictUTF8.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 index b6c79484b..abbb82f1e 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs @@ -47,8 +47,9 @@ public void Test_CreateCallDestroy() Assert.IsInstanceOfType(item, typeof(Array)); var itemArray = item as Array; Assert.AreEqual(script.finalNEF, itemArray[0]); // Script - Assert.AreEqual(false, itemArray[1]); // HasStorage - Assert.AreEqual(false, itemArray[2]); // Payable + Assert.AreEqual(manifest.ToString(), itemArray[1].GetString()); // Manifest + Assert.AreEqual(false, itemArray[2]); // HasStorage + Assert.AreEqual(false, itemArray[3]); // Payable // Call @@ -59,7 +60,7 @@ public void Test_CreateCallDestroy() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(123, item.GetBigInteger()); + Assert.AreEqual(123, item.GetInteger()); // Destroy @@ -109,8 +110,9 @@ public void Test_Update() Assert.IsInstanceOfType(item, typeof(Array)); var itemArray = item as Array; Assert.AreEqual(script.finalNEF, itemArray[0]); // Script - Assert.AreEqual(false, itemArray[1]); // HasStorage - Assert.AreEqual(false, itemArray[2]); // Payable + Assert.AreEqual(manifest.ToString(), itemArray[1].GetString()); // Manifest + Assert.AreEqual(false, itemArray[2]); // HasStorage + Assert.AreEqual(false, itemArray[3]); // Payable // Call & Update @@ -126,7 +128,7 @@ public void Test_Update() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(123, item.GetBigInteger()); + Assert.AreEqual(123, item.GetInteger()); // Call Again @@ -137,7 +139,7 @@ public void Test_Update() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(124, item.GetBigInteger()); + Assert.AreEqual(124, item.GetInteger()); // Check again for failures diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/CryptoTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/CryptoTest.cs index 5252035d3..99d23c0c2 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/CryptoTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/CryptoTest.cs @@ -24,7 +24,7 @@ public void Init() { Attributes = new TransactionAttribute[0], Script = new byte[0], - Sender = UInt160.Zero, + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, Witnesses = new Witness[0], NetworkFee = 1, Nonce = 2, @@ -49,15 +49,14 @@ public static KeyPair GenerateKey(int privateKeyLength) [TestMethod] public void Test_SHA256() { - var data = _engine.ScriptContainer.GetHashData(); _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("SHA256", data); + var result = _engine.ExecuteTestCaseStandard("SHA256", "asd"); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(ByteString)); - Assert.AreEqual("293ba9cd0c05e23da15e39d29bcb8edfa5b2eeb29163a325c3229e81feed3d11", item.GetSpan().ToArray().ToHexString()); + Assert.AreEqual("688787d8ff144c502c7f5cffaafe2cc588d86079f9de88304c26b0cb99ce91c6", item.GetSpan().ToArray().ToHexString()); } [TestMethod] @@ -118,7 +117,7 @@ public void Test_VerifySignature() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); // True @@ -130,7 +129,7 @@ public void Test_VerifySignature() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); } [TestMethod] @@ -150,7 +149,7 @@ public void Test_VerifySignatures() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); // True @@ -163,7 +162,7 @@ public void Test_VerifySignatures() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); } [TestMethod] @@ -184,7 +183,7 @@ public void Test_VerifySignaturesWithMessage() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); // True @@ -198,7 +197,7 @@ public void Test_VerifySignaturesWithMessage() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); } [TestMethod] @@ -218,7 +217,7 @@ public void Test_VerifySignatureWithMessage() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsFalse(item.ToBoolean()); + Assert.IsFalse(item.GetBoolean()); // True @@ -231,7 +230,7 @@ public void Test_VerifySignatureWithMessage() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Boolean)); - Assert.IsTrue(item.ToBoolean()); + 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 index 568e2ccb7..85ba41092 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/EnumeratorTest.cs @@ -19,25 +19,38 @@ public void Init() } [TestMethod] - public void TestNext() + public void TestNextIntArray() { _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("testNext", new Array(new StackItem[] { 1, 2, 3 })); + var result = _engine.ExecuteTestCaseStandard("testNextIntArray", 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()); + Assert.AreEqual(6, item.GetInteger()); } [TestMethod] - public void TestConcat() + public void TestNextByteArray() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testNextByteArray", new byte[] { 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.GetInteger()); + } + + [TestMethod] + public void TestConcatIntArray() { // A and B _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("testConcat", + var result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(new StackItem[] { 1, 2, 3 }), new Array(new StackItem[] { 4, 5, 6 }) ); @@ -46,12 +59,12 @@ public void TestConcat() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(21, item.GetBigInteger()); + Assert.AreEqual(21, item.GetInteger()); // Only A _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcat", + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(new StackItem[] { 1, 2, 3 }), new Array() ); @@ -60,12 +73,12 @@ public void TestConcat() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(6, item.GetBigInteger()); + Assert.AreEqual(6, item.GetInteger()); // Only B _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcat", + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(), new Array(new StackItem[] { 4, 5, 6 }) ); @@ -74,12 +87,12 @@ public void TestConcat() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(15, item.GetBigInteger()); + Assert.AreEqual(15, item.GetInteger()); // Empty _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcat", + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(), new Array() ); @@ -88,7 +101,67 @@ public void TestConcat() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetByteLength()); + Assert.AreEqual(0, item.GetSpan().Length); + } + + [TestMethod] + public void TestConcatByteArray() + { + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testConcatByteArray", + new byte[] { 1, 2, 3 }, + new byte[] { 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.GetInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", + new byte[] { 1, 2, 3 }, + new byte[] { } + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(6, item.GetInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", + new byte[] { }, + new byte[] { 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.GetInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", + new byte[] { }, + new byte[] { } + ); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0, item.GetSpan().Length); } [TestMethod] @@ -99,15 +172,15 @@ public void TestIntEnumerator() enumerator.Next(); var v1 = enumerator.Value(); - Assert.AreEqual(4, v1.GetBigInteger()); + Assert.AreEqual(4, v1.GetInteger()); enumerator.Next(); var v2 = enumerator.Value(); - Assert.AreEqual(6, v2.GetBigInteger()); + Assert.AreEqual(6, v2.GetInteger()); enumerator.Next(); var v3 = enumerator.Value(); - Assert.AreEqual(8, v3.GetBigInteger()); + Assert.AreEqual(8, v3.GetInteger()); } } } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs index 7462187d0..c9ecbf41e 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/IteratorTest.cs @@ -18,20 +18,33 @@ public void Init() } [TestMethod] - public void TestNextArray() + public void TestNextIntArray() { _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("testNextArray", new Array(new StackItem[] { 1, 2, 3 })); + var result = _engine.ExecuteTestCaseStandard("testNextIntArray", 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()); + Assert.AreEqual(6, item.GetInteger()); } [TestMethod] - public void TestConcatArray() + public void TestNextByteArray() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testNextByteArray", new byte[] { 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.GetInteger()); + } + + [TestMethod] + public void TestConcatIntArray() { var a = new Array(new StackItem[] { 1, 2, 3 }); var b = new Array(new StackItem[] { 4, 5, 6 }); @@ -39,46 +52,97 @@ public void TestConcatArray() // A and B _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("testConcatArray", a, b); + var result = _engine.ExecuteTestCaseStandard("testConcatIntArray", 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.GetInteger()); + + // Only A + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", 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.GetInteger()); + + // Only B + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", 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.GetInteger()); + + // Empty + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("testConcatIntArray", new Array(), new Array()); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0, item.GetSpan().Length); + } + + [TestMethod] + public void TestConcatByteArray() + { + var a = new byte[] { 1, 2, 3 }; + var b = new byte[] { 4, 5, 6 }; + + // A and B + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("testConcatByteArray", 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()); + Assert.AreEqual(21, item.GetInteger()); // Only A _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcatArray", a, new Array()); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", a, new byte[] { }); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(6, item.GetBigInteger()); + Assert.AreEqual(6, item.GetInteger()); // Only B _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcatArray", new Array(), b); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", new byte[] { }, 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()); + Assert.AreEqual(15, item.GetInteger()); // Empty _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("testConcatArray", new Array(), new Array()); + result = _engine.ExecuteTestCaseStandard("testConcatByteArray", new byte[] { }, new byte[] { }); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetByteLength()); + Assert.AreEqual(0, item.GetSpan().Length); } [TestMethod] @@ -105,7 +169,7 @@ public void TestConcatMap() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(36, item.GetBigInteger()); + Assert.AreEqual(36, item.GetInteger()); // Only A @@ -116,7 +180,7 @@ public void TestConcatMap() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(10, item.GetBigInteger()); + Assert.AreEqual(10, item.GetInteger()); // Only B @@ -127,7 +191,7 @@ public void TestConcatMap() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(26, item.GetBigInteger()); + Assert.AreEqual(26, item.GetInteger()); // Empty @@ -138,7 +202,7 @@ public void TestConcatMap() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetByteLength()); + Assert.AreEqual(0, item.GetSpan().Length); } [TestMethod] @@ -165,7 +229,7 @@ public void TestConcatKeys() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(16, item.GetBigInteger()); + Assert.AreEqual(16, item.GetInteger()); // Only A @@ -176,7 +240,7 @@ public void TestConcatKeys() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(4, item.GetBigInteger()); + Assert.AreEqual(4, item.GetInteger()); // Only B @@ -187,7 +251,7 @@ public void TestConcatKeys() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(12, item.GetBigInteger()); + Assert.AreEqual(12, item.GetInteger()); // Empty @@ -198,7 +262,7 @@ public void TestConcatKeys() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetByteLength()); + Assert.AreEqual(0, item.GetSpan().Length); } [TestMethod] @@ -225,7 +289,7 @@ public void TestConcatValues() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(20, item.GetBigInteger()); + Assert.AreEqual(20, item.GetInteger()); // Only A @@ -236,7 +300,7 @@ public void TestConcatValues() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(6, item.GetBigInteger()); + Assert.AreEqual(6, item.GetInteger()); // Only B @@ -247,7 +311,7 @@ public void TestConcatValues() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(14, item.GetBigInteger()); + Assert.AreEqual(14, item.GetInteger()); // Empty @@ -258,7 +322,7 @@ public void TestConcatValues() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetByteLength()); + Assert.AreEqual(0, item.GetSpan().Length); } } } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/JsonTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/JsonTest.cs index 0855296e4..cbac16fd5 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/JsonTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/JsonTest.cs @@ -45,7 +45,7 @@ public void Test_SerializeDeserialize() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(ByteString)); - Assert.AreEqual("[null,true,\"YXNk\"]", item.GetString()); + Assert.AreEqual("[null,true,\"asd\"]", item.GetString()); // Deserialize @@ -61,7 +61,7 @@ public void Test_SerializeDeserialize() Assert.IsInstanceOfType(entry, typeof(Null)); entry = ((Array)item)[1]; Assert.IsInstanceOfType(entry, typeof(Boolean)); - Assert.AreEqual(true, entry.ToBoolean()); + Assert.AreEqual(true, entry.GetBoolean()); entry = ((Array)item)[2]; Assert.IsInstanceOfType(entry, typeof(ByteString)); 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 index 3af0bb889..f88a16980 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/NativeTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/NativeTest.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.Cryptography.ECC; using Neo.VM; using Neo.VM.Types; @@ -9,15 +10,13 @@ namespace Neo.SmartContract.Framework.UnitTests.Services.Neo public class NativeTest { private TestEngine _engine; + private readonly byte[] pubKey = NeonTestTool.HexString2Bytes("03ea01cb94bdaf0cd1c01b159d474f9604f4af35a3e2196f6bdfdb33b2aa4961fa"); [TestInitialize] public void Init() { - _engine = new TestEngine(); - // Deploy native contracts - - ((TestSnapshot)_engine.Snapshot).SetPersistingBlock(new Network.P2P.Payloads.Block() + var block = new Network.P2P.Payloads.Block() { Index = 0, ConsensusData = new Network.P2P.Payloads.ConsensusData(), @@ -25,12 +24,15 @@ public void Init() Witness = new Network.P2P.Payloads.Witness() { InvocationScript = new byte[0], - VerificationScript = new byte[0] + VerificationScript = Contract.CreateSignatureRedeemScript(ECPoint.FromBytes(pubKey, ECCurve.Secp256k1)) }, NextConsensus = UInt160.Zero, MerkleRoot = UInt256.Zero, PrevHash = UInt256.Zero - }); + }; + + _engine = new TestEngine(TriggerType.Application, block); + ((TestSnapshot)_engine.Snapshot).SetPersistingBlock(block); using (var script = new ScriptBuilder()) { @@ -53,7 +55,7 @@ public void Test_NEO() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetBigInteger()); + Assert.AreEqual(0, item.GetInteger()); _engine.Reset(); result = _engine.ExecuteTestCaseStandard("NEO_Name"); @@ -63,6 +65,54 @@ public void Test_NEO() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(ByteString)); Assert.AreEqual("NEO", item.GetString()); + + _engine.Reset(); + var account = new byte[] { 0xf6, 0x64, 0x43, 0x49, 0x8d, 0x38, 0x78, 0xd3, 0x2b, 0x99, 0x4e, 0x4e, 0x12, 0x83, 0xc6, 0x93, 0x44, 0x21, 0xda, 0xfe }; + result = _engine.ExecuteTestCaseStandard("NEO_BalanceOf", account); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(0, item.GetInteger()); + + // Before RegisterCandidate + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("NEO_GetCandidates"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Array)); + Assert.AreEqual(0, ((Array)item).Count); + + // RegisterCandidate + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("NEO_RegisterCandidate", pubKey); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Boolean)); + Assert.AreEqual(true, item.GetBoolean()); + + // After RegisterCandidate + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("NEO_GetCandidates"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Array)); + Assert.AreEqual(1, ((Array)item).Count); + var candidate = ((Array)item)[0]; + Assert.IsInstanceOfType(candidate, typeof(Struct)); + var candidatePubKey = ((Struct)candidate)[0]; + var candidateVotes = ((Struct)candidate)[1]; + Assert.IsInstanceOfType(candidatePubKey, typeof(ByteString)); + Assert.AreEqual(true, candidatePubKey.Equals((ByteString)pubKey)); + Assert.IsInstanceOfType(candidateVotes, typeof(Integer)); + Assert.AreEqual(0, candidateVotes.GetInteger()); } [TestMethod] @@ -75,7 +125,7 @@ public void Test_GAS() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(8, item.GetBigInteger()); + Assert.AreEqual(8, item.GetInteger()); _engine.Reset(); result = _engine.ExecuteTestCaseStandard("GAS_Name"); @@ -97,7 +147,25 @@ public void Test_Policy() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(1000L, item.GetBigInteger()); + Assert.AreEqual(1000L, item.GetInteger()); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("policy_GetMaxTransactionsPerBlock"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(512, item.GetInteger()); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("policy_GetBlockedAccounts"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Array)); + Assert.AreEqual(0, ((Array)item).Count); } } } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/PointerTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/PointerTest.cs index 23b3691e2..d0ce1308f 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/PointerTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/PointerTest.cs @@ -43,7 +43,7 @@ public void Test_CreatePointer(bool optimized) item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(123, ((Integer)item).GetBigInteger()); + Assert.AreEqual(123, ((Integer)item).GetInteger()); } [TestMethod] @@ -69,7 +69,7 @@ public void Test_ExecutePointer(bool optimized) var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(123, ((Integer)item).GetBigInteger()); + Assert.AreEqual(123, ((Integer)item).GetInteger()); } [TestMethod] @@ -95,7 +95,7 @@ public void Test_ExecutePointerWithArgs(bool optimized) var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); var wantResult = new BigInteger(new byte[] { 11, 22, 33 }); - Assert.AreEqual(wantResult, ((Integer)item).GetBigInteger()); + Assert.AreEqual(wantResult, ((Integer)item).GetInteger()); } } } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/RuntimeTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/RuntimeTest.cs index 25f9129f6..db71d65f9 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/RuntimeTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/RuntimeTest.cs @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.IO; using System.Text; -using NEOSmartContract = Neo.SmartContract; namespace Neo.SmartContract.Framework.UnitTests.Services.Neo { @@ -83,11 +82,11 @@ public void Test_InvocationCounter() var item = _engine.ResultStack.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x02, item.GetBigInteger()); + Assert.AreEqual(0x02, item.GetInteger()); item = _engine.ResultStack.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x01, item.GetBigInteger()); + Assert.AreEqual(0x01, item.GetInteger()); } [TestMethod] @@ -114,7 +113,7 @@ public void Test_Time() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(1234, item.GetBigInteger()); + Assert.AreEqual(1234, item.GetInteger()); } [TestMethod] @@ -136,7 +135,7 @@ public void Test_Trigger() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual((byte)TriggerType.Application, item.GetBigInteger()); + Assert.AreEqual((byte)TriggerType.Application, item.GetInteger()); } [TestMethod] @@ -147,7 +146,7 @@ public void Test_GasLeft() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(-1, item.GetBigInteger()); + Assert.AreEqual(TestEngine.TestGas - 1200, item.GetInteger()); } [TestMethod] @@ -157,7 +156,7 @@ public void Test_Log() var method = new EventHandler((s, e) => list.Add(e)); ApplicationEngine.Log += method; - var result = _engine.ExecuteTestCaseStandard("log", new ByteString(Encoding.UTF8.GetBytes("LogTest"))); + var result = _engine.ExecuteTestCaseStandard("log", new ByteString(Utility.StrictUTF8.GetBytes("LogTest"))); ApplicationEngine.Log -= method; Assert.AreEqual(1, list.Count); @@ -178,7 +177,7 @@ public void Test_CheckWitness() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(VM.Types.Boolean)); - Assert.IsTrue(item.ToBoolean()); + Assert.IsTrue(item.GetBoolean()); // False @@ -190,44 +189,22 @@ public void Test_CheckWitness() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(VM.Types.Boolean)); - Assert.IsFalse(item.ToBoolean()); - } - - [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 ByteString(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()); + Assert.IsFalse(item.GetBoolean()); } [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)) - }); + _engine.ClearNotifications(); + _engine.SendTestNotification(UInt160.Zero, "", new VM.Types.Array(new StackItem[] { new Integer(0x01) })); + _engine.SendTestNotification(UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), "", new VM.Types.Array(new StackItem[] { new Integer(0x02) })); var result = _engine.ExecuteTestCaseStandard("getNotificationsCount", new ByteString(UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").ToArray())); Assert.AreEqual(1, result.Count); var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x01, item.GetBigInteger()); + Assert.AreEqual(0x01, item.GetInteger()); _engine.Reset(); result = _engine.ExecuteTestCaseStandard("getNotificationsCount", StackItem.Null); @@ -235,26 +212,22 @@ public void Test_GetNotificationsCount() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x02, item.GetBigInteger()); + Assert.AreEqual(0x02, item.GetInteger()); } [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)) - }); + _engine.ClearNotifications(); + _engine.SendTestNotification(UInt160.Zero, "", new VM.Types.Array(new StackItem[] { new Integer(0x01) })); + _engine.SendTestNotification(UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), "", new VM.Types.Array(new StackItem[] { new Integer(0x02) })); var result = _engine.ExecuteTestCaseStandard("getNotifications", new ByteString(UInt160.Parse("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").ToArray())); Assert.AreEqual(1, result.Count); var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x02, item.GetBigInteger()); + Assert.AreEqual(0x02, item.GetInteger()); _engine.Reset(); result = _engine.ExecuteTestCaseStandard("getAllNotifications"); @@ -262,7 +235,7 @@ public void Test_GetNotifications() item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0x03, item.GetBigInteger()); + Assert.AreEqual(0x03, item.GetInteger()); } } } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StaticStorageMapTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StaticStorageMapTest.cs new file mode 100644 index 000000000..b98b912d1 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StaticStorageMapTest.cs @@ -0,0 +1,72 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.Ledger; +using Neo.VM; +using System.Linq; + +namespace Neo.SmartContract.Framework.UnitTests.Services.Neo +{ + [TestClass] + public class StaticStorageMapTest + { + private TestEngine _engine; + + [TestInitialize] + public void Init() + { + var _ = TestBlockchain.TheNeoSystem; + var snapshot = Blockchain.Singleton.GetSnapshot(); + + _engine = new TestEngine(snapshot: snapshot.Clone()); + _engine.AddEntryScript("./TestClasses/Contract_StaticStorageMap.cs"); + Assert.AreEqual(ContractFeatures.HasStorage, _engine.ScriptEntry.converterIL.outModule.attributes + .Where(u => u.AttributeType.Name == "FeaturesAttribute") + .Select(u => (ContractFeatures)u.ConstructorArguments.FirstOrDefault().Value) + .FirstOrDefault()); + + _engine.Snapshot.Contracts.Add(_engine.EntryScriptHash, new ContractState() + { + Script = _engine.EntryContext.Script, + Manifest = new Manifest.ContractManifest() + { + Features = Manifest.ContractFeatures.HasStorage + } + }); + } + + [TestMethod] + public void Test_Storage() + { + _engine.Reset(); + _engine.ExecuteTestCaseStandard("put2", "a"); + Assert.AreEqual(VMState.HALT, _engine.State); + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("get2", "a"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(3, result.Pop()); + } + + [TestMethod] + public void Test_StaticStorageMap() + { + _engine.Reset(); + _engine.ExecuteTestCaseStandard("put", "a"); + Assert.AreEqual(VMState.HALT, _engine.State); + + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("get", "a"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Pop()); + + _engine.Reset(); + _engine.ExecuteTestCaseStandard("putReadonly", "a"); + Assert.AreEqual(VMState.HALT, _engine.State); + + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("getReadonly", "a"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(2, result.Pop()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StorageTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StorageTest.cs index 41b439886..b5fa276b0 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StorageTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/StorageTest.cs @@ -18,7 +18,7 @@ private void Put(TestEngine testengine, string method, byte[] prefix, byte[] key var rItem = result.Pop(); Assert.IsInstanceOfType(rItem, typeof(Integer)); - Assert.AreEqual(1, ((Integer)rItem).ToBigInteger()); + Assert.AreEqual(1, ((Integer)rItem).GetInteger()); Assert.AreEqual(1, testengine.Snapshot.Storages.GetChangeSet() .Count(a => @@ -68,7 +68,7 @@ public void Init() testengine = new TestEngine(snapshot: snapshot.Clone()); testengine.AddEntryScript("./TestClasses/Contract_Storage.cs"); Assert.AreEqual(ContractFeatures.HasStorage, testengine.ScriptEntry.converterIL.outModule.attributes - .Where(u => u.AttributeType.Name == "FeaturesAttribute") + .Where(u => u.AttributeType.FullName == "Neo.SmartContract.Framework.FeaturesAttribute") .Select(u => (ContractFeatures)u.ConstructorArguments.FirstOrDefault().Value) .FirstOrDefault()); diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/System/BinaryTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/System/BinaryTest.cs new file mode 100644 index 000000000..82d6e7d4a --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/System/BinaryTest.cs @@ -0,0 +1,84 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.Ledger; +using Neo.SmartContract; +using Neo.SmartContract.Framework.UnitTests; +using Neo.SmartContract.Manifest; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.Compiler.MSIL.SmartContractFramework.Services.System +{ + [TestClass] + public class BinaryTest + { + private TestEngine _engine; + private UInt160 scriptHash; + + [TestInitialize] + public void Init() + { + var _ = TestBlockchain.TheNeoSystem; + var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); + snapshot.BlockHashIndex.Get().Index = 1234; + + _engine = new TestEngine(TriggerType.Application, snapshot: snapshot); + _engine.AddEntryScript("./TestClasses/Contract_Binary.cs"); + scriptHash = _engine.ScriptEntry.finalNEF.ToScriptHash(); + + snapshot.Contracts.Add(scriptHash, new ContractState() + { + Script = _engine.ScriptEntry.finalNEF, + Manifest = ContractManifest.Parse(_engine.ScriptEntry.finalManifest) + }); + } + + [TestMethod] + public void base64DecodeTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("base64Decode", "dGVzdA=="); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.AreEqual("test", item.GetString()); + } + + [TestMethod] + public void base64EncodeTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("base64Encode", "test"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.AreEqual("dGVzdA==", item.GetString()); + } + + [TestMethod] + public void base58DecodeTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("base58Decode", "3yZe7d"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.AreEqual("test", item.GetString()); + } + + [TestMethod] + public void base58EncodeTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("base58Encode", "test"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.AreEqual("3yZe7d", item.GetString()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/System/CallbackTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/System/CallbackTest.cs new file mode 100644 index 000000000..5f46a605a --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/System/CallbackTest.cs @@ -0,0 +1,111 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.UnitTests.Utils; +using Neo.IO; +using Neo.Ledger; +using Neo.SmartContract; +using Neo.SmartContract.Framework.Services.System; +using Neo.SmartContract.Framework.UnitTests; +using Neo.SmartContract.Manifest; +using Neo.VM; +using Neo.VM.Types; +using System.Linq; + +namespace Neo.Compiler.MSIL.SmartContractFramework.Services.System +{ + [TestClass] + public class CallbackTest + { + private TestEngine _engine; + private UInt160 scriptHash; + + [TestInitialize] + public void Init() + { + var _ = TestBlockchain.TheNeoSystem; + var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); + snapshot.BlockHashIndex.Get().Index = 1234; + + _engine = new TestEngine(TriggerType.Application, snapshot: snapshot); + _engine.AddEntryScript("./TestClasses/Contract_Callback.cs"); + scriptHash = _engine.ScriptEntry.finalNEF.ToScriptHash(); + + snapshot.Contracts.Add(scriptHash, new ContractState() + { + Script = _engine.ScriptEntry.finalNEF, + Manifest = ContractManifest.Parse(_engine.ScriptEntry.finalManifest) + }); + } + + [TestMethod] + public void createFromMethodTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("createFromMethod", scriptHash.ToArray(), "test"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(InteropInterface)); + } + + [TestMethod] + public void createAndCallFromMethodTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("createAndCallFromMethod", scriptHash.ToArray(), "test"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.AreEqual(123, item.GetInteger()); + } + + [TestMethod] + public void createFromSyscallTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("createFromSyscall", (uint)SyscallCallback.System_Blockchain_GetHeight); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(InteropInterface)); + } + + [TestMethod] + public void createAndCallFromSyscallTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("createAndCallFromSyscall", (uint)SyscallCallback.System_Blockchain_GetHeight); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.AreEqual(1234, item.GetInteger()); + } + + [TestMethod] + public void createTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("create"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(InteropInterface)); + } + + [TestMethod] + public void createAndCallTest() + { + _engine.Reset(); + var result = _engine.ExecuteTestCaseStandard("createAndCall"); + Assert.AreEqual(VMState.HALT, _engine.State); + Assert.AreEqual(1, result.Count); + + var item = result.Pop(); + Assert.AreEqual(123, item.GetInteger()); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/SupportedStandardsTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/SupportedStandardsTest.cs new file mode 100644 index 000000000..17aa4f57f --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/SupportedStandardsTest.cs @@ -0,0 +1,28 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler; +using Neo.IO.Json; +using System.IO; + +namespace Neo.SmartContract.Framework.UnitTests +{ + [TestClass] + public class SupportedStandardsTest + { + [TestMethod] + public void TestAttribute() + { + string path = Directory.GetCurrentDirectory(); + var option = new Program.Options() + { + File = path + "/TestClasses/Contract_SupportedStandards.cs" + }; + Program.Compile(option); + + //Compile changes the path, reseting so that other UT won't break + Directory.SetCurrentDirectory(path); + + var jobj = JObject.Parse(File.ReadAllText(path + "/TestClasses/Contract_SupportedStandards.manifest.json")); + Assert.AreEqual(jobj["supportedstandards"].ToString(), @"[""NEP10"",""NEP5""]"); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/SyscallCallbackTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/SyscallCallbackTest.cs new file mode 100644 index 000000000..cb292eb24 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/SyscallCallbackTest.cs @@ -0,0 +1,48 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Framework.Services.System; +using System; +using System.Collections.Generic; + +namespace Neo.SmartContract.Framework.UnitTests +{ + [TestClass] + public class SyscallCallbackTest + { + [TestMethod] + public void TestAllSyscallCallbacks() + { + // Current allowed syscalls + + var current = new Dictionary(); + + foreach (var syscall in ApplicationEngine.Services) + { + if (!syscall.Value.AllowCallback) continue; + + current.Add(syscall.Value.Name.Replace(".", "_"), syscall.Value.Hash); + } + + // Check equals + + foreach (var en in Enum.GetValues(typeof(SyscallCallback))) + { + if (!current.TryGetValue(en.ToString(), out var val)) + { + Assert.Fail($"`{en}` Syscall is not defined in SyscallCallback"); + } + + current.Remove(en.ToString()); + + if (val != (uint)en) + { + Assert.Fail($"`{en}` Syscall has a different hash, found {((uint)en):x2}, expected: {val:x2}"); + } + } + + if (current.Count > 0) + { + Assert.Fail($"Not implemented syscalls: {string.Join("\n-", current.Keys)}"); + } + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/SyscallTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/SyscallTest.cs index 61413ab45..83b85690e 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/SyscallTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/SyscallTest.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Mono.Cecil; -using System; using System.Collections.Generic; using System.IO; @@ -19,7 +18,7 @@ public void TestAllSyscalls() using (var stream = File.OpenRead(typeof(SmartContract).Assembly.Location)) { var expectedType = typeof(SyscallAttribute).FullName; - var module = Mono.Cecil.ModuleDefinition.ReadModule(stream); + var module = ModuleDefinition.ReadModule(stream); foreach (var type in module.Types) { @@ -33,15 +32,16 @@ public void TestAllSyscalls() foreach (var syscall in ApplicationEngine.Services) { - if (syscall.Name == "Neo.Native.Deploy") continue; - if (syscall.Name == "Neo.Native.Tokens.NEO") continue; - if (syscall.Name == "Neo.Native.Tokens.GAS") continue; - if (syscall.Name == "Neo.Native.Policy") continue; - if (syscall.Name == "Neo.Native.Call") continue; + if (syscall.Value.Name == "Neo.Native.Deploy") continue; + if (syscall.Value.Name == "Neo.Native.Tokens.NEO") continue; + if (syscall.Value.Name == "Neo.Native.Tokens.GAS") continue; + if (syscall.Value.Name == "Neo.Native.Policy") continue; + if (syscall.Value.Name == "Neo.Native.Call") continue; + if (syscall.Value.Name == "System.Runtime.Notify") continue; - if (list.Remove(syscall.Name)) continue; + if (list.Remove(syscall.Value.Name)) continue; - notFound.Add(syscall.Name); + notFound.Add(syscall.Value.Name); } if (list.Count > 0) diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Binary.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Binary.cs new file mode 100644 index 000000000..1e8ff6eda --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Binary.cs @@ -0,0 +1,29 @@ +using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.System; +using System; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Binary : SmartContract.Framework.SmartContract + { + public static byte[] base64Decode(string input) + { + return Binary.Base64Decode(input); + } + + public static string base64Encode(byte[] input) + { + return Binary.Base64Encode(input); + } + + public static byte[] base58Decode(string input) + { + return Binary.Base58Decode(input); + } + + public static string base58Encode(byte[] input) + { + return Binary.Base58Encode(input); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Blockchain.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Blockchain.cs index f047f43b2..57f3ac285 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Blockchain.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Blockchain.cs @@ -100,6 +100,7 @@ private static object GetContractInfo(Contract contract, string whatReturn) return null; } + if (whatReturn == "Manifest") return contract.Manifest; if (whatReturn == "HasStorage") return contract.HasStorage; if (whatReturn == "IsPayable") return contract.IsPayable; if (whatReturn == "Script") return contract.Script; diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Callback.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Callback.cs new file mode 100644 index 000000000..be360606b --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Callback.cs @@ -0,0 +1,52 @@ +using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.System; +using System; +using System.Collections.Specialized; +using System.ComponentModel; + +namespace Neo.Compiler.MSIL.TestClasses +{ + public class Contract_Callback : SmartContract.Framework.SmartContract + { + public static int test() { return 123; } + + public static object test2(object args) + { + return 123; + } + + public static object createFromMethod(byte[] hash, string method) + { + return Callback.CreateFromMethod(hash, method); + } + + public static object createAndCallFromMethod(byte[] hash, string method) + { + return Callback.CreateFromMethod(hash, method).Invoke(new object[0]); + } + + public static object create() + { + var action = new Func(test2); + return Callback.Create(action); + } + + public static object createAndCall() + { + var action = new Func(test2); + var callback = Callback.Create(action); + + return callback.Invoke(new object[] { null }); + } + + public static object createFromSyscall(uint method) + { + return Callback.CreateFromSyscall((SyscallCallback)method); + } + + public static object createAndCallFromSyscall(uint method) + { + return Callback.CreateFromSyscall((SyscallCallback)method).Invoke(new object[0]); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs index 9fb156c72..fafd6befd 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Enumerator.cs @@ -4,7 +4,7 @@ namespace Neo.Compiler.MSIL.TestClasses { public class Contract_Enumerator : SmartContract.Framework.SmartContract { - public static int TestNext(byte[] a) + public static int TestNextByteArray(byte[] a) { int sum = 0; var enumerator = Enumerator.Create(a); @@ -17,7 +17,20 @@ public static int TestNext(byte[] a) return sum; } - public static int TestConcat(byte[] a, byte[] b) + public static int TestNextIntArray(int[] a) + { + int sum = 0; + var enumerator = Enumerator.Create(a); + + while (enumerator.Next()) + { + sum += enumerator.Value; + } + + return sum; + } + + public static int TestConcatByteArray(byte[] a, byte[] b) { int sum = 0; var enumeratorA = Enumerator.Create(a); @@ -32,6 +45,21 @@ public static int TestConcat(byte[] a, byte[] b) return sum; } + public static int TestConcatIntArray(int[] a, int[] 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; + } + public static Enumerator TestIntEnumerator() { var enumerator = Enumerator.Create(new int[3] { 4, 6, 8 }); diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Helper.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Helper.cs index 5f0be22ef..03970dfc7 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Helper.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Helper.cs @@ -1,4 +1,5 @@ using Neo.SmartContract.Framework; +using System.Numerics; namespace Compiler.MSIL.TestClasses { @@ -18,6 +19,11 @@ public static int AssertCall(bool value) return 5; } + public static BigInteger TestToBigInteger(byte[] data) + { + return data.ToBigInteger(); + } + public static void VoidAssertCall(bool value) { Assert(value == true); diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs index 3f38f045e..43b4cb28a 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Iterator.cs @@ -5,7 +5,7 @@ namespace Neo.Compiler.MSIL.TestClasses { public class Contract_Iterator : SmartContract.Framework.SmartContract { - public static int TestNextArray(byte[] a) + public static int TestNextByteArray(byte[] a) { int sum = 0; var iterator = Iterator.Create(a); @@ -18,7 +18,20 @@ public static int TestNextArray(byte[] a) return sum; } - public static int TestConcatArray(byte[] a, byte[] b) + public static int TestNextIntArray(int[] a) + { + int sum = 0; + var iterator = Iterator.Create(a); + + while (iterator.Next()) + { + sum += iterator.Value; + } + + return sum; + } + + public static int TestConcatByteArray(byte[] a, byte[] b) { int sum = 0; var iteratorA = Iterator.Create(a); @@ -33,6 +46,21 @@ public static int TestConcatArray(byte[] a, byte[] b) return sum; } + public static int TestConcatIntArray(int[] a, int[] 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; diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Map.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Map.cs new file mode 100644 index 000000000..2a55f713c --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Map.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.SmartContract.Framework.UnitTests.TestClasses +{ + public class Contract_Map : SmartContract + { + public static object TestByteArray(byte[] key) + { + Map some = new Map(); + some[key.ToByteString()] = "teststring2"; + return Json.Serialize(some); + } + + public static string TestByteArray2() + { + Map some = new Map(); + string key = new byte[] { 0x01, 0x01 }.ToByteString(); + some[key] = Json.Serialize(""); + return Json.Serialize(some); + } + + public static string TestUnicode(string key) + { + Map some = new Map(); + some[key] = "129840test10022939"; + return Json.Serialize(some); + } + + public static string TestUnicodeValue(string value) + { + Map some = new Map(); + some["ab"] = value; + return Json.Serialize(some); + } + + public static string TestUnicodeKeyValue(string key, string value) + { + Map some = new Map(); + some[key] = value; + return Json.Serialize(some); + } + + public static string TestInt(int key) + { + Map some = new Map(); + some[key] = "string"; + return Json.Serialize(some); + } + + public static string TestBool(bool key) + { + Map some = new Map(); + some[key] = "testbool"; + return Json.Serialize(some); + } + + public static object TestDeserialize(string key) + { + Map some = new Map(); + some[key] = "testdeserialize"; + string sea = Json.Serialize(some); + return Json.Deserialize(sea); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_MapException.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_MapException.cs new file mode 100644 index 000000000..733c51f06 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_MapException.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Neo.SmartContract.Framework.Services.Neo; + +namespace Neo.SmartContract.Framework.UnitTests.TestClasses +{ + public class Contract_MapException : SmartContract + { + public static string TestByteArrayMap() + { + Map some = new Map(); + some[new byte[] { 0x01, 0x01 }] = Json.Serialize(""); + return Json.Serialize(some); + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Native.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Native.cs index a3883513b..4608f9681 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Native.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Native.cs @@ -1,6 +1,7 @@ using Neo.SmartContract.Framework.Services.Neo; using System.ComponentModel; using System.Numerics; +using System; namespace Neo.Compiler.MSIL.TestClasses { @@ -9,30 +10,74 @@ public class Contract_Native : SmartContract.Framework.SmartContract [DisplayName("NEO_Decimals")] public static int NEO_Decimals() { - return (int)Native.NEO("decimals", new object[0]); + return (int)NEO.Decimals(); } [DisplayName("NEO_Name")] public static string NEO_Name() { - return (string)Native.NEO("name", new object[0]); + return NEO.Name(); + } + + [DisplayName("NEO_BalanceOf")] + public static BigInteger NEO_BalanceOf(byte[] account) + { + return NEO.BalanceOf(account); + } + + [DisplayName("NEO_GetValidators")] + public static string[] NEO_GetValidators() + { + return NEO.GetValidators(); + } + + [DisplayName("NEO_RegisterCandidate")] + public static bool NEO_RegisterCandidate(byte[] pubkey) + { + return NEO.RegisterCandidate(pubkey); + } + + [DisplayName("NEO_GetCandidates")] + public static (string, BigInteger)[] NEO_GetCandidates() + { + return NEO.GetCandidates(); } [DisplayName("GAS_Decimals")] public static int GAS_Decimals() { - return (int)Native.GAS("decimals", new object[0]); + return (int)GAS.Decimals(); } [DisplayName("GAS_Name")] public static string GAS_Name() { - return (string)Native.GAS("name", new object[0]); + return GAS.Name(); } public static BigInteger Policy_GetFeePerByte() { - return (BigInteger)Native.Policy("getFeePerByte", new object[0]); + return Policy.GetFeePerByte(); + } + + public static bool Policy_SetMaxTransactionsPerBlock(uint value) + { + return Policy.SetMaxTransactionsPerBlock(value); + } + + public static uint Policy_GetMaxTransactionsPerBlock() + { + return Policy.GetMaxTransactionsPerBlock(); + } + + public static bool Policy_BlockAccount(byte[] account) + { + return Policy.BlockAccount(account); + } + + public static object[] Policy_GetBlockedAccounts() + { + return Policy.GetBlockedAccounts(); } } } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Pointers.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Pointers.cs index b06aae429..de2d147a1 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Pointers.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Pointers.cs @@ -7,7 +7,7 @@ namespace Neo.Compiler.MSIL.TestClasses { public class Contract_Pointers : SmartContract.Framework.SmartContract { - public static Func CreateFuncPointer() + public static object CreateFuncPointer() { return new Func(MyMethod); } @@ -17,27 +17,27 @@ public static int MyMethod() return 123; } - public static int CallFuncPointer() - { - var pointer = CreateFuncPointer(); - return pointer.Invoke(); - } - - public static Func CreateFuncPointerWithArg() + public static int CallFuncPointer() { - return new Func(MyMethodWithArg); - } - - public static BigInteger MyMethodWithArg(byte[] num) - { - return num.ToBigInteger(); - } - - public static BigInteger CallFuncPointerWithArg() - { - var pointer = CreateFuncPointerWithArg(); - - return pointer.Invoke(new byte[] { 11, 22, 33 }); - } + var pointer = new Func(MyMethod); + return pointer.Invoke(); + } + + public static object CreateFuncPointerWithArg() + { + return new Func(MyMethodWithArg); + } + + public static BigInteger MyMethodWithArg(byte[] num) + { + return num.ToBigInteger(); + } + + public static BigInteger CallFuncPointerWithArg() + { + var pointer = new Func(MyMethodWithArg); + + return pointer.Invoke(new byte[] { 11, 22, 33 }); + } } } diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Runtime.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Runtime.cs index 0a8627228..8cb1986a0 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Runtime.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_Runtime.cs @@ -34,11 +34,6 @@ 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); @@ -58,7 +53,7 @@ public static int GetAllNotifications() for (int x = 0; x < notifications.Length; x++) { var notify = notifications[x]; - sum += (int)notify.State; + sum += (int)notify.State[0]; } return sum; @@ -80,7 +75,7 @@ public static int GetNotifications(byte[] hash) if (notify.ScriptHash[y] != hash[y]) return int.MinValue; } - sum += (int)notify.State; + sum += (int)notify.State[0]; } return sum; diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_StaticStorageMap.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_StaticStorageMap.cs new file mode 100644 index 000000000..ed3bc5509 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_StaticStorageMap.cs @@ -0,0 +1,45 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; +using System.Numerics; + +namespace Neo.Compiler.MSIL.TestClasses +{ + [Features(ContractFeatures.HasStorage)] + class Contract_StaticStorageMap : SmartContract.Framework.SmartContract + { + private static StorageMap Data = Storage.CurrentContext.CreateMap("data"); + private static readonly StorageMap ReadonlyData = Storage.CurrentContext.CreateMap("readonlydata"); + + public static void Put(string message) + { + Data.Put(message, 1); + } + + public static BigInteger Get(string msg) + { + return Data.Get(msg)?.ToBigInteger() ?? 0; + } + + public static void PutReadonly(string message) + { + ReadonlyData.Put(message, 2); + } + + public static BigInteger GetReadonly(string msg) + { + return ReadonlyData.Get(msg)?.ToBigInteger() ?? 0; + } + + public static void Put2(string message) + { + var Data2 = Storage.CurrentContext.CreateMap("data"); + Data2.Put(message, 3); + } + + public static BigInteger Get2(string msg) + { + var Data2 = Storage.CurrentContext.CreateMap("data"); + return Data2.Get(msg)?.ToBigInteger() ?? 0; + } + } +} diff --git a/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_SupportedStandards.cs b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_SupportedStandards.cs new file mode 100644 index 000000000..7591a0828 --- /dev/null +++ b/tests/Neo.SmartContract.Framework.UnitTests/TestClasses/Contract_SupportedStandards.cs @@ -0,0 +1,14 @@ +using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework; + +namespace Neo.Compiler.MSIL.TestClasses +{ + [SupportedStandards("NEP10","NEP5")] + public class Contract_SupportedStandards : SmartContract.Framework.SmartContract + { + public static bool AccountIsStandard(byte[] scripthash) + { + return Account.IsStandard(scripthash); + } + } +} diff --git a/tests/Template.NEP5.UnitTests/UnitTest_NEP5.cs b/tests/Template.NEP5.UnitTests/UnitTest_NEP5.cs index a832aa897..8eb6e9b89 100644 --- a/tests/Template.NEP5.UnitTests/UnitTest_NEP5.cs +++ b/tests/Template.NEP5.UnitTests/UnitTest_NEP5.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Compiler.MSIL.UnitTests.Utils; -using Neo.VM; using Neo.VM.Types; using System.Linq; using System.Numerics; @@ -12,8 +11,8 @@ namespace Template.NEP5.UnitTests public class UnitTest_NEP5 { private TestEngine _engine; - private static readonly byte[] _prefixBalance = { 0x01, 0x01 }; - private static readonly byte[] _prefixContract = { 0x02, 0x02 }; + private static readonly byte[] _prefixAsset = Encoding.UTF8.GetBytes("asset"); + private static readonly byte[] _prefixContract = Encoding.UTF8.GetBytes("contract"); [TestInitialize] public void Init() @@ -28,7 +27,9 @@ TestEngine CreateEngine() engine.AddEntryScript(new string[] { "../../../../../templates/Template.NEP5.CSharp/NEP5.cs", - "../../../../../templates/Template.NEP5.CSharp/NEP5.Admin.cs", + "../../../../../templates/Template.NEP5.CSharp/Storage/TotalSupplyStorage.cs", + "../../../../../templates/Template.NEP5.CSharp/Storage/AssetStorage.cs", + "../../../../../templates/Template.NEP5.CSharp/NEP5.Owner.cs", "../../../../../templates/Template.NEP5.CSharp/NEP5.Crowdsale.cs", "../../../../../templates/Template.NEP5.CSharp/NEP5.Helpers.cs", "../../../../../templates/Template.NEP5.CSharp/NEP5.Methods.cs" @@ -67,7 +68,7 @@ public void Test_decimals() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(8, item.GetBigInteger()); + Assert.AreEqual(8, item.GetInteger()); } [TestMethod] @@ -75,7 +76,7 @@ public void Test_totalSupply() { var engine = CreateEngine(); var hash = engine.CurrentScriptHash; - var snapshot = engine.Snapshot as TestSnapshot; + var snapshot = engine.Snapshot; snapshot.Contracts.Add(hash, new Neo.Ledger.ContractState() { @@ -101,7 +102,7 @@ public void Test_totalSupply() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(123, item.GetBigInteger()); + Assert.AreEqual(123, item.GetInteger()); } [TestMethod] @@ -109,7 +110,7 @@ public void Test_totalSupply_empty() { var engine = CreateEngine(); var hash = engine.CurrentScriptHash; - var snapshot = engine.Snapshot as TestSnapshot; + var snapshot = engine.Snapshot; snapshot.Contracts.Add(hash, new Neo.Ledger.ContractState() { @@ -124,7 +125,7 @@ public void Test_totalSupply_empty() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetBigInteger()); + Assert.AreEqual(0, item.GetInteger()); } [TestMethod] @@ -132,7 +133,7 @@ public void Test_balanceOf() { var engine = CreateEngine(); var hash = engine.CurrentScriptHash; - var snapshot = engine.Snapshot as TestSnapshot; + var snapshot = engine.Snapshot; var address = new byte[] { 0xf6, 0x64, 0x43, 0x49, 0x8d, 0x38, 0x78, 0xd3, 0x2b, 0x99, 0x4e, 0x4e, 0x12, 0x83, 0xc6, 0x93, 0x44, 0x21, 0xda, 0xfe }; snapshot.Contracts.Add(hash, new Neo.Ledger.ContractState() @@ -146,7 +147,7 @@ public void Test_balanceOf() snapshot.Storages.Add(new Neo.Ledger.StorageKey() { Id = 0, - Key = _prefixBalance.Concat(address).ToArray() + Key = _prefixAsset.Concat(address).ToArray() }, new Neo.Ledger.StorageItem() { @@ -159,7 +160,7 @@ public void Test_balanceOf() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(321, item.GetBigInteger()); + Assert.AreEqual(321, item.GetInteger()); } [TestMethod] @@ -167,7 +168,7 @@ public void Test_balanceOf_empty() { var engine = CreateEngine(); var hash = engine.CurrentScriptHash; - var snapshot = engine.Snapshot as TestSnapshot; + var snapshot = engine.Snapshot; var address = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13 }; snapshot.Contracts.Add(hash, new Neo.Ledger.ContractState() @@ -183,19 +184,7 @@ public void Test_balanceOf_empty() var item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetBigInteger()); - } - - [TestMethod] - public void Test_supportedStandards() - { - var result = _engine.ExecuteTestCaseStandard("supportedStandards"); - Assert.AreEqual(1, result.Count); - - var item = (Array)result.Pop(); - Assert.IsInstanceOfType(item, typeof(Array)); - Assert.AreEqual("NEP-5", item[0].GetString()); - Assert.AreEqual("NEP-10", item[1].GetString()); + Assert.AreEqual(0, item.GetInteger()); } } }