Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Commit 7990069

Browse files
authored
Merge pull request #250 from atoulme/uint_fixes
UInt compat fixes
2 parents 5bc1520 + 09091de commit 7990069

12 files changed

Lines changed: 210 additions & 17 deletions

File tree

evm/src/main/kotlin/org/apache/tuweni/evm/impl/berlin/OpCodes.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ val slt = Opcode { gasManager, _, stack, _, _, _, _ ->
102102
if (null == item || null == item2) {
103103
Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
104104
} else {
105-
if (item.toBigInteger() < item2.toBigInteger()) {
105+
if (item.toSignedBigInteger() < item2.toSignedBigInteger()) {
106106
stack.push(UInt256.ONE)
107107
} else {
108108
stack.push(UInt256.ZERO)
@@ -134,7 +134,7 @@ val sgt = Opcode { gasManager, _, stack, _, _, _, _ ->
134134
if (null == item || null == item2) {
135135
Result(EVMExecutionStatusCode.STACK_UNDERFLOW)
136136
} else {
137-
if (item.toBigInteger() > item2.toBigInteger()) {
137+
if (item.toSignedBigInteger() > item2.toSignedBigInteger()) {
138138
stack.push(UInt256.ONE)
139139
} else {
140140
stack.push(UInt256.ZERO)

units/src/main/java/org/apache/tuweni/units/bigints/BaseUInt256Value.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.apache.tuweni.bytes.MutableBytes32;
2020

2121
import java.math.BigInteger;
22+
import java.nio.ByteOrder;
2223
import java.util.function.Function;
2324

2425
/**
@@ -381,4 +382,9 @@ public Bytes slice(int i, int length) {
381382
public MutableBytes32 mutableCopy() {
382383
return MutableBytes32.wrap(value.toArrayUnsafe());
383384
}
385+
386+
@Override
387+
public long toLong(ByteOrder order) {
388+
return value.toLong(order);
389+
}
384390
}

units/src/main/java/org/apache/tuweni/units/bigints/UInt256.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ public UInt256 sdiv0(UInt256 divisor) {
451451
if (divisor.isZero()) {
452452
return UInt256.ZERO;
453453
} else {
454-
BigInteger result = this.toBigInteger().divide(divisor.toBigInteger());
454+
BigInteger result = this.toSignedBigInteger().divide(divisor.toSignedBigInteger());
455455
Bytes resultBytes = Bytes.wrap(result.toByteArray());
456456
if (resultBytes.size() > 32) {
457457
resultBytes = resultBytes.slice(resultBytes.size() - 32, 32);
@@ -532,8 +532,8 @@ public UInt256 smod0(UInt256 modulus) {
532532
return UInt256.ZERO;
533533
}
534534

535-
BigInteger bi = this.toBigInteger();
536-
BigInteger result = bi.abs().mod(modulus.toBigInteger().abs());
535+
BigInteger bi = this.toSignedBigInteger();
536+
BigInteger result = bi.abs().mod(modulus.toSignedBigInteger().abs());
537537

538538
if (bi.signum() < 0) {
539539
result = result.negate();

units/src/main/java/org/apache/tuweni/units/bigints/UInt256Value.java

Lines changed: 133 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@
1313
package org.apache.tuweni.units.bigints;
1414

1515

16+
import static java.nio.ByteOrder.BIG_ENDIAN;
17+
1618
import org.apache.tuweni.bytes.Bytes;
1719
import org.apache.tuweni.bytes.Bytes32;
1820

21+
import java.math.BigInteger;
22+
import java.nio.ByteOrder;
23+
1924

2025
/**
2126
* Represents a 256-bit (32 bytes) unsigned integer value.
@@ -336,13 +341,33 @@ default T subtractExact(long value) {
336341
* @return True if this value fits a java {@code int} (i.e. is less or equal to {@code Integer.MAX_VALUE}).
337342
*/
338343
default boolean fitsInt() {
339-
// Ints are 4 bytes, so anything but the 4 last bytes must be zeroes
340-
for (int i = 0; i < Bytes32.SIZE - 4; i++) {
341-
if (get(i) != 0)
342-
return false;
344+
return fitsInt(ByteOrder.BIG_ENDIAN);
345+
}
346+
347+
/**
348+
* Returns true if the value can fit in an int according to the byte order.
349+
*
350+
* @param order the byte order, little or big endian
351+
* @return True if this value fits a java {@code int} (i.e. is less or equal to {@code Integer.MAX_VALUE}).
352+
*/
353+
default boolean fitsInt(ByteOrder order) {
354+
if (order == ByteOrder.BIG_ENDIAN) {
355+
// Ints are 4 bytes, so anything but the 4 last bytes must be zeroes
356+
for (int i = 0; i < Bytes32.SIZE - 4; i++) {
357+
if (get(i) != 0)
358+
return false;
359+
}
360+
// Lastly, the left-most byte of the int must not start with a 1.
361+
return get(Bytes32.SIZE - 4) >= 0;
362+
} else {
363+
// Ints are 4 bytes, so only the 4 first bytes must not be zeroes
364+
for (int i = 4; i < Bytes32.SIZE - 4; i++) {
365+
if (get(i) != 0)
366+
return false;
367+
}
368+
// Lastly, the right-most byte of the int must not start with a 1.
369+
return get(3) >= 0;
343370
}
344-
// Lastly, the left-most byte of the int must not start with a 1.
345-
return get(Bytes32.SIZE - 4) >= 0;
346371
}
347372

348373
/**
@@ -358,19 +383,63 @@ default int intValue() {
358383
return getInt(Bytes32.SIZE - 4);
359384
}
360385

386+
@Override
387+
default int toInt(ByteOrder order) {
388+
if (!fitsInt(order)) {
389+
throw new ArithmeticException("Value does not fit a 4 byte int");
390+
}
391+
if (order == ByteOrder.BIG_ENDIAN) {
392+
return getInt(Bytes32.SIZE - 4, order);
393+
} else {
394+
return getInt(0, order);
395+
}
396+
}
397+
398+
@Override
399+
default long toLong(ByteOrder order) {
400+
if (!fitsLong(order)) {
401+
throw new ArithmeticException("Value does not fit a 8 byte long");
402+
}
403+
if (order == ByteOrder.BIG_ENDIAN) {
404+
return getLong(Bytes32.SIZE - 8, order);
405+
} else {
406+
return getLong(0, order);
407+
}
408+
}
409+
361410
/**
362411
* Returns true if the value can fit in a long.
363412
*
364413
* @return True if this value fits a java {@code long} (i.e. is less or equal to {@code Long.MAX_VALUE}).
365414
*/
366415
default boolean fitsLong() {
367-
// Longs are 8 bytes, so anything but the 8 last bytes must be zeroes
368-
for (int i = 0; i < Bytes32.SIZE - 8; i++) {
369-
if (get(i) != 0)
370-
return false;
416+
return fitsLong(ByteOrder.BIG_ENDIAN);
417+
}
418+
419+
/**
420+
* Returns true if the value can fit in a long.
421+
*
422+
* @param order byte order, little or big endian
423+
* @return True if this value fits a java {@code long} (i.e. is less or equal to {@code Long.MAX_VALUE}).
424+
*/
425+
default boolean fitsLong(ByteOrder order) {
426+
if (order == ByteOrder.BIG_ENDIAN) {
427+
// Longs are 8 bytes, so anything but the 8 last bytes must be zeroes
428+
for (int i = 0; i < Bytes32.SIZE - 8; i++) {
429+
if (get(i) != 0)
430+
return false;
431+
}
432+
// Lastly, the left-most byte of the long must not start with a 1.
433+
return get(Bytes32.SIZE - 8) >= 0;
434+
} else {
435+
// Longs are 8 bytes, so only the 8 first bytes may not be zeroes
436+
for (int i = 8; i < Bytes32.SIZE; i++) {
437+
if (get(i) != 0)
438+
return false;
439+
}
440+
// Lastly, the left-most byte of the long must not start with a 1.
441+
return get(7) >= 0;
371442
}
372-
// Lastly, the left-most byte of the long must not start with a 1.
373-
return get(Bytes32.SIZE - 8) >= 0;
374443
}
375444

376445
/**
@@ -433,4 +502,56 @@ default boolean lessThan(UInt256Value<T> other) {
433502
default boolean lessOrEqualThan(UInt256Value<T> other) {
434503
return compareTo(other) <= 0;
435504
}
505+
506+
/**
507+
* Returns the decimal representation of this value as a String.
508+
*
509+
* @return the decimal representation of this value as a String.
510+
*/
511+
default String toDecimalString() {
512+
return toBigInteger().toString(10);
513+
}
514+
515+
/**
516+
* The BigInteger corresponding to interpreting these bytes as a two's-complement signed integer.
517+
*
518+
* @return A {@link BigInteger} corresponding to interpreting these bytes as a two's-complement signed integer.
519+
*/
520+
default BigInteger toSignedBigInteger() {
521+
return toSignedBigInteger(BIG_ENDIAN);
522+
}
523+
524+
/**
525+
* The BigInteger corresponding to interpreting these bytes as a two's-complement signed integer.
526+
*
527+
* @param order The byte-order for decoding the integer.
528+
* @return A {@link BigInteger} corresponding to interpreting these bytes as a two's-complement signed integer.
529+
*/
530+
default BigInteger toSignedBigInteger(ByteOrder order) {
531+
if (size() == 0) {
532+
return BigInteger.ZERO;
533+
}
534+
return new BigInteger((order == BIG_ENDIAN) ? toArrayUnsafe() : reverse().toArrayUnsafe());
535+
}
536+
537+
/**
538+
* The BigInteger corresponding to interpreting these bytes as an unsigned integer.
539+
*
540+
* @return A positive (or zero) {@link BigInteger} corresponding to interpreting these bytes as an unsigned integer.
541+
*/
542+
@Override
543+
default BigInteger toBigInteger() {
544+
return toUnsignedBigInteger();
545+
}
546+
547+
/**
548+
* The BigInteger corresponding to interpreting these bytes as an unsigned integer.
549+
*
550+
* @param order The byte-order for decoding the integer.
551+
* @return A positive (or zero) {@link BigInteger} corresponding to interpreting these bytes as an unsigned integer.
552+
*/
553+
@Override
554+
default BigInteger toBigInteger(ByteOrder order) {
555+
return toUnsignedBigInteger(order);
556+
}
436557
}

units/src/main/java/org/apache/tuweni/units/bigints/UInt32Value.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,4 +390,13 @@ default int numberOfLeadingZeros() {
390390
default int bitLength() {
391391
return toBytes().bitLength();
392392
}
393+
394+
/**
395+
* Returns the decimal representation of this value as a String.
396+
*
397+
* @return the decimal representation of this value as a String.
398+
*/
399+
default String toDecimalString() {
400+
return toBigInteger().toString(10);
401+
}
393402
}

units/src/main/java/org/apache/tuweni/units/bigints/UInt384Value.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,4 +409,13 @@ default int numberOfLeadingZeros() {
409409
default int bitLength() {
410410
return toBytes().bitLength();
411411
}
412+
413+
/**
414+
* Returns the decimal representation of this value as a String.
415+
*
416+
* @return the decimal representation of this value as a String.
417+
*/
418+
default String toDecimalString() {
419+
return toBigInteger().toString(10);
420+
}
412421
}

units/src/main/java/org/apache/tuweni/units/bigints/UInt64Value.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,4 +403,13 @@ default int numberOfLeadingZeros() {
403403
default int bitLength() {
404404
return toBytes().bitLength();
405405
}
406+
407+
/**
408+
* Returns the decimal representation of this value as a String.
409+
*
410+
* @return the decimal representation of this value as a String.
411+
*/
412+
default String toDecimalString() {
413+
return toBigInteger().toString(10);
414+
}
406415
}

units/src/test/java/org/apache/tuweni/units/bigints/UInt256Test.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,4 +1168,9 @@ private void assertValueEquals(UInt256 expected, UInt256 actual) {
11681168
String msg = String.format("Expected %s but got %s", expected.toHexString(), actual.toHexString());
11691169
assertEquals(expected, actual, msg);
11701170
}
1171+
1172+
@Test
1173+
void testToDecimalString() {
1174+
assertEquals("3456", UInt256.valueOf(3456).toDecimalString());
1175+
}
11711176
}

units/src/test/java/org/apache/tuweni/units/bigints/UInt32Test.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,4 +863,8 @@ void toLongTooLarge() {
863863
assertEquals(4294967295L, UInt32.MAX_VALUE.toLong());
864864
}
865865

866+
@Test
867+
void testToDecimalString() {
868+
assertEquals("3456", UInt32.valueOf(3456).toDecimalString());
869+
}
866870
}

units/src/test/java/org/apache/tuweni/units/bigints/UInt384Test.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,4 +1096,9 @@ private void assertValueEquals(UInt384 expected, UInt384 actual) {
10961096
String msg = String.format("Expected %s but got %s", expected.toHexString(), actual.toHexString());
10971097
assertEquals(expected, actual, msg);
10981098
}
1099+
1100+
@Test
1101+
void testToDecimalString() {
1102+
assertEquals("3456", UInt384.valueOf(3456).toDecimalString());
1103+
}
10991104
}

0 commit comments

Comments
 (0)