From 61ae7b0384d0a26f34539e4275178362161a4d98 Mon Sep 17 00:00:00 2001 From: matkt Date: Wed, 8 Sep 2021 11:42:04 +0200 Subject: [PATCH] Update memory to use MutableBytes (#2673) Signed-off-by: Karim TAAM --- .../besu/ethereum/debug/TraceFrame.java | 2 +- .../precompiles/IDPrecompiledContract.java | 2 +- .../ethereum/vm/AbstractCallOperation.java | 3 +- .../hyperledger/besu/ethereum/vm/Memory.java | 37 +++++++++---------- .../besu/ethereum/vm/MessageFrame.java | 17 +++++++-- .../operations/AbstractCreateOperation.java | 4 +- .../vm/operations/Create2Operation.java | 2 +- .../vm/operations/MLoadOperation.java | 3 +- .../ethereum/vm/operations/Sha3Operation.java | 2 +- 9 files changed, 42 insertions(+), 30 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/debug/TraceFrame.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/debug/TraceFrame.java index fea65a06c5..d1cb5f4353 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/debug/TraceFrame.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/debug/TraceFrame.java @@ -92,7 +92,7 @@ public class TraceFrame { this.exceptionalHaltReason = exceptionalHaltReason; this.recipient = recipient; this.value = value; - this.inputData = inputData; + this.inputData = inputData.copy(); this.outputData = outputData; this.stack = stack; this.memory = memory; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/IDPrecompiledContract.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/IDPrecompiledContract.java index 57aeaee073..5672b4c82d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/IDPrecompiledContract.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/IDPrecompiledContract.java @@ -34,6 +34,6 @@ public class IDPrecompiledContract extends AbstractPrecompiledContract { @Override public Bytes compute(final Bytes input, final MessageFrame messageFrame) { - return input; + return input.copy(); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/AbstractCallOperation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/AbstractCallOperation.java index b8b2ed4fa9..214996bb65 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/AbstractCallOperation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/AbstractCallOperation.java @@ -182,7 +182,8 @@ public abstract class AbstractCallOperation extends AbstractOperation { return new OperationResult(optionalCost, Optional.empty()); } - final Bytes inputData = frame.readMemory(inputDataOffset(frame), inputDataLength(frame)); + final Bytes inputData = + frame.readMutableMemory(inputDataOffset(frame), inputDataLength(frame)); final MessageFrame childFrame = MessageFrame.builder() diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/Memory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/Memory.java index b06ddba56d..ae78ec0efb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/Memory.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/Memory.java @@ -15,10 +15,10 @@ package org.hyperledger.besu.ethereum.vm; import java.math.BigInteger; -import java.util.Arrays; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.bytes.MutableBytes; import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256s; @@ -40,18 +40,18 @@ public class Memory { * overflow this. A byte array implementation limits us to 2GiB. But that would cost over 51 * trillion gas. So this is likely a reasonable limitation, at least at first. */ - private byte[] data; + private MutableBytes data; private UInt256 activeWords; private int dataSize256; public Memory() { - data = new byte[0]; + data = MutableBytes.EMPTY; updateSize(); } private void updateSize() { - dataSize256 = data.length / Bytes32.SIZE; + dataSize256 = data.size() / Bytes32.SIZE; activeWords = UInt256.valueOf(dataSize256); } @@ -170,8 +170,8 @@ public class Memory { if (dataSize256 >= newActiveWords) return; // Require full capacity to guarantee we don't resize more than once. - final byte[] newData = new byte[newActiveWords * Bytes32.SIZE]; - System.arraycopy(data, 0, newData, 0, data.length); + final MutableBytes newData = MutableBytes.create(newActiveWords * Bytes32.SIZE); + data.copyTo(newData, 0); data = newData; updateSize(); } @@ -189,12 +189,12 @@ public class Memory { if (!(other instanceof Memory)) return false; final Memory that = (Memory) other; - return Arrays.equals(this.data, that.data); + return this.data.equals(that.data); } @Override public int hashCode() { - return Arrays.hashCode(data); + return data.hashCode(); } /** @@ -203,7 +203,7 @@ public class Memory { * @return The current number of active bytes stored in memory. */ int getActiveBytes() { - return data.length; + return data.size(); } /** @@ -236,7 +236,7 @@ public class Memory { final int start = asByteIndex(location); ensureCapacityForBytes(start, length); - return Bytes.of(Arrays.copyOfRange(data, start, start + numBytes.intValue())); + return data.slice(start, numBytes.intValue()); } /** @@ -303,10 +303,10 @@ public class Memory { ensureCapacityForBytes(start, length); if (srcLength >= length) { - System.arraycopy(taintedValue.toArrayUnsafe(), 0, data, start, length); + data.set(start, taintedValue.slice(0, length)); } else { - Arrays.fill(data, start, end, (byte) 0); - System.arraycopy(taintedValue.toArrayUnsafe(), 0, data, start, srcLength); + data.set(start, Bytes.of(new byte[end - start])); + data.set(start, taintedValue.slice(0, srcLength)); } } @@ -337,7 +337,7 @@ public class Memory { } ensureCapacityForBytes(location, numBytes); - Arrays.fill(data, location, location + numBytes, (byte) 0); + data.set(location, Bytes.of(new byte[numBytes])); } /** @@ -349,7 +349,7 @@ public class Memory { void setByte(final UInt256 location, final byte value) { final int start = asByteIndex(location); ensureCapacityForBytes(start, 1); - data[start] = value; + data.set(start, value); } /** @@ -361,7 +361,7 @@ public class Memory { public Bytes32 getWord(final UInt256 location) { final int start = asByteIndex(location); ensureCapacityForBytes(start, Bytes32.SIZE); - return Bytes32.wrap(Arrays.copyOfRange(data, start, start + Bytes32.SIZE)); + return Bytes32.wrap(data.slice(start, Bytes32.SIZE)); } /** @@ -376,12 +376,11 @@ public class Memory { public void setWord(final UInt256 location, final Bytes32 bytes) { final int start = asByteIndex(location); ensureCapacityForBytes(start, Bytes32.SIZE); - - System.arraycopy(bytes.toArrayUnsafe(), 0, data, start, Bytes32.SIZE); + data.set(start, bytes); } @Override public String toString() { - return Bytes.wrap(data).toHexString(); + return data.toHexString(); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/MessageFrame.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/MessageFrame.java index 7151848a60..ed0ae58077 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/MessageFrame.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/MessageFrame.java @@ -563,14 +563,25 @@ public class MessageFrame { } /** - * Read bytes in memory. + * Read bytes in memory as mutable. + * + * @param offset The offset in memory + * @param length The length of the bytes to read + * @return The bytes in the specified range + */ + public Bytes readMutableMemory(final UInt256 offset, final UInt256 length) { + return readMutableMemory(offset, length, false); + } + + /** + * Read bytes in memory . * * @param offset The offset in memory * @param length The length of the bytes to read * @return The bytes in the specified range */ public Bytes readMemory(final UInt256 offset, final UInt256 length) { - return readMemory(offset, length, false); + return readMutableMemory(offset, length, false).copy(); } /** @@ -581,7 +592,7 @@ public class MessageFrame { * @param explicitMemoryRead true if triggered by a memory opcode, false otherwise * @return The bytes in the specified range */ - public Bytes readMemory( + public Bytes readMutableMemory( final UInt256 offset, final UInt256 length, final boolean explicitMemoryRead) { final Bytes value = memory.getBytes(offset, length); if (explicitMemoryRead) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/AbstractCreateOperation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/AbstractCreateOperation.java index 7209bab4c4..4d213f8cbb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/AbstractCreateOperation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/AbstractCreateOperation.java @@ -96,7 +96,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation { private void fail(final MessageFrame frame) { final UInt256 inputOffset = frame.getStackItem(1); final UInt256 inputSize = frame.getStackItem(2); - frame.readMemory(inputOffset, inputSize); + frame.readMutableMemory(inputOffset, inputSize); frame.popStackItems(getStackItemsConsumed()); frame.pushStackItem(UInt256.ZERO); } @@ -114,7 +114,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation { final Wei value = Wei.wrap(frame.getStackItem(0)); final UInt256 inputOffset = frame.getStackItem(1); final UInt256 inputSize = frame.getStackItem(2); - final Bytes inputData = frame.readMemory(inputOffset, inputSize); + final Bytes inputData = frame.readMutableMemory(inputOffset, inputSize); final Address contractAddress = targetContractAddress(frame); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Create2Operation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Create2Operation.java index f14942c7d8..20f901666f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Create2Operation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Create2Operation.java @@ -38,7 +38,7 @@ public class Create2Operation extends AbstractCreateOperation { final UInt256 offset = frame.getStackItem(1); final UInt256 length = frame.getStackItem(2); final Bytes32 salt = frame.getStackItem(3); - final Bytes initCode = frame.readMemory(offset, length); + final Bytes initCode = frame.readMutableMemory(offset, length); final Hash hash = Hash.hash(Bytes.concatenate(PREFIX, sender, salt, Hash.hash(initCode))); final Address address = Address.extract(hash); frame.warmUpAddress(address); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/MLoadOperation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/MLoadOperation.java index 7a28f6a958..97d9e82f16 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/MLoadOperation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/MLoadOperation.java @@ -43,7 +43,8 @@ public class MLoadOperation extends AbstractOperation { } final UInt256 value = - UInt256.fromBytes(Bytes32.leftPad(frame.readMemory(location, UInt256.valueOf(32), true))); + UInt256.fromBytes( + Bytes32.leftPad(frame.readMutableMemory(location, UInt256.valueOf(32), true))); frame.pushStackItem(value); return new OperationResult(optionalCost, Optional.empty()); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Sha3Operation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Sha3Operation.java index 9325fc5e6c..47bec639f9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Sha3Operation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Sha3Operation.java @@ -44,7 +44,7 @@ public class Sha3Operation extends AbstractOperation { return new OperationResult(optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS)); } - final Bytes bytes = frame.readMemory(from, length); + final Bytes bytes = frame.readMutableMemory(from, length); frame.pushStackItem(UInt256.fromBytes(Hash.hash(bytes))); return new OperationResult(optionalCost, Optional.empty()); }