aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDiep Pham <mrfavadi@gmail.com>2018-09-04 23:53:28 +0800
committerFelix Lange <fjl@users.noreply.github.com>2018-09-04 23:53:28 +0800
commit42bd67bd6fd599a5583452f011152a0c26c9dff4 (patch)
tree41176161eda207d0fd4b27358d5d3adb00d4f252
parentbeee7a52e08f6e948d4cca9de8ff59d5b8305917 (diff)
downloaddexon-42bd67bd6fd599a5583452f011152a0c26c9dff4.tar.gz
dexon-42bd67bd6fd599a5583452f011152a0c26c9dff4.tar.zst
dexon-42bd67bd6fd599a5583452f011152a0c26c9dff4.zip
accounts/abi: fix unpacking of negative int256 (#17583)
-rw-r--r--accounts/abi/unpack.go28
-rw-r--r--accounts/abi/unpack_test.go5
2 files changed, 30 insertions, 3 deletions
diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go
index 793d515ad..d5875140c 100644
--- a/accounts/abi/unpack.go
+++ b/accounts/abi/unpack.go
@@ -25,8 +25,17 @@ import (
"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
-func readInteger(kind reflect.Kind, b []byte) interface{} {
+func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} {
switch kind {
case reflect.Uint8:
return b[len(b)-1]
@@ -45,7 +54,20 @@ func readInteger(kind reflect.Kind, b []byte) interface{} {
case reflect.Int64:
return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
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
return string(output[begin : begin+end]), nil
case IntTy, UintTy:
- return readInteger(t.Kind, returnOutput), nil
+ return readInteger(t.T, t.Kind, returnOutput), nil
case BoolTy:
return readBool(returnOutput)
case AddressTy:
diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go
index bdbab10b4..97552b90c 100644
--- a/accounts/abi/unpack_test.go
+++ b/accounts/abi/unpack_test.go
@@ -118,6 +118,11 @@ var unpackTests = []unpackTest{
want: big.NewInt(1),
},
{
+ def: `[{"type": "int256"}]`,
+ enc: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ want: big.NewInt(-1),
+ },
+ {
def: `[{"type": "address"}]`,
enc: "0000000000000000000000000100000000000000000000000000000000000000",
want: common.Address{1},