From bf7db40d0fad93d58f3fea75fa7bdb7e7f61c3bb Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 18 Feb 2019 03:06:37 +0800 Subject: [PATCH 1/3] Correctly handle conversions between JSON objects --- neo/IO/Json/JArray.cs | 6 +++ neo/IO/Json/JBoolean.cs | 14 ++---- neo/IO/Json/JNumber.cs | 64 ++++++++------------------ neo/IO/Json/JObject.cs | 49 ++++---------------- neo/IO/Json/JString.cs | 61 ++++++------------------ neo/Network/RPC/RpcServer.cs | 8 ++-- neo/SmartContract/ContractParameter.cs | 2 +- neo/Wallets/NEP6/NEP6Contract.cs | 2 +- neo/neo.csproj | 1 + 9 files changed, 61 insertions(+), 146 deletions(-) diff --git a/neo/IO/Json/JArray.cs b/neo/IO/Json/JArray.cs index 0fc758a0bf..02911d505f 100644 --- a/neo/IO/Json/JArray.cs +++ b/neo/IO/Json/JArray.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; namespace Neo.IO.Json @@ -52,6 +53,11 @@ public void Add(JObject item) items.Add(item); } + public override string AsString() + { + return string.Join(",", items.Select(p => p?.AsString())); + } + public void Clear() { items.Clear(); diff --git a/neo/IO/Json/JBoolean.cs b/neo/IO/Json/JBoolean.cs index bf941fc860..6cc39ed231 100644 --- a/neo/IO/Json/JBoolean.cs +++ b/neo/IO/Json/JBoolean.cs @@ -17,18 +17,14 @@ public override bool AsBoolean() return Value; } - public override string AsString() + public override double AsNumber() { - return Value.ToString().ToLower(); + return Value ? 1 : 0; } - public override bool CanConvertTo(Type type) + public override string AsString() { - if (type == typeof(bool)) - return true; - if (type == typeof(string)) - return true; - return false; + return Value.ToString().ToLower(); } internal static JBoolean Parse(TextReader reader) @@ -61,7 +57,7 @@ internal static JBoolean Parse(TextReader reader) public override string ToString() { - return Value.ToString().ToLower(); + return AsString(); } } } diff --git a/neo/IO/Json/JNumber.cs b/neo/IO/Json/JNumber.cs index bf9451975a..fdeb495211 100644 --- a/neo/IO/Json/JNumber.cs +++ b/neo/IO/Json/JNumber.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Reflection; using System.Text; namespace Neo.IO.Json @@ -16,34 +15,7 @@ public JNumber(double value = 0) public override bool AsBoolean() { - if (Value == 0) - return false; - return true; - } - - public override T AsEnum(bool ignoreCase = false) - { - Type t = typeof(T); - TypeInfo ti = t.GetTypeInfo(); - if (!ti.IsEnum) - throw new InvalidCastException(); - if (ti.GetEnumUnderlyingType() == typeof(byte)) - return (T)Enum.ToObject(t, (byte)Value); - if (ti.GetEnumUnderlyingType() == typeof(int)) - return (T)Enum.ToObject(t, (int)Value); - if (ti.GetEnumUnderlyingType() == typeof(long)) - return (T)Enum.ToObject(t, (long)Value); - if (ti.GetEnumUnderlyingType() == typeof(sbyte)) - return (T)Enum.ToObject(t, (sbyte)Value); - if (ti.GetEnumUnderlyingType() == typeof(short)) - return (T)Enum.ToObject(t, (short)Value); - if (ti.GetEnumUnderlyingType() == typeof(uint)) - return (T)Enum.ToObject(t, (uint)Value); - if (ti.GetEnumUnderlyingType() == typeof(ulong)) - return (T)Enum.ToObject(t, (ulong)Value); - if (ti.GetEnumUnderlyingType() == typeof(ushort)) - return (T)Enum.ToObject(t, (ushort)Value); - throw new InvalidCastException(); + return Value != 0 && !double.IsNaN(Value); } public override double AsNumber() @@ -53,23 +25,11 @@ public override double AsNumber() public override string AsString() { + if (double.IsPositiveInfinity(Value)) return "Infinity"; + if (double.IsNegativeInfinity(Value)) return "-Infinity"; return Value.ToString(); } - public override bool CanConvertTo(Type type) - { - if (type == typeof(bool)) - return true; - if (type == typeof(double)) - return true; - if (type == typeof(string)) - return true; - TypeInfo ti = type.GetTypeInfo(); - if (ti.IsEnum && Enum.IsDefined(type, Convert.ChangeType(Value, ti.GetEnumUnderlyingType()))) - return true; - return false; - } - internal static JNumber Parse(TextReader reader) { SkipSpace(reader); @@ -92,7 +52,7 @@ internal static JNumber Parse(TextReader reader) public override string ToString() { - return Value.ToString(); + return AsString(); } public DateTime ToTimestamp() @@ -101,5 +61,21 @@ public DateTime ToTimestamp() throw new InvalidCastException(); return ((ulong)Value).ToDateTime(); } + + public override T TryGetEnum(T defaultValue = default, bool ignoreCase = false) + { + Type enumType = typeof(T); + object value; + try + { + value = Convert.ChangeType(Value, enumType.GetEnumUnderlyingType()); + } + catch (OverflowException) + { + return defaultValue; + } + object result = Enum.ToObject(enumType, value); + return Enum.IsDefined(enumType, result) ? (T)result : defaultValue; + } } } diff --git a/neo/IO/Json/JObject.cs b/neo/IO/Json/JObject.cs index 3d7d9df7b0..a477e49902 100644 --- a/neo/IO/Json/JObject.cs +++ b/neo/IO/Json/JObject.cs @@ -27,55 +27,17 @@ public JObject this[string name] public virtual bool AsBoolean() { - throw new InvalidCastException(); - } - - public bool AsBooleanOrDefault(bool value = false) - { - if (!CanConvertTo(typeof(bool))) - return value; - return AsBoolean(); - } - - public virtual T AsEnum(bool ignoreCase = false) - { - throw new InvalidCastException(); - } - - public T AsEnumOrDefault(T value = default(T), bool ignoreCase = false) - { - if (!CanConvertTo(typeof(T))) - return value; - return AsEnum(ignoreCase); + return true; } public virtual double AsNumber() { - throw new InvalidCastException(); - } - - public double AsNumberOrDefault(double value = 0) - { - if (!CanConvertTo(typeof(double))) - return value; - return AsNumber(); + return double.NaN; } public virtual string AsString() { - throw new InvalidCastException(); - } - - public string AsStringOrDefault(string value = null) - { - if (!CanConvertTo(typeof(string))) - return value; - return AsString(); - } - - public virtual bool CanConvertTo(Type type) - { - return false; + return "[object Object]"; } public bool ContainsProperty(string key) @@ -189,6 +151,11 @@ public override string ToString() return sb.ToString(); } + public virtual T TryGetEnum(T defaultValue = default, bool ignoreCase = false) where T : Enum + { + return defaultValue; + } + public static implicit operator JObject(Enum value) { return new JString(value.ToString()); diff --git a/neo/IO/Json/JString.cs b/neo/IO/Json/JString.cs index c9fac5a9a2..f208ea95c5 100644 --- a/neo/IO/Json/JString.cs +++ b/neo/IO/Json/JString.cs @@ -1,7 +1,6 @@ using System; using System.Globalization; using System.IO; -using System.Reflection; using System.Text; using System.Text.Encodings.Web; @@ -18,42 +17,13 @@ public JString(string value) public override bool AsBoolean() { - switch (Value.ToLower()) - { - case "0": - case "f": - case "false": - case "n": - case "no": - case "off": - return false; - default: - return true; - } - } - - public override T AsEnum(bool ignoreCase = false) - { - try - { - return (T)Enum.Parse(typeof(T), Value, ignoreCase); - } - catch - { - throw new InvalidCastException(); - } + return !string.IsNullOrEmpty(Value); } public override double AsNumber() { - try - { - return double.Parse(Value); - } - catch - { - throw new InvalidCastException(); - } + if (string.IsNullOrEmpty(Value)) return 0; + return double.TryParse(Value, out double result) ? result : double.NaN; } public override string AsString() @@ -61,19 +31,6 @@ public override string AsString() return Value; } - public override bool CanConvertTo(Type type) - { - if (type == typeof(bool)) - return true; - if (type.GetTypeInfo().IsEnum && Enum.IsDefined(type, Value)) - return true; - if (type == typeof(double)) - return true; - if (type == typeof(string)) - return true; - return false; - } - internal static JString Parse(TextReader reader) { SkipSpace(reader); @@ -112,5 +69,17 @@ public override string ToString() { return $"\"{JavaScriptEncoder.Default.Encode(Value)}\""; } + + public override T TryGetEnum(T defaultValue = default, bool ignoreCase = false) + { + try + { + return (T)Enum.Parse(typeof(T), Value, ignoreCase); + } + catch + { + return defaultValue; + } + } } } diff --git a/neo/Network/RPC/RpcServer.cs b/neo/Network/RPC/RpcServer.cs index 5a12f190ba..9ba441c381 100644 --- a/neo/Network/RPC/RpcServer.cs +++ b/neo/Network/RPC/RpcServer.cs @@ -200,7 +200,7 @@ private JObject Process(string method, JArray _params) } if (block == null) throw new RpcException(-100, "Unknown block"); - bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); + bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); if (verbose) { JObject json = block.ToJson(); @@ -239,7 +239,7 @@ private JObject Process(string method, JArray _params) if (header == null) throw new RpcException(-100, "Unknown block"); - bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); + bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); if (verbose) { JObject json = header.ToJson(); @@ -301,7 +301,7 @@ private JObject Process(string method, JArray _params) } case "getrawmempool": { - bool shouldGetUnverified = _params.Count >= 1 && _params[0].AsBooleanOrDefault(false); + bool shouldGetUnverified = _params.Count >= 1 && _params[0].AsBoolean(); if (!shouldGetUnverified) return new JArray(Blockchain.Singleton.MemPool.GetVerifiedTransactions().Select(p => (JObject)p.Hash.ToString())); @@ -317,7 +317,7 @@ private JObject Process(string method, JArray _params) case "getrawtransaction": { UInt256 hash = UInt256.Parse(_params[0].AsString()); - bool verbose = _params.Count >= 2 && _params[1].AsBooleanOrDefault(false); + bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); Transaction tx = Blockchain.Singleton.GetTransaction(hash); if (tx == null) throw new RpcException(-100, "Unknown transaction"); diff --git a/neo/SmartContract/ContractParameter.cs b/neo/SmartContract/ContractParameter.cs index 0b0f76703e..5e78005e13 100644 --- a/neo/SmartContract/ContractParameter.cs +++ b/neo/SmartContract/ContractParameter.cs @@ -59,7 +59,7 @@ public static ContractParameter FromJson(JObject json) { ContractParameter parameter = new ContractParameter { - Type = json["type"].AsEnum() + Type = json["type"].TryGetEnum() }; if (json["value"] != null) switch (parameter.Type) diff --git a/neo/Wallets/NEP6/NEP6Contract.cs b/neo/Wallets/NEP6/NEP6Contract.cs index d934cf0326..a3dd36f414 100644 --- a/neo/Wallets/NEP6/NEP6Contract.cs +++ b/neo/Wallets/NEP6/NEP6Contract.cs @@ -15,7 +15,7 @@ public static NEP6Contract FromJson(JObject json) return new NEP6Contract { Script = json["script"].AsString().HexToBytes(), - ParameterList = ((JArray)json["parameters"]).Select(p => p["type"].AsEnum()).ToArray(), + ParameterList = ((JArray)json["parameters"]).Select(p => p["type"].TryGetEnum()).ToArray(), ParameterNames = ((JArray)json["parameters"]).Select(p => p["name"].AsString()).ToArray(), Deployed = json["deployed"].AsBoolean() }; diff --git a/neo/neo.csproj b/neo/neo.csproj index f922aae876..c9752a83fd 100644 --- a/neo/neo.csproj +++ b/neo/neo.csproj @@ -16,6 +16,7 @@ Neo The Neo Project Neo + latest From cbfebf912e0a724af48cb709c5dce61cd00ed593 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 18 Feb 2019 03:26:59 +0800 Subject: [PATCH 2/3] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 772858f229..6855ad3880 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ dist: trusty osx_image: xcode9.1 mono: none -dotnet: 2.0.0 +dotnet: 2.1.105 before_install: - cd neo.UnitTests From bf6b544df29376f2d310332bfe096624357660ce Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 18 Feb 2019 03:34:00 +0800 Subject: [PATCH 3/3] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6855ad3880..41d54f6fc4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ dist: trusty osx_image: xcode9.1 mono: none -dotnet: 2.1.105 +dotnet: 2.1.502 before_install: - cd neo.UnitTests