stackitem: allow to unJSONize big numbers (>int64), fix #2477

100000000000000000000 overflows int64 and NeoGo returns some garbage to
contracts instead of a proper number.
This commit is contained in:
Roman Khimov 2022-05-11 21:03:10 +03:00
parent 3d1a81df1f
commit 621db8c832

View file

@ -7,9 +7,9 @@ import (
"errors" "errors"
"fmt" "fmt"
gio "io" gio "io"
"math"
"math/big" "math/big"
"strconv" "strconv"
"strings"
) )
// decoder is a wrapper around json.Decoder helping to mimic C# json decoder behaviour. // 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)), Decoder: *json.NewDecoder(bytes.NewReader(data)),
count: maxCount, count: maxCount,
} }
d.UseNumber()
if item, err := d.decode(); err != nil { if item, err := d.decode(); err != nil {
return nil, err return nil, err
} else if _, err := d.Token(); err != gio.EOF { } else if _, err := d.Token(); err != gio.EOF {
@ -208,11 +209,24 @@ func (d *decoder) decode() (Item, error) {
} }
case string: case string:
return NewByteArray([]byte(t)), nil return NewByteArray([]byte(t)), nil
case float64: case json.Number:
if math.Floor(t) != t { 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) return nil, fmt.Errorf("%w (real value for int)", ErrInvalidValue)
} }
return NewBigInteger(big.NewInt(int64(t))), nil }
ts = ts[:dot]
}
num, ok := new(big.Int).SetString(ts, 10)
if !ok {
return nil, fmt.Errorf("%w (integer)", ErrInvalidValue)
}
return NewBigInteger(num), nil
case bool: case bool:
return NewBool(t), nil return NewBool(t), nil
default: default: