From 573cb1bc433de8d044292a9e52d9ed305b27165e Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 9 Oct 2023 03:25:19 -0600 Subject: [PATCH] Change Array Copying (#5998) * Change Array Copying Change array copying by re-using arrays when safe. Signed-off-by: Danno Ferrin * spotless Signed-off-by: Danno Ferrin * different bigint API Signed-off-by: Danno Ferrin * straddle case Signed-off-by: Danno Ferrin * less stack traces Signed-off-by: Danno Ferrin * spotless Signed-off-by: Danno Ferrin --------- Signed-off-by: Danno Ferrin --- .../besu/evmtool/EvmToolCommand.java | 3 +- .../vm/BlockchainReferenceTestTools.java | 2 +- .../hyperledger/besu/evm/frame/Memory.java | 4 ++- .../hyperledger/besu/evm/internal/Words.java | 28 +++++++++++++------ .../AltBN128MulPrecompiledContract.java | 2 +- .../AltBN128PairingPrecompiledContract.java | 2 +- .../BLAKE2BFPrecompileContract.java | 2 +- ...ularExponentiationPrecompiledContract.java | 12 +++++--- .../KZGPointEvalPrecompiledContract.java | 2 +- .../besu/evm/toy/EvmToyCommand.java | 3 +- 10 files changed, 39 insertions(+), 21 deletions(-) diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index e55c36721b..4f2c2a5a5f 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java @@ -424,7 +424,8 @@ public class EvmToolCommand implements Runnable { out.println(messageFrame.getExceptionalHaltReason().get()); } if (messageFrame.getRevertReason().isPresent()) { - out.println(new String(messageFrame.getRevertReason().get().toArray(), UTF_8)); + out.println( + new String(messageFrame.getRevertReason().get().toArrayUnsafe(), UTF_8)); } } } diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java index 266f8bb6a3..9d6f7982d8 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java @@ -87,7 +87,7 @@ public class BlockchainReferenceTestTools { params.ignore("blockWithAllTransactionTypes"); // EIP-4788 is still in flux and the current fill is not against the final address - params.ignore("[Cancun]"); + params.ignore("\\[Cancun\\]"); // EOF tests are written against an older version of the spec params.ignore("/stEOF/"); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/Memory.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/Memory.java index ac503ad090..ac5aa396b8 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/frame/Memory.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/Memory.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.evm.frame; +import org.hyperledger.besu.evm.internal.Words; + import java.util.Arrays; import org.apache.tuweni.bytes.Bytes; @@ -100,7 +102,7 @@ public class Memory { } try { - final long byteSize = Math.addExact(Math.addExact(location, numBytes), 31); + final long byteSize = Words.clampedAdd(Words.clampedAdd(location, numBytes), 31); long wordSize = byteSize / 32; return Math.max(wordSize, activeWords); } catch (ArithmeticException ae) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/internal/Words.java b/evm/src/main/java/org/hyperledger/besu/evm/internal/Words.java index 965573c995..71d599d0a2 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/internal/Words.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/internal/Words.java @@ -117,10 +117,12 @@ public interface Words { * @return value of a plus b if no over/underflows or Long.MAX_VALUE/Long.MIN_VALUE otherwise */ static long clampedAdd(final long a, final long b) { - try { - return Math.addExact(a, b); - } catch (final ArithmeticException ae) { + long r = a + b; + if (((a ^ r) & (b ^ r)) < 0) { + // out of bounds, clamp it! return a > 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } else { + return r; } } @@ -132,10 +134,15 @@ public interface Words { * @return value of a times b if no over/underflows or Long.MAX_VALUE/Long.MIN_VALUE otherwise */ static long clampedMultiply(final long a, final long b) { - try { - return Math.multiplyExact(a, b); - } catch (final ArithmeticException ae) { + long r = a * b; + long ax = Math.abs(a); + long ay = Math.abs(b); + if (((ax | ay) >>> 31 != 0) + && (((b != 0) && (r / b != a)) || (a == Long.MIN_VALUE && b == -1))) { + // out of bounds, clamp it! return ((a ^ b) < 0) ? Long.MIN_VALUE : Long.MAX_VALUE; + } else { + return r; } } @@ -148,9 +155,12 @@ public interface Words { * otherwise */ static int clampedMultiply(final int a, final int b) { - try { - return Math.multiplyExact(a, b); - } catch (final ArithmeticException ae) { + long r = (long) a * (long) b; + int ri = (int) r; + if (ri == r) { + return ri; + } else { + // out of bounds, clamp it! return ((a ^ b) < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128MulPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128MulPrecompiledContract.java index 0b8da1a3e4..73b824f763 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128MulPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128MulPrecompiledContract.java @@ -112,7 +112,7 @@ public class AltBN128MulPrecompiledContract extends AbstractAltBnPrecompiledCont if (offset > input.size() || length == 0) { return BigInteger.ZERO; } - final byte[] raw = Arrays.copyOfRange(input.toArray(), offset, offset + length); + final byte[] raw = Arrays.copyOfRange(input.toArrayUnsafe(), offset, offset + length); return new BigInteger(1, raw); } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128PairingPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128PairingPrecompiledContract.java index fd5205b309..992544d5c0 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128PairingPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128PairingPrecompiledContract.java @@ -151,7 +151,7 @@ public class AltBN128PairingPrecompiledContract extends AbstractAltBnPrecompiled if (offset > input.size() || length == 0) { return BigInteger.ZERO; } - final byte[] raw = Arrays.copyOfRange(input.toArray(), offset, offset + length); + final byte[] raw = Arrays.copyOfRange(input.toArrayUnsafe(), offset, offset + length); return new BigInteger(1, raw); } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/BLAKE2BFPrecompileContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/BLAKE2BFPrecompileContract.java index de7152d604..44707525d8 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/BLAKE2BFPrecompileContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/BLAKE2BFPrecompileContract.java @@ -57,7 +57,7 @@ public class BLAKE2BFPrecompileContract extends AbstractPrecompiledContract { return 0L; } - final byte[] roundsBytes = copyOfRange(input.toArray(), 0, 4); + final byte[] roundsBytes = copyOfRange(input.toArrayUnsafe(), 0, 4); final BigInteger rounds = new BigInteger(1, roundsBytes); return rounds.longValueExact(); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/BigIntegerModularExponentiationPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/BigIntegerModularExponentiationPrecompiledContract.java index 669edc7810..ffb82f078c 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/BigIntegerModularExponentiationPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/BigIntegerModularExponentiationPrecompiledContract.java @@ -25,7 +25,6 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.nativelib.arithmetic.LibArithmetic; import java.math.BigInteger; -import java.util.Arrays; import java.util.Optional; import javax.annotation.Nonnull; @@ -200,11 +199,16 @@ public class BigIntegerModularExponentiationPrecompiledContract * @return the big integer */ public static BigInteger extractParameter(final Bytes input, final int offset, final int length) { - if (offset > input.size() || length == 0) { + if (offset >= input.size() || length == 0) { return BigInteger.ZERO; + } else if (offset + length < input.size()) { + return new BigInteger(1, input.slice(offset, length).toArray()); + } else { + byte[] raw = new byte[length]; + Bytes partial = input.slice(offset); + System.arraycopy(partial.toArray(), 0, raw, 0, partial.size()); + return new BigInteger(1, raw); } - final byte[] raw = Arrays.copyOfRange(input.toArray(), offset, offset + length); - return new BigInteger(1, raw); } /** diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java index 4383b44ddb..bd5747f3b2 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/KZGPointEvalPrecompiledContract.java @@ -115,7 +115,7 @@ public class KZGPointEvalPrecompiledContract implements PrecompiledContract { return PrecompileContractResult.halt( null, Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); } else { - byte[] hash = Hash.sha256(commitment).toArray(); + byte[] hash = Hash.sha256(commitment).toArrayUnsafe(); hash[0] = 0x01; if (!versionedHash.equals(Bytes32.wrap(hash))) { return PrecompileContractResult.halt( diff --git a/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java b/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java index 368dbffabd..54060c9f34 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java @@ -211,7 +211,8 @@ public class EvmToyCommand implements Runnable { } if (messageFrame.getRevertReason().isPresent()) { out.println( - new String(messageFrame.getRevertReason().get().toArray(), StandardCharsets.UTF_8)); + new String( + messageFrame.getRevertReason().get().toArrayUnsafe(), StandardCharsets.UTF_8)); } } if (messageFrameStack.isEmpty()) {