-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug fix for Int256 decode range [2^248, type(int256).max] and [ type(int256.min), -(2^248) ) #2070
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -141,17 +141,14 @@ public static <T extends NumericType> T decodeNumeric(String input, Class<T> 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The BigInteger constructor already support reading offset from input byte array, do not need the array copying here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. makes sense |
||
} else { | ||
numericValue = new BigInteger(inputByteArray, valueOffset, typeLengthAsBytes); | ||
} | ||
return type.getConstructor(BigInteger.class).newInstance(numericValue); | ||
|
||
} catch (NoSuchMethodException | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,6 +97,7 @@ | |
import org.web3j.abi.datatypes.generated.Uint80; | ||
import org.web3j.abi.datatypes.generated.Uint88; | ||
import org.web3j.abi.datatypes.generated.Uint96; | ||
import org.web3j.utils.Numeric; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
@@ -858,11 +859,63 @@ 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 testInt16All() throws Exception { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pick one type that won't take too long to run test to test the entire range for sanity There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. testing all Int16 and uint16 can be a overkill, adding tests for boundary cases should be enough. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
it is a loop with 2^16 = 65536 entries, I think it runs at a reasonable time. But if there is concern I can change it to boundary There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yes, that's the case I'm using, later on found that the bug is in a large range mentioned in PR title There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nischal is right, test only min and max here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
int boundary = (int) Math.pow(2, 16 - 1); | ||
for (int i = -boundary; i < boundary; i++) { | ||
assertEquals( | ||
TypeDecoder.decodeNumeric( | ||
TypeEncoder.encodeNumeric(new Int16(BigInteger.valueOf(i))), | ||
Int16.class), | ||
new Int16(BigInteger.valueOf(i))); | ||
} | ||
} | ||
|
||
@Test | ||
public void testUint16All() throws Exception { | ||
int boundary = (int) Math.pow(2, 16); | ||
for (int i = 0; i < boundary; i++) { | ||
assertEquals( | ||
TypeDecoder.decodeNumeric( | ||
TypeEncoder.encodeNumeric(new Uint16(BigInteger.valueOf(i))), | ||
Uint16.class), | ||
new Uint16(BigInteger.valueOf(i))); | ||
} | ||
} | ||
/* | ||
TODO: Enable once Solidity supports fixed types - see | ||
https://github.com/ethereum/solidity/issues/409 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These contains bug for decoding int256 range mentioned in PR