diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs
index 479303cfb5..95b1f08ef2 100644
--- a/src/Neo.Json/JNumber.cs
+++ b/src/Neo.Json/JNumber.cs
@@ -10,6 +10,7 @@
// modifications are permitted.
using System.Globalization;
+using System.Numerics;
using System.Text.Json;
namespace Neo.Json
@@ -40,7 +41,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 < MIN_SAFE_INTEGER)
+ throw new ArgumentException("value is lower than MIN_SAFE_INTEGER", nameof(value));
+
this.Value = value;
}
@@ -119,11 +126,22 @@ public static implicit operator JNumber(double value)
return new JNumber(value);
}
- public static implicit operator JNumber(long value)
+ public static implicit operator JNumber(BigInteger value)
{
- return new JNumber(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;
diff --git a/src/Neo.Json/JToken.cs b/src/Neo.Json/JToken.cs
index bb6a510a69..4316bfd27e 100644
--- a/src/Neo.Json/JToken.cs
+++ b/src/Neo.Json/JToken.cs
@@ -9,6 +9,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;
@@ -298,6 +299,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 4d77104a6e..86ae75748c 100644
--- a/src/Neo/SmartContract/JsonSerializer.cs
+++ b/src/Neo/SmartContract/JsonSerializer.cs
@@ -51,10 +51,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:
{
@@ -66,7 +63,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);
diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs
index 6eb0598fd3..4342c46451 100644
--- a/tests/Neo.Json.UnitTests/UT_JNumber.cs
+++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs
@@ -9,6 +9,8 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
+using System.Numerics;
+
namespace Neo.Json.UnitTests
{
enum Woo
@@ -37,20 +39,45 @@ 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 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()
{
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]
diff --git a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs
index 3ab32ad7a5..675727757f 100644
--- a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs
+++ b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs
@@ -43,7 +43,7 @@ public void JsonTest_WrongJson()
Assert.ThrowsException(() => JObject.Parse(json));
json = @"{""length"":99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999}";
- Assert.ThrowsException(() => JObject.Parse(json));
+ Assert.ThrowsException(() => JObject.Parse(json));
}
[TestMethod]
@@ -91,10 +91,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));
@@ -216,7 +216,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]
@@ -303,7 +303,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);
@@ -313,7 +313,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]