accounts/abi: fix unpacking of negative int256 (#17583)
This commit is contained in:
parent
beee7a52e0
commit
42bd67bd6f
|
@ -25,8 +25,17 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
maxUint256 = big.NewInt(0).Add(
|
||||||
|
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil),
|
||||||
|
big.NewInt(-1))
|
||||||
|
maxInt256 = big.NewInt(0).Add(
|
||||||
|
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil),
|
||||||
|
big.NewInt(-1))
|
||||||
|
)
|
||||||
|
|
||||||
// reads the integer based on its kind
|
// reads the integer based on its kind
|
||||||
func readInteger(kind reflect.Kind, b []byte) interface{} {
|
func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} {
|
||||||
switch kind {
|
switch kind {
|
||||||
case reflect.Uint8:
|
case reflect.Uint8:
|
||||||
return b[len(b)-1]
|
return b[len(b)-1]
|
||||||
|
@ -45,7 +54,20 @@ func readInteger(kind reflect.Kind, b []byte) interface{} {
|
||||||
case reflect.Int64:
|
case reflect.Int64:
|
||||||
return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
|
return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
|
||||||
default:
|
default:
|
||||||
return new(big.Int).SetBytes(b)
|
// the only case lefts for integer is int256/uint256.
|
||||||
|
// big.SetBytes can't tell if a number is negative, positive on itself.
|
||||||
|
// On EVM, if the returned number > max int256, it is negative.
|
||||||
|
ret := new(big.Int).SetBytes(b)
|
||||||
|
if typ == UintTy {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.Cmp(maxInt256) > 0 {
|
||||||
|
ret.Add(maxUint256, big.NewInt(0).Neg(ret))
|
||||||
|
ret.Add(ret, big.NewInt(1))
|
||||||
|
ret.Neg(ret)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +201,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
|
||||||
case StringTy: // variable arrays are written at the end of the return bytes
|
case StringTy: // variable arrays are written at the end of the return bytes
|
||||||
return string(output[begin : begin+end]), nil
|
return string(output[begin : begin+end]), nil
|
||||||
case IntTy, UintTy:
|
case IntTy, UintTy:
|
||||||
return readInteger(t.Kind, returnOutput), nil
|
return readInteger(t.T, t.Kind, returnOutput), nil
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
return readBool(returnOutput)
|
return readBool(returnOutput)
|
||||||
case AddressTy:
|
case AddressTy:
|
||||||
|
|
|
@ -117,6 +117,11 @@ var unpackTests = []unpackTest{
|
||||||
enc: "0000000000000000000000000000000000000000000000000000000000000001",
|
enc: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
want: big.NewInt(1),
|
want: big.NewInt(1),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
def: `[{"type": "int256"}]`,
|
||||||
|
enc: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
want: big.NewInt(-1),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
def: `[{"type": "address"}]`,
|
def: `[{"type": "address"}]`,
|
||||||
enc: "0000000000000000000000000100000000000000000000000000000000000000",
|
enc: "0000000000000000000000000100000000000000000000000000000000000000",
|
||||||
|
|
Loading…
Reference in New Issue