From 6b31958ca9b6a863a484e41d14057362c6d763b6 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Dec 2023 10:10:06 +0100 Subject: [PATCH 01/15] Json BigInteger --- src/Neo.Json/JNumber.cs | 14 +++++++++++++- src/Neo.Json/JToken.cs | 6 ++++++ src/Neo/SmartContract/JsonSerializer.cs | 7 ++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 7e58b72567..624c7e9d11 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -9,6 +9,7 @@ // modifications are permitted. using System.Globalization; +using System.Numerics; using System.Text.Json; namespace Neo.Json @@ -39,7 +40,13 @@ public class JNumber : JToken /// The value of the JSON token. public JNumber(double value = 0) { - if (!double.IsFinite(value)) throw new FormatException(); + if (!double.IsFinite(value)) + throw new ArgumentException("value is not finite", nameof(value)); + if (value > MAX_SAFE_INTEGER) + throw new ArgumentException("value is higher than MAX_SAFE_INTEGER", nameof(value)); + if (value < MAX_SAFE_INTEGER) + throw new ArgumentException("value is lower than MAX_SAFE_INTEGER", nameof(value)); + this.Value = value; } @@ -117,5 +124,10 @@ public static implicit operator JNumber(double value) { return new JNumber(value); } + + public static implicit operator JNumber(BigInteger value) + { + return new JNumber((long)value); + } } } diff --git a/src/Neo.Json/JToken.cs b/src/Neo.Json/JToken.cs index 8c38fb9bc4..c93365b92a 100644 --- a/src/Neo.Json/JToken.cs +++ b/src/Neo.Json/JToken.cs @@ -8,6 +8,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System.Numerics; using System.Text.Json; using static Neo.Json.Utility; @@ -297,6 +298,11 @@ public static implicit operator JToken(double value) return (JNumber)value; } + public static implicit operator JToken(BigInteger value) + { + return (JNumber)value; + } + public static implicit operator JToken?(string? value) { return (JString?)value; diff --git a/src/Neo/SmartContract/JsonSerializer.cs b/src/Neo/SmartContract/JsonSerializer.cs index 06eb1d5c22..cd69dfaaa8 100644 --- a/src/Neo/SmartContract/JsonSerializer.cs +++ b/src/Neo/SmartContract/JsonSerializer.cs @@ -50,10 +50,7 @@ public static JToken Serialize(StackItem item) } case Integer num: { - var integer = num.GetInteger(); - if (integer > JNumber.MAX_SAFE_INTEGER || integer < JNumber.MIN_SAFE_INTEGER) - throw new InvalidOperationException(); - return (double)integer; + return num.GetInteger(); } case Boolean boolean: { @@ -65,7 +62,7 @@ public static JToken Serialize(StackItem item) foreach (var entry in map) { - if (!(entry.Key is ByteString)) throw new FormatException(); + if (entry.Key is not ByteString) throw new FormatException(); var key = entry.Key.GetString(); var value = Serialize(entry.Value); From 48c26490f941b6e5652c3e5a95e00dace8ba553a Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Dec 2023 10:17:33 +0100 Subject: [PATCH 02/15] Fix Min --- src/Neo.Json/JNumber.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 624c7e9d11..aa78569048 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -44,7 +44,7 @@ public JNumber(double value = 0) throw new ArgumentException("value is not finite", nameof(value)); if (value > MAX_SAFE_INTEGER) throw new ArgumentException("value is higher than MAX_SAFE_INTEGER", nameof(value)); - if (value < MAX_SAFE_INTEGER) + if (value < MIN_SAFE_INTEGER) throw new ArgumentException("value is lower than MAX_SAFE_INTEGER", nameof(value)); this.Value = value; From 186c2baa0ca66eaf2f0620ea11658aebb1ff6d55 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Dec 2023 10:18:17 +0100 Subject: [PATCH 03/15] Fix ut --- tests/Neo.Json.UnitTests/UT_JNumber.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index 6156bc1cb5..c03709f43e 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -33,13 +33,13 @@ public void TestAsBoolean() public void TestAsString() { Action action1 = () => new JNumber(double.PositiveInfinity).AsString(); - action1.Should().Throw(); + action1.Should().Throw(); Action action2 = () => new JNumber(double.NegativeInfinity).AsString(); - action2.Should().Throw(); + action2.Should().Throw(); Action action3 = () => new JNumber(double.NaN).AsString(); - action3.Should().Throw(); + action3.Should().Throw(); } [TestMethod] From eab5b25783a004e7d78dfc5b68f1da7449aa09ae Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Dec 2023 10:19:45 +0100 Subject: [PATCH 04/15] add ut --- tests/Neo.Json.UnitTests/UT_JNumber.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index c03709f43e..6644e05e2f 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -1,3 +1,5 @@ +using System.Numerics; + namespace Neo.Json.UnitTests { enum Woo @@ -26,9 +28,18 @@ public void SetUp() public void TestAsBoolean() { maxInt.AsBoolean().Should().BeTrue(); + minInt.AsBoolean().Should().BeTrue(); zero.AsBoolean().Should().BeFalse(); } + [TestMethod] + public void TestBigInteger() + { + ((JNumber)BigInteger.One).AsNumber().Should().Be(1); + ((JNumber)BigInteger.Zero).AsNumber().Should().Be(0); + ((JNumber)BigInteger.MinusOne).AsNumber().Should().Be(-1); + } + [TestMethod] public void TestAsString() { From 776ab647b729acb4d3f029db5eef5720130472a3 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Dec 2023 10:20:20 +0100 Subject: [PATCH 05/15] Fix exception msg --- src/Neo.Json/JNumber.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index aa78569048..1a4c078583 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -45,7 +45,7 @@ public JNumber(double value = 0) if (value > MAX_SAFE_INTEGER) throw new ArgumentException("value is higher than MAX_SAFE_INTEGER", nameof(value)); if (value < MIN_SAFE_INTEGER) - throw new ArgumentException("value is lower than MAX_SAFE_INTEGER", nameof(value)); + throw new ArgumentException("value is lower than MIN_SAFE_INTEGER", nameof(value)); this.Value = value; } From 9ccb97d7ad46a3c94de65f08cb3e8f1272b2c544 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Dec 2023 10:28:04 +0100 Subject: [PATCH 06/15] format --- src/Neo.Json/JNumber.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 1a4c078583..c090bf381d 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -40,7 +40,7 @@ public class JNumber : JToken /// The value of the JSON token. public JNumber(double value = 0) { - if (!double.IsFinite(value)) + if (!double.IsFinite(value)) throw new ArgumentException("value is not finite", nameof(value)); if (value > MAX_SAFE_INTEGER) throw new ArgumentException("value is higher than MAX_SAFE_INTEGER", nameof(value)); From 458499b4cc9aeddf05bb2d8fa165757e751abca5 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Wed, 27 Dec 2023 10:38:26 +0100 Subject: [PATCH 07/15] Fix UT --- .../Neo.UnitTests/SmartContract/UT_JsonSerializer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs index bf608bc57e..7e48d9df01 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs @@ -32,7 +32,7 @@ public void JsonTest_WrongJson() Assert.ThrowsException(() => JObject.Parse(json)); json = @"{""length"":99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999}"; - Assert.ThrowsException(() => JObject.Parse(json)); + Assert.ThrowsException(() => JObject.Parse(json)); } [TestMethod] @@ -80,10 +80,10 @@ public void JsonTest_Numbers() Assert.AreEqual("[1,-2,3.5]", parsed.ToString()); - json = "[200.500000E+005,200.500000e+5,-1.1234e-100,9.05E+28]"; + json = "[200.500000E+005,200.500000e+5,-1.1234e-100,9.05E+8]"; parsed = JObject.Parse(json); - Assert.AreEqual("[20050000,20050000,-1.1234E-100,9.05E+28]", parsed.ToString()); + Assert.AreEqual("[20050000,20050000,-1.1234E-100,905000000]", parsed.ToString()); json = "[-]"; Assert.ThrowsException(() => JObject.Parse(json)); @@ -205,7 +205,7 @@ public void Serialize_EmptyObject() public void Serialize_Number() { var entry = new VM.Types.Array { 1, 9007199254740992 }; - Assert.ThrowsException(() => JsonSerializer.Serialize(entry)); + Assert.ThrowsException(() => JsonSerializer.Serialize(entry)); } [TestMethod] @@ -292,7 +292,7 @@ public void Serialize_Array_Bool_Str_Num() public void Deserialize_Array_Bool_Str_Num() { ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null); - var items = JsonSerializer.Deserialize(engine, JObject.Parse("[true,\"test\",123,9.05E+28]"), ExecutionEngineLimits.Default); + var items = JsonSerializer.Deserialize(engine, JObject.Parse("[true,\"test\",123,1.05E+4]"), ExecutionEngineLimits.Default); Assert.IsInstanceOfType(items, typeof(VM.Types.Array)); Assert.AreEqual(((VM.Types.Array)items).Count, 4); @@ -302,7 +302,7 @@ public void Deserialize_Array_Bool_Str_Num() Assert.IsTrue(array[0].GetBoolean()); Assert.AreEqual(array[1].GetString(), "test"); Assert.AreEqual(array[2].GetInteger(), 123); - Assert.AreEqual(array[3].GetInteger(), BigInteger.Parse("90500000000000000000000000000")); + Assert.AreEqual(array[3].GetInteger(), BigInteger.Parse("10500")); } [TestMethod] From 308d33ddf9c990f2cbf229b7f9794d7af3bab10d Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 15 Feb 2024 17:23:55 +0800 Subject: [PATCH 08/15] Update src/Neo.Json/JNumber.cs --- src/Neo.Json/JNumber.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index ff75d0f6a1..95b1f08ef2 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -131,6 +131,17 @@ public static implicit operator JNumber(BigInteger value) return new JNumber((long)value); } + /// + /// Check if two JNumber are equal. + /// + /// Non null value + /// Nullable value + /// bool + /// + /// If the left is null, throw an . + /// If the right is null, return false. + /// If the left and right are the same object, return true. + /// public static bool operator ==(JNumber left, JNumber? right) { if (right is null) return false; From 19e31118051b4c1368fe81bf4697cb932659d3ec Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 15 Feb 2024 17:24:11 +0800 Subject: [PATCH 09/15] Update tests/Neo.Json.UnitTests/UT_JNumber.cs --- tests/Neo.Json.UnitTests/UT_JNumber.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index 0709a9bcd6..84d4019f1f 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -50,6 +50,22 @@ public void TestBigInteger() ((JNumber)BigInteger.Zero).AsNumber().Should().Be(0); ((JNumber)BigInteger.MinusOne).AsNumber().Should().Be(-1); } + + [TestMethod] + public void TestNullEqual() + { + JNumber nullJNumber = null; + + Assert.IsFalse(maxInt.Equals(null)); + Assert.IsFalse(maxInt == null); + Assert.IsFalse(minInt.Equals(null)); + Assert.IsFalse(minInt == null); + Assert.IsFalse(zero == null); + + Assert.ThrowsException(() => nullJNumber == maxInt); + Assert.ThrowsException(() => nullJNumber == minInt); + Assert.ThrowsException(() => nullJNumber == zero); + } [TestMethod] public void TestAsString() From 1214697581fa17d064793fd3386ad1b04e9f50df Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 15 Feb 2024 12:06:47 +0100 Subject: [PATCH 10/15] Fix format --- tests/Neo.Json.UnitTests/UT_JNumber.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index 84d4019f1f..4342c46451 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -50,7 +50,7 @@ public void TestBigInteger() ((JNumber)BigInteger.Zero).AsNumber().Should().Be(0); ((JNumber)BigInteger.MinusOne).AsNumber().Should().Be(-1); } - + [TestMethod] public void TestNullEqual() { From 4b6542b1b04b5e5fe1fb0c40947c5670f3541fcc Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 28 Nov 2024 11:27:45 +0100 Subject: [PATCH 11/15] Add min and max ut --- tests/Neo.Json.UnitTests/UT_JNumber.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index 58f01dc5b7..082598c126 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -49,6 +49,8 @@ public void TestBigInteger() ((JNumber)BigInteger.One).AsNumber().Should().Be(1); ((JNumber)BigInteger.Zero).AsNumber().Should().Be(0); ((JNumber)BigInteger.MinusOne).AsNumber().Should().Be(-1); + ((JNumber)JNumber.MAX_SAFE_INTEGER).AsNumber().Should().Be(JNumber.MAX_SAFE_INTEGER); + ((JNumber)JNumber.MIN_SAFE_INTEGER).AsNumber().Should().Be(JNumber.MIN_SAFE_INTEGER); } [TestMethod] From 758933e9b254232fe7cb3c2f3a1fa128be2e80ce Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 28 Nov 2024 11:29:30 +0100 Subject: [PATCH 12/15] Vitor suggestion --- src/Neo.Json/JNumber.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 54b0f148e1..1efaeb6354 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -41,12 +41,12 @@ public class JNumber : JToken /// The value of the JSON token. public JNumber(double value = 0) { - if (!double.IsFinite(value)) - throw new ArgumentException("value is not finite", nameof(value)); if (value > MAX_SAFE_INTEGER) throw new ArgumentException("value is higher than MAX_SAFE_INTEGER", nameof(value)); if (value < MIN_SAFE_INTEGER) throw new ArgumentException("value is lower than MIN_SAFE_INTEGER", nameof(value)); + if (!double.IsFinite(value)) + throw new ArgumentException("value is not finite", nameof(value)); Value = value; } From 3599c81eba0df838baacf82b7ccaf9c166ad0dfa Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 28 Nov 2024 11:33:49 +0100 Subject: [PATCH 13/15] Avoid doble casting --- src/Neo.Json/JToken.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.Json/JToken.cs b/src/Neo.Json/JToken.cs index 9db17334d2..b4dbf38ca3 100644 --- a/src/Neo.Json/JToken.cs +++ b/src/Neo.Json/JToken.cs @@ -296,12 +296,12 @@ public static implicit operator JToken(JToken?[] value) public static implicit operator JToken(bool value) { - return (JBoolean)value; + return new JBoolean(value); } public static implicit operator JToken(double value) { - return (JNumber)value; + return new JNumber(value); } public static implicit operator JToken(BigInteger value) From d41891672aa10bd42fe960b0551b1af42690a7ad Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 28 Nov 2024 11:46:08 +0100 Subject: [PATCH 14/15] Add HK checker --- src/Neo.Json/JNumber.cs | 15 ++++++++++----- src/Neo/SmartContract/JsonSerializer.cs | 9 +++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 1efaeb6354..1bc604a3fc 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -39,12 +39,17 @@ public class JNumber : JToken /// Initializes a new instance of the class with the specified value. /// /// The value of the JSON token. - public JNumber(double value = 0) + /// True if we want to ensure that the value is in the limits. + public JNumber(double value = 0, bool checkMinMax = true) { - if (value > MAX_SAFE_INTEGER) - throw new ArgumentException("value is higher than MAX_SAFE_INTEGER", nameof(value)); - if (value < MIN_SAFE_INTEGER) - throw new ArgumentException("value is lower than MIN_SAFE_INTEGER", nameof(value)); + if (checkMinMax) + { + if (value > MAX_SAFE_INTEGER) + throw new ArgumentException("value is higher than MAX_SAFE_INTEGER", nameof(value)); + if (value < MIN_SAFE_INTEGER) + throw new ArgumentException("value is lower than MIN_SAFE_INTEGER", nameof(value)); + } + if (!double.IsFinite(value)) throw new ArgumentException("value is not finite", nameof(value)); diff --git a/src/Neo/SmartContract/JsonSerializer.cs b/src/Neo/SmartContract/JsonSerializer.cs index d0fec67cdd..482adefc54 100644 --- a/src/Neo/SmartContract/JsonSerializer.cs +++ b/src/Neo/SmartContract/JsonSerializer.cs @@ -35,14 +35,15 @@ public static class JsonSerializer /// Serializes a to a . /// /// The to serialize. + /// Hardfork checker /// The serialized object. - public static JToken Serialize(StackItem item) + public static JToken Serialize(StackItem item, Func hardforkChecker = null) { switch (item) { case Array array: { - return array.Select(p => Serialize(p)).ToArray(); + return array.Select(p => Serialize(p, hardforkChecker)).ToArray(); } case ByteString _: case Buffer _: @@ -51,7 +52,7 @@ public static JToken Serialize(StackItem item) } case Integer num: { - return num.GetInteger(); + return new JNumber((long)num.GetInteger(), hardforkChecker == null || hardforkChecker(Hardfork.HF_Echidna)); } case Boolean boolean: { @@ -66,7 +67,7 @@ public static JToken Serialize(StackItem item) if (entry.Key is not ByteString) throw new FormatException(); var key = entry.Key.GetString(); - var value = Serialize(entry.Value); + var value = Serialize(entry.Value, hardforkChecker); ret[key] = value; } From 04402c9d26adfbbe9678740d4f12e5f6eaa3043f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Thu, 28 Nov 2024 11:47:01 +0100 Subject: [PATCH 15/15] Reduce changes --- src/Neo.Json/JNumber.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 1bc604a3fc..0842ed92e4 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -132,6 +132,11 @@ public static implicit operator JNumber(double value) return new JNumber(value); } + public static implicit operator JNumber(long value) + { + return new JNumber(value); + } + public static implicit operator JNumber(BigInteger value) { return new JNumber((long)value);