From 1e83c608c0edd0c2a14d4682ccbe92c9279c1406 Mon Sep 17 00:00:00 2001 From: tonykwok1992 Date: Wed, 26 Jun 2024 20:12:27 +0800 Subject: [PATCH] Bug fix for Int256 decode range [2^248, type(int256).max] and [ type(int256.min), -(2^248) ) (#2070) * Bug fix for Int256 decode Signed-off-by: tonykwok1992 * Change log Signed-off-by: tonykwok1992 * Test int16/Uint16 min max only Signed-off-by: tonykwok1992 --------- Signed-off-by: tonykwok1992 --- CHANGELOG.md | 2 +- .../main/java/org/web3j/abi/TypeDecoder.java | 15 ++--- .../java/org/web3j/abi/TypeDecoderTest.java | 57 +++++++++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3155dbbb0..6b638f612 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes -* +* Bug fix for Int256 decode range [2^248, type(int256).max] and [ type(int256.min), -(2^248) ) ### Features diff --git a/abi/src/main/java/org/web3j/abi/TypeDecoder.java b/abi/src/main/java/org/web3j/abi/TypeDecoder.java index e24d8f01c..00975c3e1 100644 --- a/abi/src/main/java/org/web3j/abi/TypeDecoder.java +++ b/abi/src/main/java/org/web3j/abi/TypeDecoder.java @@ -141,17 +141,14 @@ public static T decodeNumeric(String input, Class typ try { byte[] inputByteArray = Numeric.hexStringToByteArray(input); int typeLengthAsBytes = getTypeLengthInBytes(type); - - byte[] resultByteArray = new byte[typeLengthAsBytes + 1]; - - if (Int.class.isAssignableFrom(type) || Fixed.class.isAssignableFrom(type)) { - resultByteArray[0] = inputByteArray[0]; // take MSB as sign bit - } - int valueOffset = Type.MAX_BYTE_LENGTH - typeLengthAsBytes; - System.arraycopy(inputByteArray, valueOffset, resultByteArray, 1, typeLengthAsBytes); - BigInteger numericValue = new BigInteger(resultByteArray); + BigInteger numericValue; + if (Uint.class.isAssignableFrom(type) || Ufixed.class.isAssignableFrom(type)) { + numericValue = new BigInteger(1, inputByteArray, valueOffset, typeLengthAsBytes); + } else { + numericValue = new BigInteger(inputByteArray, valueOffset, typeLengthAsBytes); + } return type.getConstructor(BigInteger.class).newInstance(numericValue); } catch (NoSuchMethodException diff --git a/abi/src/test/java/org/web3j/abi/TypeDecoderTest.java b/abi/src/test/java/org/web3j/abi/TypeDecoderTest.java index c23a898fc..24e63422b 100644 --- a/abi/src/test/java/org/web3j/abi/TypeDecoderTest.java +++ b/abi/src/test/java/org/web3j/abi/TypeDecoderTest.java @@ -858,11 +858,68 @@ public void testIntDecode() throws Exception { Int256.class), (new Int256(BigInteger.valueOf(-1)))); + assertEquals( + TypeDecoder.decodeNumeric( + TypeEncoder.encodeNumeric(new Int256(BigInteger.TWO.pow(248))), + Int256.class), + new Int256(BigInteger.TWO.pow(248))); + + assertEquals( + TypeDecoder.decodeNumeric( + TypeEncoder.encodeNumeric( + new Int256( + BigInteger.TWO.pow(248).negate().subtract(BigInteger.ONE))), + Int256.class), + new Int256(BigInteger.TWO.pow(248).negate().subtract(BigInteger.ONE))); + + assertEquals( + TypeDecoder.decodeNumeric( + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + Int256.class), + new Int256( + new BigInteger( + "57896044618658097711785492504343953926634992332820282019728792003956564819967"))); + + assertEquals( + TypeDecoder.decodeNumeric( + "0x8000000000000000000000000000000000000000000000000000000000000000", + Int256.class), + new Int256( + new BigInteger( + "-57896044618658097711785492504343953926634992332820282019728792003956564819968"))); + assertEquals(TypeDecoder.instantiateType("int", 123), (new Int(BigInteger.valueOf(123)))); assertEquals(TypeDecoder.instantiateType("int", -123), (new Int(BigInteger.valueOf(-123)))); } + @Test + public void testInt16MinMax() throws Exception { + assertEquals( + TypeDecoder.decodeNumeric( + TypeEncoder.encodeNumeric( + new Int16(BigInteger.valueOf((long) Math.pow(2, 15) - 1))), + Int16.class), + new Int16(BigInteger.valueOf((long) Math.pow(2, 15) - 1))); + + assertEquals( + TypeDecoder.decodeNumeric( + TypeEncoder.encodeNumeric( + new Int16(BigInteger.valueOf((long) -Math.pow(2, 15)))), + Int16.class), + new Int16(BigInteger.valueOf((long) -Math.pow(2, 15)))); + } + + @Test + public void testUint16Max() throws Exception { + assertEquals( + TypeDecoder.decodeNumeric( + TypeEncoder.encodeNumeric( + new Uint16(BigInteger.valueOf((long) Math.pow(2, 16) - 1))), + Uint16.class), + new Uint16(BigInteger.valueOf((long) Math.pow(2, 16) - 1))); + } + /* TODO: Enable once Solidity supports fixed types - see https://github.com/ethereum/solidity/issues/409