diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bdc3d1f5..4426353d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ This document outlines major changes between releases. +## 0.98.4 "Mesmerization" (11 May 2022) + +An urgent release to fix incompatibility with mainnet at block 1528989. The +actual pair of problems leading to inability to process this block occurred +earilier than that, so to fix this you need to resynchronize your node. Fixed +node is confirmed to have identical state as 3.1.0 C# node up to block +1529810. + +Bugs fixed: + * StdLib itoa() implementation emitted uppercase letters instead of lowercase + (#2478) + * StdLib jsonDeserialize() implementation couldn't handle properly integers + larger than 64-bit signed (#2478) + ## 0.98.3 "Liquidation" (07 May 2022) This is a hotfix release to fix t4 testnet incompatibility at block diff --git a/pkg/core/native/std.go b/pkg/core/native/std.go index eecd58bf2..00ff22562 100644 --- a/pkg/core/native/std.go +++ b/pkg/core/native/std.go @@ -238,7 +238,6 @@ func (s *Std) itoa(_ *interop.Context, args []stackitem.Item) stackitem.Item { if pad := bs[0] & 0xF8; pad == 0 || pad == 0xF8 { str = str[1:] } - str = strings.ToUpper(str) default: panic(ErrInvalidBase) } diff --git a/pkg/core/native/std_test.go b/pkg/core/native/std_test.go index 2817850e0..da56a4f90 100644 --- a/pkg/core/native/std_test.go +++ b/pkg/core/native/std_test.go @@ -35,9 +35,9 @@ func TestStdLibItoaAtoi(t *testing.T) { {big.NewInt(1), big.NewInt(16), "1"}, {big.NewInt(7), big.NewInt(16), "7"}, {big.NewInt(8), big.NewInt(16), "08"}, - {big.NewInt(65535), big.NewInt(16), "0FFFF"}, - {big.NewInt(15), big.NewInt(16), "0F"}, - {big.NewInt(-1), big.NewInt(16), "F"}, + {big.NewInt(65535), big.NewInt(16), "0ffff"}, + {big.NewInt(15), big.NewInt(16), "0f"}, + {big.NewInt(-1), big.NewInt(16), "f"}, } for _, tc := range testCases { diff --git a/pkg/vm/stackitem/json.go b/pkg/vm/stackitem/json.go index 12e9df816..89540b51d 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 behavior. @@ -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: