From f868ee5965dd0accfdecf8236aa628e65f8f628a Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 21 Feb 2022 11:35:58 -0700 Subject: [PATCH] Migrate JumpDestCache to CodeCache (#3472) Migrate the jump dest analysis cache into a more generic code cache that lives inside the EVM. This is in preparation for Ethereum Object Formats where a string of code may be treated differently depending on what EVM version is executing the code. Newer versions will also have difference analyses to run that will need different backing data structures. Signed-off-by: Danno Ferrin --- build.gradle | 2 +- .../results/tracing/vm/VmTraceGenerator.java | 2 +- .../mainnet/MainnetTransactionProcessor.java | 12 ++-- .../privacy/PrivateTransactionProcessor.java | 12 ++-- .../core/MessageFrameTestFixture.java | 3 +- .../besu/ethereum/core/TestCodeExecutor.java | 12 +++- .../hyperledger/besu/ethereum/vm/EVMTest.java | 4 +- .../vm/operations/Create2OperationTest.java | 10 +++- .../vm/operations/CreateOperationTest.java | 2 +- .../vm/operations/JumpOperationTest.java | 12 ++-- .../besu/evmtool/EvmToolCommand.java | 3 +- .../java/org/hyperledger/besu/evm/Code.java | 48 +++++++++------- .../java/org/hyperledger/besu/evm/EVM.java | 35 +++--------- .../besu/evm/fluent/EVMExecutor.java | 55 +++++++++---------- .../{JumpDestCache.java => CodeCache.java} | 13 +++-- .../besu/evm/internal/CodeScale.java | 7 ++- .../evm/operation/AbstractCallOperation.java | 11 ++-- .../operation/AbstractCreateOperation.java | 7 +-- .../besu/evm/operation/JumpOperation.java | 2 +- .../besu/evm/operation/JumpiOperation.java | 2 +- .../processor/AbstractMessageProcessor.java | 8 +++ ...pDestCacheTest.java => CodeCacheTest.java} | 15 +++-- .../besu/evm/precompile/Benchmarks.java | 2 +- .../besu/evm/toy/EvmToyCommand.java | 3 +- 24 files changed, 148 insertions(+), 134 deletions(-) rename evm/src/main/java/org/hyperledger/besu/evm/internal/{JumpDestCache.java => CodeCache.java} (82%) rename evm/src/test/java/org/hyperledger/besu/evm/internal/{JumpDestCacheTest.java => CodeCacheTest.java} (71%) diff --git a/build.gradle b/build.gradle index 8cdb4824d9..49d64892da 100644 --- a/build.gradle +++ b/build.gradle @@ -130,7 +130,7 @@ allprojects { java { // This path needs to be relative to each project target '**/*.java' - targetExclude '**/src/reference-test/**', '**/src/main/generated/**', '**/src/test/generated/**' + targetExclude '**/src/reference-test/**', '**/src/main/generated/**', '**/src/test/generated/**', '**/src/jmh/generated/**' removeUnusedImports() googleJavaFormat('1.10.0') importOrder 'org.hyperledger', 'java', '' diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/vm/VmTraceGenerator.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/vm/VmTraceGenerator.java index 1dd645ca8f..4d9dccb75e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/vm/VmTraceGenerator.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/vm/VmTraceGenerator.java @@ -288,7 +288,7 @@ public class VmTraceGenerator { // set smart contract code if (currentTrace != null && "0x".equals(currentTrace.getCode())) { currentTrace.setCode( - currentTraceFrame.getMaybeCode().orElse(new Code()).getBytes().toHexString()); + currentTraceFrame.getMaybeCode().orElse(Code.EMPTY_CODE).getBytes().toHexString()); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 1e22372396..e8e1856d8d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -36,7 +36,6 @@ import org.hyperledger.besu.evm.AccessListEntry; import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.AccountState; import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.MessageFrame; @@ -366,13 +365,16 @@ public class MainnetTransactionProcessor { final Address contractAddress = Address.contractAddress(senderAddress, senderMutableAccount.getNonce() - 1L); + final Bytes initCodeBytes = transaction.getPayload(); initialFrame = commonMessageFrameBuilder .type(MessageFrame.Type.CONTRACT_CREATION) .address(contractAddress) .contract(contractAddress) .inputData(Bytes.EMPTY) - .code(new Code(transaction.getPayload(), Hash.EMPTY)) + .code( + contractCreationProcessor.getCodeFromEVM( + Hash.hash(initCodeBytes), initCodeBytes)) .build(); } else { @SuppressWarnings("OptionalGetWithoutIsPresent") // isContractCall tests isPresent @@ -385,9 +387,9 @@ public class MainnetTransactionProcessor { .contract(to) .inputData(transaction.getPayload()) .code( - new Code( - maybeContract.map(AccountState::getCode).orElse(Bytes.EMPTY), - maybeContract.map(AccountState::getCodeHash).orElse(Hash.EMPTY))) + maybeContract + .map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode())) + .orElse(Code.EMPTY_CODE)) .build(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java index 6ea2f1e160..1f515398f4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java @@ -29,7 +29,6 @@ import org.hyperledger.besu.ethereum.worldstate.DefaultMutablePrivateWorldStateU import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.account.AccountState; import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.MessageFrame; @@ -151,13 +150,16 @@ public class PrivateTransactionProcessor { previousNonce, privacyGroupId.toString()); + final Bytes initCodeBytes = transaction.getPayload(); initialFrame = commonMessageFrameBuilder .type(MessageFrame.Type.CONTRACT_CREATION) .address(privateContractAddress) .contract(privateContractAddress) .inputData(Bytes.EMPTY) - .code(new Code(transaction.getPayload(), Hash.EMPTY)) + .code( + contractCreationProcessor.getCodeFromEVM( + Hash.hash(initCodeBytes), initCodeBytes)) .build(); } else { final Address to = transaction.getTo().get(); @@ -170,9 +172,9 @@ public class PrivateTransactionProcessor { .contract(to) .inputData(transaction.getPayload()) .code( - new Code( - maybeContract.map(AccountState::getCode).orElse(Bytes.EMPTY), - maybeContract.map(AccountState::getCodeHash).orElse(Hash.EMPTY))) + maybeContract + .map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode())) + .orElse(Code.EMPTY_CODE)) .build(); } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java index 395092cfb6..60bcf08fce 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java @@ -17,7 +17,6 @@ package org.hyperledger.besu.ethereum.core; import static org.hyperledger.besu.evm.frame.MessageFrame.DEFAULT_MAX_STACK_SIZE; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.vm.BlockHashLookup; @@ -52,7 +51,7 @@ public class MessageFrameTestFixture { private Wei gasPrice = Wei.ZERO; private Wei value = Wei.ZERO; private Bytes inputData = Bytes.EMPTY; - private Code code = new Code(Bytes.EMPTY, Hash.EMPTY); + private Code code = Code.EMPTY_CODE; private final List stackItems = new ArrayList<>(); private Optional blockHeader = Optional.empty(); private int depth = 0; diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java index 5a93faff16..acc7279bb4 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.Code; +import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.MessageFrame; @@ -49,14 +50,19 @@ public class TestCodeExecutor { } public MessageFrame executeCode( - final String code, final long gasLimit, final Consumer accountSetup) { + final String codeHexString, + final long gasLimit, + final Consumer accountSetup) { final ProtocolSpec protocolSpec = fixture.getProtocolSchedule().getByBlockNumber(0); final WorldUpdater worldUpdater = createInitialWorldState(accountSetup, fixture.getStateArchive()); final Deque messageFrameStack = new ArrayDeque<>(); + final EVM evm = protocolSpec.getEvm(); final MessageCallProcessor messageCallProcessor = - new MessageCallProcessor(protocolSpec.getEvm(), new PrecompileContractRegistry()); + new MessageCallProcessor(evm, new PrecompileContractRegistry()); + final Bytes codeBytes = Bytes.fromHexString(codeHexString); + final Code code = evm.getCode(Hash.hash(codeBytes), codeBytes); final Transaction transaction = Transaction.builder() @@ -85,7 +91,7 @@ public class TestCodeExecutor { .inputData(transaction.getPayload()) .sender(SENDER_ADDRESS) .value(transaction.getValue()) - .code(new Code(Bytes.fromHexString(code), Hash.EMPTY)) + .code(code) .blockHeader(blockHeader) .depth(0) .build(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EVMTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EVMTest.java index 420568c42e..829ee206ad 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EVMTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EVMTest.java @@ -50,7 +50,7 @@ public class EVMTest { @Test public void assertThatEndOfScriptNotExplicitlySetInCodeReturnsAVirtualOperation() { final Bytes noEnd = Bytes.fromHexString("0x60203560003555606035604035556000"); - final Code code = new Code(noEnd, Hash.hash(noEnd)); + final Code code = Code.createLegacyCode(noEnd, Hash.hash(noEnd)); final Operation operation = evm.operationAtOffset(code, code.getSize()); assertThat(operation).isNotNull(); assertThat(operation.isVirtualOperation()).isTrue(); @@ -59,7 +59,7 @@ public class EVMTest { @Test public void assertThatEndOfScriptExplicitlySetInCodeDoesNotReturnAVirtualOperation() { final Bytes ends = Bytes.fromHexString("0x6020356000355560603560403555600000"); - final Code code = new Code(ends, Hash.hash(ends)); + final Code code = Code.createLegacyCode(ends, Hash.hash(ends)); when(operationRegistry.get(anyByte())).thenReturn(new StopOperation(gasCalculator)); final Operation operation = evm.operationAtOffset(code, code.getSize() - 1); assertThat(operation).isNotNull(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/Create2OperationTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/Create2OperationTest.java index 94d3d85155..b59ad5d848 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/Create2OperationTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/Create2OperationTest.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.evm.Code; +import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.MessageFrame; @@ -56,6 +57,7 @@ public class Create2OperationTest { private final WorldUpdater worldUpdater = mock(WorldUpdater.class); private final WrappedEvmAccount account = mock(WrappedEvmAccount.class); private final MutableAccount mutableAccount = mock(MutableAccount.class); + private final EVM evm = mock(EVM.class); private final Create2Operation operation = new Create2Operation(new ConstantinopleGasCalculator()); @@ -141,7 +143,7 @@ public class Create2OperationTest { .sender(Address.fromHexString(sender)) .value(Wei.ZERO) .apparentValue(Wei.ZERO) - .code(new Code(codeBytes, Hash.hash(codeBytes))) + .code(Code.createLegacyCode(codeBytes, Hash.hash(codeBytes))) .depth(1) .completer(__ -> {}) .address(Address.fromHexString(sender)) @@ -164,6 +166,10 @@ public class Create2OperationTest { when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.updater()).thenReturn(worldUpdater); + when(evm.getCode(any(), any())) + .thenAnswer( + invocation -> + Code.createLegacyCode(invocation.getArgument(1), invocation.getArgument(0))); } @Test @@ -174,7 +180,7 @@ public class Create2OperationTest { @Test public void shouldCalculateGasPrice() { - final OperationResult result = operation.execute(messageFrame, null); + final OperationResult result = operation.execute(messageFrame, evm); assertThat(result.getHaltReason()).isEmpty(); assertThat(result.getGasCost()).contains(Gas.of(expectedGas)); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/CreateOperationTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/CreateOperationTest.java index b411c2e7b4..3873b585c7 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/CreateOperationTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/CreateOperationTest.java @@ -88,7 +88,7 @@ public class CreateOperationTest { .sender(Address.fromHexString(SENDER)) .value(Wei.ZERO) .apparentValue(Wei.ZERO) - .code(new Code(SIMPLE_CREATE, Hash.hash(SIMPLE_CREATE))) + .code(Code.createLegacyCode(SIMPLE_CREATE, Hash.hash(SIMPLE_CREATE))) .depth(1) .completer(__ -> {}) .address(Address.fromHexString(SENDER)) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/JumpOperationTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/JumpOperationTest.java index 725c26e5aa..7b526bda75 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/JumpOperationTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/JumpOperationTest.java @@ -96,7 +96,7 @@ public class JumpOperationTest { final MessageFrame frame = createMessageFrameBuilder(Gas.of(10_000)) .pushStackItem(UInt256.fromHexString("0x03")) - .code(new Code(jumpBytes, Hash.hash(jumpBytes))) + .code(Code.createLegacyCode(jumpBytes, Hash.hash(jumpBytes))) .build(); frame.setPC(CURRENT_PC); @@ -111,7 +111,7 @@ public class JumpOperationTest { final MessageFrame frame = createMessageFrameBuilder(Gas.of(10_000)) .pushStackItem(UInt256.fromHexString("0x03")) - .code(new Code(jumpBytes, Hash.hash(jumpBytes))) + .code(Code.createLegacyCode(jumpBytes, Hash.hash(jumpBytes))) .build(); frame.setPC(CURRENT_PC); @@ -126,7 +126,7 @@ public class JumpOperationTest { final MessageFrame frameDestinationGreaterThanCodeSize = createMessageFrameBuilder(Gas.of(100)) .pushStackItem(UInt256.fromHexString("0xFFFFFFFF")) - .code(new Code(jumpBytes, Hash.hash(jumpBytes))) + .code(Code.createLegacyCode(jumpBytes, Hash.hash(jumpBytes))) .build(); frameDestinationGreaterThanCodeSize.setPC(CURRENT_PC); @@ -136,7 +136,7 @@ public class JumpOperationTest { final MessageFrame frameDestinationEqualsToCodeSize = createMessageFrameBuilder(Gas.of(100)) .pushStackItem(UInt256.fromHexString("0x04")) - .code(new Code(badJump, Hash.hash(badJump))) + .code(Code.createLegacyCode(badJump, Hash.hash(badJump))) .build(); frameDestinationEqualsToCodeSize.setPC(CURRENT_PC); @@ -154,7 +154,7 @@ public class JumpOperationTest { final MessageFrame longContract = createMessageFrameBuilder(Gas.of(100)) .pushStackItem(UInt256.fromHexString("0x12c")) - .code(new Code(longCode, Hash.hash(longCode))) + .code(Code.createLegacyCode(longCode, Hash.hash(longCode))) .build(); longContract.setPC(255); @@ -166,7 +166,7 @@ public class JumpOperationTest { public void shouldReuseJumpDestMap() { final JumpOperation operation = new JumpOperation(gasCalculator); final Bytes jumpBytes = Bytes.fromHexString("0x6003565b00"); - Code getsCached = spy(new Code(jumpBytes, Hash.hash(jumpBytes))); + Code getsCached = spy(Code.createLegacyCode(jumpBytes, Hash.hash(jumpBytes))); MessageFrame frame = createMessageFrameBuilder(Gas.of(10_000)) .pushStackItem(UInt256.fromHexString("0x03")) 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 0ba1adb9d2..1eb34545c7 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 @@ -213,6 +213,7 @@ public class EvmToolCommand implements Runnable { final PrecompileContractRegistry precompileContractRegistry = protocolSpec.getPrecompileContractRegistry(); final EVM evm = protocolSpec.getEvm(); + Code code = evm.getCode(Hash.hash(codeHexString), codeHexString); final Stopwatch stopwatch = Stopwatch.createUnstarted(); long lastTime = 0; do { @@ -242,7 +243,7 @@ public class EvmToolCommand implements Runnable { .inputData(callData) .value(ethValue) .apparentValue(ethValue) - .code(new Code(codeHexString, Hash.hash(codeHexString))) + .code(code) .blockValues(blockHeader) .depth(0) .completer(c -> {}) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/Code.java b/evm/src/main/java/org/hyperledger/besu/evm/Code.java index de8f963b30..8573afbb6e 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/Code.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/Code.java @@ -19,11 +19,14 @@ import org.hyperledger.besu.evm.operation.JumpDestOperation; import org.hyperledger.besu.evm.operation.PushOperation; import com.google.common.base.MoreObjects; +import com.google.errorprone.annotations.RestrictedApi; import org.apache.tuweni.bytes.Bytes; /** Represents EVM code associated with an account. */ public class Code { + public static final Code EMPTY_CODE = new Code(Bytes.EMPTY, Hash.EMPTY); + /** The bytes representing the code. */ private final Bytes bytes; @@ -42,19 +45,17 @@ public class Code { * @param bytes The byte representation of the code. * @param codeHash the Hash of the bytes in the code. */ - public Code(final Bytes bytes, final Hash codeHash) { + protected Code(final Bytes bytes, final Hash codeHash) { this.bytes = bytes; this.codeHash = codeHash; } - public Code(final Bytes bytecode, final Hash codeHash, final long[] validJumpDestinations) { - this.bytes = bytecode; - this.validJumpDestinations = validJumpDestinations; - this.codeHash = codeHash; - } - - public Code() { - this(Bytes.EMPTY, Hash.EMPTY); + @RestrictedApi( + explanation = "To be used for testing purpose only", + link = "", + allowedOnPath = ".*/src/test/.*") + public static Code createLegacyCode(final Bytes bytes, final Hash codeHash) { + return new Code(bytes, codeHash); } /** @@ -88,24 +89,24 @@ public class Code { } public long[] calculateJumpDests() { - int size = getSize(); - long[] bitmap = new long[(size >> 6) + 1]; - byte[] rawCode = getBytes().toArrayUnsafe(); - int length = rawCode.length; + final int size = getSize(); + final long[] bitmap = new long[(size >> 6) + 1]; + final byte[] rawCode = getBytes().toArrayUnsafe(); + final int length = rawCode.length; for (int i = 0; i < length; ) { long thisEntry = 0L; - int entryPos = i >> 6; - int max = Math.min(64, length - (entryPos << 6)); + final int entryPos = i >> 6; + final int max = Math.min(64, length - (entryPos << 6)); int j = i & 0x3F; for (; j < max; i++, j++) { - byte operationNum = rawCode[i]; + final byte operationNum = rawCode[i]; if (operationNum == JumpDestOperation.OPCODE) { thisEntry |= 1L << j; } else if (operationNum > PushOperation.PUSH_BASE) { // not needed - && operationNum <= PushOperation.PUSH_MAX // Java quirk, all bytes are signed, and PUSH32 is 127, which is Byte.MAX_VALUE // so we don't need to check the upper bound as it will never be violated - int multiByteDataLen = operationNum - PushOperation.PUSH_BASE; + final int multiByteDataLen = operationNum - PushOperation.PUSH_BASE; j += multiByteDataLen; i += multiByteDataLen; } @@ -129,7 +130,16 @@ public class Code { return codeHash; } - public long[] getValidJumpDestinations() { - return validJumpDestinations; + public boolean isJumpDestInvalid(final int jumpDestination) { + if (jumpDestination < 0 || jumpDestination >= getSize()) { + return true; + } + if (validJumpDestinations == null || validJumpDestinations.length == 0) { + validJumpDestinations = calculateJumpDests(); + } + + final long targetLong = validJumpDestinations[jumpDestination >>> 6]; + final long targetBit = 1L << (jumpDestination & 0x3F); + return (targetLong & targetBit) == 0L; } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/EVM.java b/evm/src/main/java/org/hyperledger/besu/evm/EVM.java index dbc312af8b..fbd277bd29 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/EVM.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/EVM.java @@ -19,10 +19,10 @@ import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame.State; import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.internal.CodeCache; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.FixedStack.OverflowException; import org.hyperledger.besu.evm.internal.FixedStack.UnderflowException; -import org.hyperledger.besu.evm.internal.JumpDestCache; import org.hyperledger.besu.evm.operation.InvalidOperation; import org.hyperledger.besu.evm.operation.Operation; import org.hyperledger.besu.evm.operation.Operation.OperationResult; @@ -51,7 +51,7 @@ public class EVM { private final OperationRegistry operations; private final GasCalculator gasCalculator; private final Operation endOfScriptStop; - private final JumpDestCache jumpDestCache; + private final CodeCache codeCache; public EVM( final OperationRegistry operations, @@ -60,7 +60,7 @@ public class EVM { this.operations = operations; this.gasCalculator = gasCalculator; this.endOfScriptStop = new VirtualOperation(new StopOperation(gasCalculator)); - this.jumpDestCache = new JumpDestCache(evmConfiguration); + this.codeCache = new CodeCache(evmConfiguration); } public GasCalculator getGasCalculator() { @@ -142,29 +142,12 @@ public class EVM { } } - /** - * Determine whether a specified destination is a valid jump target. - * - * @param jumpDestination The destination we're checking for validity. - * @param code The code within which we are looking for the destination. - * @return Whether or not this location is a valid jump destination. - */ - public boolean isValidJumpDestination(final int jumpDestination, final Code code) { - if (jumpDestination < 0 || jumpDestination >= code.getSize()) return false; - long[] validJumpDestinations = code.getValidJumpDestinations(); - if (validJumpDestinations == null || validJumpDestinations.length == 0) { - validJumpDestinations = jumpDestCache.getIfPresent(code.getCodeHash()); - if (validJumpDestinations == null) { - validJumpDestinations = code.calculateJumpDests(); - if (code.getCodeHash() != null && !code.getCodeHash().equals(Hash.EMPTY)) { - jumpDestCache.put(code.getCodeHash(), validJumpDestinations); - } else { - LOG.debug("not caching jumpdest for unhashed contract code"); - } - } + public Code getCode(final Hash codeHash, final Bytes codeBytes) { + Code result = codeCache.getIfPresent(codeHash); + if (result == null) { + result = new Code(codeBytes, codeHash); + codeCache.put(codeHash, result); } - long targetLong = validJumpDestinations[jumpDestination >>> 6]; - long targetBit = 1L << (jumpDestination & 0x3F); - return (targetLong & targetBit) != 0L; + return result; } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java index fac5b613f9..c86bb2be01 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.evm.fluent; +import static com.google.common.base.Preconditions.checkNotNull; + import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -48,8 +50,8 @@ import org.apache.tuweni.bytes.Bytes32; public class EVMExecutor { + private final EVM evm; private PrecompileContractRegistry precompileContractRegistry; - private EVM evm; private boolean commitWorldState = false; private WorldUpdater worldUpdater = new SimpleWorld(); private Gas gas = Gas.MAX_VALUE; @@ -58,7 +60,7 @@ public class EVMExecutor { private Wei gasPriceGWei = Wei.ZERO; private Bytes callData = Bytes.EMPTY; private Wei ethValue = Wei.ZERO; - private Code code = new Code(Bytes.EMPTY, Hash.EMPTY); + private Code code = Code.EMPTY_CODE; private BlockValues blockValues = new SimpleBlockValues(); private OperationTracer tracer = OperationTracer.NO_TRACING; private boolean requireDeposit = true; @@ -71,15 +73,17 @@ public class EVMExecutor { private MessageCallProcessor messageCallProcessor = null; private ContractCreationProcessor contractCreationProcessor = null; + private EVMExecutor(final EVM evm) { + checkNotNull(evm, "evm must not be null"); + this.evm = evm; + } + public static EVMExecutor evm(final EVM evm) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = evm; - return executor; + return new EVMExecutor(evm); } public static EVMExecutor frontier(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.frontier(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.frontier(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(); @@ -89,8 +93,7 @@ public class EVMExecutor { } public static EVMExecutor homestead(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.homestead(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.homestead(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(); @@ -99,8 +102,7 @@ public class EVMExecutor { } public static EVMExecutor spuriousDragon(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.spuriousDragon(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.spuriousDragon(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); @@ -108,8 +110,7 @@ public class EVMExecutor { } public static EVMExecutor tangerineWhistle(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.tangerineWhistle(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.tangerineWhistle(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); @@ -117,8 +118,7 @@ public class EVMExecutor { } public static EVMExecutor byzantium(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.byzantium(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.byzantium(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); @@ -126,8 +126,7 @@ public class EVMExecutor { } public static EVMExecutor constantinople(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.constantinople(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.constantinople(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); @@ -135,8 +134,7 @@ public class EVMExecutor { } public static EVMExecutor petersburg(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.petersburg(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.petersburg(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); @@ -144,8 +142,7 @@ public class EVMExecutor { } public static EVMExecutor istanbul(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.istanbul(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.istanbul(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); @@ -153,8 +150,7 @@ public class EVMExecutor { } public static EVMExecutor berlin(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.berlin(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.berlin(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); @@ -162,8 +158,7 @@ public class EVMExecutor { } public static EVMExecutor london(final EvmConfiguration evmConfiguration) { - EVMExecutor executor = new EVMExecutor(); - executor.evm = MainnetEVMs.istanbul(evmConfiguration); + final EVMExecutor executor = new EVMExecutor(MainnetEVMs.london(evmConfiguration)); executor.precompileContractRegistry = MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); return executor; @@ -198,7 +193,7 @@ public class EVMExecutor { public Bytes execute( final Bytes codeBytes, final Bytes inputData, final Wei value, final Address receiver) { - this.code = new Code(codeBytes, Hash.EMPTY); + this.code = evm.getCode(Hash.hash(codeBytes), codeBytes); this.callData = inputData; this.ethValue = value; this.receiver = receiver; @@ -206,10 +201,10 @@ public class EVMExecutor { } public Bytes execute() { - MessageCallProcessor mcp = thisMessageCallProcessor(); - ContractCreationProcessor ccp = thisContractCreationProcessor(); + final MessageCallProcessor mcp = thisMessageCallProcessor(); + final ContractCreationProcessor ccp = thisContractCreationProcessor(); final Deque messageFrameStack = new ArrayDeque<>(); - MessageFrame initialMessageFrame = + final MessageFrame initialMessageFrame = MessageFrame.builder() .type(MessageFrame.Type.MESSAGE_CALL) .messageFrameStack(messageFrameStack) @@ -302,7 +297,7 @@ public class EVMExecutor { } public EVMExecutor code(final Bytes codeBytes, final Hash hash) { - this.code = new Code(codeBytes, hash); + this.code = evm.getCode(hash, codeBytes); return this; } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/internal/JumpDestCache.java b/evm/src/main/java/org/hyperledger/besu/evm/internal/CodeCache.java similarity index 82% rename from evm/src/main/java/org/hyperledger/besu/evm/internal/JumpDestCache.java rename to evm/src/main/java/org/hyperledger/besu/evm/internal/CodeCache.java index 1b3acf64f5..f74f510e4a 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/internal/JumpDestCache.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/internal/CodeCache.java @@ -16,20 +16,21 @@ package org.hyperledger.besu.evm.internal; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.evm.Code; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -public class JumpDestCache { +public class CodeCache { - private final Cache cache; + private final Cache cache; private final long weightLimit; - public JumpDestCache(final EvmConfiguration config) { + public CodeCache(final EvmConfiguration config) { this(config.getJumpDestCacheWeightBytes()); } - private JumpDestCache(final long maxWeightBytes) { + private CodeCache(final long maxWeightBytes) { this.weightLimit = maxWeightBytes; this.cache = Caffeine.newBuilder().maximumWeight(maxWeightBytes).weigher(new CodeScale()).build(); @@ -43,11 +44,11 @@ public class JumpDestCache { this.cache.cleanUp(); } - public long[] getIfPresent(final Hash codeHash) { + public Code getIfPresent(final Hash codeHash) { return cache.getIfPresent(codeHash); } - public void put(final Hash key, final long[] value) { + public void put(final Hash key, final Code value) { cache.put(key, value); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/internal/CodeScale.java b/evm/src/main/java/org/hyperledger/besu/evm/internal/CodeScale.java index 62f9600c96..cd736c3d57 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/internal/CodeScale.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/internal/CodeScale.java @@ -16,12 +16,13 @@ package org.hyperledger.besu.evm.internal; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.evm.Code; import com.github.benmanes.caffeine.cache.Weigher; -class CodeScale implements Weigher { +class CodeScale implements Weigher { @Override - public int weigh(final Hash key, final long[] value) { - return (value.length * 8) + key.size(); + public int weigh(final Hash key, final Code code) { + return ((code.getSize() * 9 + 7) / 8) + key.size(); } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java index be4bdb8011..03f6345272 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.evm.operation; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.EVM; @@ -185,6 +184,11 @@ public abstract class AbstractCallOperation extends AbstractOperation { final Bytes inputData = frame.readMutableMemory(inputDataOffset(frame), inputDataLength(frame)); + final Code code = + contract == null + ? Code.EMPTY_CODE + : evm.getCode(contract.getCodeHash(), contract.getCode()); + final MessageFrame childFrame = MessageFrame.builder() .type(MessageFrame.Type.MESSAGE_CALL) @@ -199,10 +203,7 @@ public abstract class AbstractCallOperation extends AbstractOperation { .sender(sender(frame)) .value(value(frame)) .apparentValue(apparentValue(frame)) - .code( - new Code( - contract != null ? contract.getCode() : Bytes.EMPTY, - contract != null ? contract.getCodeHash() : Hash.EMPTY)) + .code(code) .blockValues(frame.getBlockValues()) .depth(frame.getMessageStackDepth() + 1) .isStatic(isStatic(frame)) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java index 08c627fc60..df3d4f53da 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java @@ -19,7 +19,6 @@ import static org.hyperledger.besu.evm.internal.Words.clampedToLong; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.account.MutableAccount; @@ -76,7 +75,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation { if (value.compareTo(account.getBalance()) > 0 || frame.getMessageStackDepth() >= 1024) { fail(frame); } else { - spawnChildMessage(frame); + spawnChildMessage(frame, evm); } } @@ -95,7 +94,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation { frame.pushStackItem(UInt256.ZERO); } - private void spawnChildMessage(final MessageFrame frame) { + private void spawnChildMessage(final MessageFrame frame, final EVM evm) { // memory cost needs to be calculated prior to memory expansion final Gas cost = cost(frame); frame.decrementRemainingGas(cost); @@ -129,7 +128,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation { .sender(frame.getRecipientAddress()) .value(value) .apparentValue(value) - .code(new Code(inputData, Hash.EMPTY)) + .code(evm.getCode(Hash.hash(inputData), inputData)) .blockValues(frame.getBlockValues()) .depth(frame.getMessageStackDepth() + 1) .completer(child -> complete(frame, child)) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/JumpOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/JumpOperation.java index a769da3e4b..f2855cd9fe 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/JumpOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/JumpOperation.java @@ -48,7 +48,7 @@ public class JumpOperation extends AbstractFixedCostOperation { return invalidJumpResponse; } final Code code = frame.getCode(); - if (!evm.isValidJumpDestination(jumpDestination, code)) { + if (code.isJumpDestInvalid(jumpDestination)) { return invalidJumpResponse; } else { frame.setPC(jumpDestination); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/JumpiOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/JumpiOperation.java index 9c4aa8e28b..29f43effaa 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/JumpiOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/JumpiOperation.java @@ -53,7 +53,7 @@ public class JumpiOperation extends AbstractFixedCostOperation { return invalidJumpResponse; } final Code code = frame.getCode(); - if (!evm.isValidJumpDestination(jumpDestination, code)) { + if (code.isJumpDestInvalid(jumpDestination)) { return invalidJumpResponse; } frame.setPC(jumpDestination); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java index 3dd298e07f..b2f0f64b5f 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java @@ -15,6 +15,8 @@ package org.hyperledger.besu.evm.processor; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.ModificationNotAllowedException; import org.hyperledger.besu.evm.account.Account; @@ -26,6 +28,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.stream.Collectors; +import org.apache.tuweni.bytes.Bytes; + /** * A skeletal class for instantiating message processors. * @@ -193,4 +197,8 @@ public abstract class AbstractMessageProcessor { completedFailed(frame); } } + + public Code getCodeFromEVM(final Hash codeHash, final Bytes codeBytes) { + return evm.getCode(codeHash, codeBytes); + } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/internal/JumpDestCacheTest.java b/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java similarity index 71% rename from evm/src/test/java/org/hyperledger/besu/evm/internal/JumpDestCacheTest.java rename to evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java index a590e7c627..37ae1e4115 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/internal/JumpDestCacheTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java @@ -24,19 +24,18 @@ import org.hyperledger.besu.evm.operation.JumpDestOperation; import org.apache.tuweni.bytes.Bytes; import org.junit.Test; -public class JumpDestCacheTest { +public class CodeCacheTest { private final String op = Bytes.of(JumpDestOperation.OPCODE).toUnprefixedHexString(); @Test public void testScale() { - Bytes contractBytes = + final Bytes contractBytes = Bytes.fromHexString("0xDEAD" + op + "BEEF" + op + "B0B0" + op + "C0DE" + op + "FACE"); - // 3rd bit, 6th bit, 9th bit, 12th bit - long[] jumpDests = {4 + 32 + 256 + 2048}; - CodeScale scale = new CodeScale(); - Code contractCode = new Code(contractBytes, Hash.hash(contractBytes), jumpDests); - int weight = scale.weigh(contractCode.getCodeHash(), contractCode.getValidJumpDestinations()); - assertThat(weight).isEqualTo(contractCode.getCodeHash().size() + jumpDests.length * 8); + final CodeScale scale = new CodeScale(); + final Code contractCode = Code.createLegacyCode(contractBytes, Hash.hash(contractBytes)); + final int weight = scale.weigh(contractCode.getCodeHash(), contractCode); + assertThat(weight) + .isEqualTo(contractCode.getCodeHash().size() + (contractBytes.size() * 9 + 7) / 8); } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java b/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java index a985bd3309..0ecd568c83 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java @@ -66,7 +66,7 @@ public class Benchmarks { .sender(Address.ZERO) .value(Wei.ZERO) .apparentValue(Wei.ZERO) - .code(new Code(Bytes.EMPTY, org.hyperledger.besu.datatypes.Hash.EMPTY)) + .code(Code.EMPTY_CODE) .depth(1) .completer(__ -> {}) .address(Address.ZERO) 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 243e211fe3..89ed4c7cce 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 @@ -144,6 +144,7 @@ public class EvmToyCommand implements Runnable { int repeat = this.repeat; final EVM evm = MainnetEVMs.berlin(EvmConfiguration.DEFAULT); + final Code code = evm.getCode(Hash.hash(codeBytes), codeBytes); final PrecompileContractRegistry precompileContractRegistry = new PrecompileContractRegistry(); MainnetPrecompiledContracts.populateForIstanbul( precompileContractRegistry, evm.getGasCalculator()); @@ -172,7 +173,7 @@ public class EvmToyCommand implements Runnable { .inputData(callData) .value(ethValue) .apparentValue(ethValue) - .code(new Code(codeBytes, Hash.hash(codeBytes))) + .code(code) .blockValues(new ToyBlockValues()) .depth(0) .completer(c -> {})