Skip to content

Precision loss in json number deserialization #4583

Description

@roman-khimov

Describe the bug
While JSON deserialization code can cope with big (>2^53-1) numbers since Basilisk with #2883, in fact precision is still lost at the 53 bits boundary because internally JNumber is still just a double.

To Reproduce
This test:

--- a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs
+++ b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs
@@ -249,10 +249,10 @@ public void Deserialize_Array_Bool_Str_Num()
         {
             var snapshot = _snapshotCache.CloneCache();
             ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default);
-            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,9.05E+28,9007199254740993]"), ExecutionEngineLimits.Default);
 
             Assert.IsInstanceOfType(items, typeof(Array));
-            Assert.HasCount(4, (Array)items);
+            Assert.HasCount(5, (Array)items);
 
             var array = (Array)items;
 
@@ -260,6 +260,7 @@ public void Deserialize_Array_Bool_Str_Num()
             Assert.AreEqual("test", array[1].GetString());
             Assert.AreEqual(123, array[2].GetInteger());
             Assert.AreEqual(array[3].GetInteger(), BigInteger.Parse("90500000000000000000000000000"));
+            Assert.AreEqual(array[4].GetInteger(), BigInteger.Parse("9007199254740993"));
         }
 
         [TestMethod]

fails:

  Neo.UnitTests test net10.0 failed with 1 error(s) (12.7s)
    /home/rik/dev/neo/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs(263): error TESTERROR: 
      Deserialize_Array_Bool_Str_Num (9ms): Error Message: Assert.AreEqual failed. Expected:<9007199254740992>. Actual:<9007199254740993>. 
      Stack Trace:
         at Neo.UnitTests.SmartContract.UT_JsonSerializer.Deserialize_Array_Bool_Str_Num() in /home/rik/dev/neo/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs:line 263
         at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
         at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

Version
3.10.1

Expected behavior
Big numbers handled normally with full 256 bit precision.

(Optional) Additional context
#2879, #3036.

Metadata

Metadata

Assignees

Labels

BugUsed to tag confirmed bugs

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions