From 621db8c832fcc5320e902357a848c2a70e34b0e0 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Wed, 11 May 2022 21:03:10 +0300 Subject: [PATCH] stackitem: allow to unJSONize big numbers (>int64), fix #2477 100000000000000000000 overflows int64 and NeoGo returns some garbage to contracts instead of a proper number. --- pkg/vm/stackitem/json.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/pkg/vm/stackitem/json.go b/pkg/vm/stackitem/json.go index a2da62657..c397b0df9 100644 --- a/pkg/vm/stackitem/json.go +++ b/pkg/vm/stackitem/json.go @@ -7,9 +7,9 @@ import ( "errors" "fmt" gio "io" - "math" "math/big" "strconv" + "strings" ) // decoder is a wrapper around json.Decoder helping to mimic C# json decoder behaviour. @@ -164,6 +164,7 @@ func FromJSON(data []byte, maxCount int) (Item, error) { Decoder: *json.NewDecoder(bytes.NewReader(data)), count: maxCount, } + d.UseNumber() if item, err := d.decode(); err != nil { return nil, err } else if _, err := d.Token(); err != gio.EOF { @@ -208,11 +209,24 @@ func (d *decoder) decode() (Item, error) { } case string: return NewByteArray([]byte(t)), nil - case float64: - if math.Floor(t) != t { - return nil, fmt.Errorf("%w (real value for int)", ErrInvalidValue) + case json.Number: + ts := t.String() + dot := strings.IndexByte(ts, '.') + if dot != -1 { + // As a special case numbers like 123.000 are allowed (SetString rejects them). + // And yes, that's the way C# code works also. + for _, r := range ts[dot+1:] { + if r != '0' { + return nil, fmt.Errorf("%w (real value for int)", ErrInvalidValue) + } + } + ts = ts[:dot] } - return NewBigInteger(big.NewInt(int64(t))), nil + num, ok := new(big.Int).SetString(ts, 10) + if !ok { + return nil, fmt.Errorf("%w (integer)", ErrInvalidValue) + } + return NewBigInteger(num), nil case bool: return NewBool(t), nil default: