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 <danno.ferrin@gmail.com>
pull/3391/head
Danno Ferrin 3 years ago committed by GitHub
parent 435c9e388c
commit f868ee5965
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      build.gradle
  2. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/vm/VmTraceGenerator.java
  3. 12
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
  4. 12
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java
  5. 3
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/MessageFrameTestFixture.java
  6. 12
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TestCodeExecutor.java
  7. 4
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EVMTest.java
  8. 10
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/Create2OperationTest.java
  9. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/CreateOperationTest.java
  10. 12
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/JumpOperationTest.java
  11. 3
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java
  12. 48
      evm/src/main/java/org/hyperledger/besu/evm/Code.java
  13. 35
      evm/src/main/java/org/hyperledger/besu/evm/EVM.java
  14. 55
      evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java
  15. 13
      evm/src/main/java/org/hyperledger/besu/evm/internal/CodeCache.java
  16. 7
      evm/src/main/java/org/hyperledger/besu/evm/internal/CodeScale.java
  17. 11
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java
  18. 7
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java
  19. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/JumpOperation.java
  20. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/JumpiOperation.java
  21. 8
      evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java
  22. 15
      evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java
  23. 2
      evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java
  24. 3
      evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java

@ -130,7 +130,7 @@ allprojects {
java { java {
// This path needs to be relative to each project // This path needs to be relative to each project
target '**/*.java' 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() removeUnusedImports()
googleJavaFormat('1.10.0') googleJavaFormat('1.10.0')
importOrder 'org.hyperledger', 'java', '' importOrder 'org.hyperledger', 'java', ''

@ -288,7 +288,7 @@ public class VmTraceGenerator {
// set smart contract code // set smart contract code
if (currentTrace != null && "0x".equals(currentTrace.getCode())) { if (currentTrace != null && "0x".equals(currentTrace.getCode())) {
currentTrace.setCode( currentTrace.setCode(
currentTraceFrame.getMaybeCode().orElse(new Code()).getBytes().toHexString()); currentTraceFrame.getMaybeCode().orElse(Code.EMPTY_CODE).getBytes().toHexString());
} }
} }

@ -36,7 +36,6 @@ import org.hyperledger.besu.evm.AccessListEntry;
import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.account.Account; 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.EvmAccount;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
@ -366,13 +365,16 @@ public class MainnetTransactionProcessor {
final Address contractAddress = final Address contractAddress =
Address.contractAddress(senderAddress, senderMutableAccount.getNonce() - 1L); Address.contractAddress(senderAddress, senderMutableAccount.getNonce() - 1L);
final Bytes initCodeBytes = transaction.getPayload();
initialFrame = initialFrame =
commonMessageFrameBuilder commonMessageFrameBuilder
.type(MessageFrame.Type.CONTRACT_CREATION) .type(MessageFrame.Type.CONTRACT_CREATION)
.address(contractAddress) .address(contractAddress)
.contract(contractAddress) .contract(contractAddress)
.inputData(Bytes.EMPTY) .inputData(Bytes.EMPTY)
.code(new Code(transaction.getPayload(), Hash.EMPTY)) .code(
contractCreationProcessor.getCodeFromEVM(
Hash.hash(initCodeBytes), initCodeBytes))
.build(); .build();
} else { } else {
@SuppressWarnings("OptionalGetWithoutIsPresent") // isContractCall tests isPresent @SuppressWarnings("OptionalGetWithoutIsPresent") // isContractCall tests isPresent
@ -385,9 +387,9 @@ public class MainnetTransactionProcessor {
.contract(to) .contract(to)
.inputData(transaction.getPayload()) .inputData(transaction.getPayload())
.code( .code(
new Code( maybeContract
maybeContract.map(AccountState::getCode).orElse(Bytes.EMPTY), .map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode()))
maybeContract.map(AccountState::getCodeHash).orElse(Hash.EMPTY))) .orElse(Code.EMPTY_CODE))
.build(); .build();
} }

@ -29,7 +29,6 @@ import org.hyperledger.besu.ethereum.worldstate.DefaultMutablePrivateWorldStateU
import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.account.Account; 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.EvmAccount;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
@ -151,13 +150,16 @@ public class PrivateTransactionProcessor {
previousNonce, previousNonce,
privacyGroupId.toString()); privacyGroupId.toString());
final Bytes initCodeBytes = transaction.getPayload();
initialFrame = initialFrame =
commonMessageFrameBuilder commonMessageFrameBuilder
.type(MessageFrame.Type.CONTRACT_CREATION) .type(MessageFrame.Type.CONTRACT_CREATION)
.address(privateContractAddress) .address(privateContractAddress)
.contract(privateContractAddress) .contract(privateContractAddress)
.inputData(Bytes.EMPTY) .inputData(Bytes.EMPTY)
.code(new Code(transaction.getPayload(), Hash.EMPTY)) .code(
contractCreationProcessor.getCodeFromEVM(
Hash.hash(initCodeBytes), initCodeBytes))
.build(); .build();
} else { } else {
final Address to = transaction.getTo().get(); final Address to = transaction.getTo().get();
@ -170,9 +172,9 @@ public class PrivateTransactionProcessor {
.contract(to) .contract(to)
.inputData(transaction.getPayload()) .inputData(transaction.getPayload())
.code( .code(
new Code( maybeContract
maybeContract.map(AccountState::getCode).orElse(Bytes.EMPTY), .map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode()))
maybeContract.map(AccountState::getCodeHash).orElse(Hash.EMPTY))) .orElse(Code.EMPTY_CODE))
.build(); .build();
} }

@ -17,7 +17,6 @@ package org.hyperledger.besu.ethereum.core;
import static org.hyperledger.besu.evm.frame.MessageFrame.DEFAULT_MAX_STACK_SIZE; import static org.hyperledger.besu.evm.frame.MessageFrame.DEFAULT_MAX_STACK_SIZE;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
@ -52,7 +51,7 @@ public class MessageFrameTestFixture {
private Wei gasPrice = Wei.ZERO; private Wei gasPrice = Wei.ZERO;
private Wei value = Wei.ZERO; private Wei value = Wei.ZERO;
private Bytes inputData = Bytes.EMPTY; private Bytes inputData = Bytes.EMPTY;
private Code code = new Code(Bytes.EMPTY, Hash.EMPTY); private Code code = Code.EMPTY_CODE;
private final List<UInt256> stackItems = new ArrayList<>(); private final List<UInt256> stackItems = new ArrayList<>();
private Optional<BlockHeader> blockHeader = Optional.empty(); private Optional<BlockHeader> blockHeader = Optional.empty();
private int depth = 0; private int depth = 0;

@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
@ -49,14 +50,19 @@ public class TestCodeExecutor {
} }
public MessageFrame executeCode( public MessageFrame executeCode(
final String code, final long gasLimit, final Consumer<MutableAccount> accountSetup) { final String codeHexString,
final long gasLimit,
final Consumer<MutableAccount> accountSetup) {
final ProtocolSpec protocolSpec = fixture.getProtocolSchedule().getByBlockNumber(0); final ProtocolSpec protocolSpec = fixture.getProtocolSchedule().getByBlockNumber(0);
final WorldUpdater worldUpdater = final WorldUpdater worldUpdater =
createInitialWorldState(accountSetup, fixture.getStateArchive()); createInitialWorldState(accountSetup, fixture.getStateArchive());
final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>(); final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
final EVM evm = protocolSpec.getEvm();
final MessageCallProcessor messageCallProcessor = 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 = final Transaction transaction =
Transaction.builder() Transaction.builder()
@ -85,7 +91,7 @@ public class TestCodeExecutor {
.inputData(transaction.getPayload()) .inputData(transaction.getPayload())
.sender(SENDER_ADDRESS) .sender(SENDER_ADDRESS)
.value(transaction.getValue()) .value(transaction.getValue())
.code(new Code(Bytes.fromHexString(code), Hash.EMPTY)) .code(code)
.blockHeader(blockHeader) .blockHeader(blockHeader)
.depth(0) .depth(0)
.build(); .build();

@ -50,7 +50,7 @@ public class EVMTest {
@Test @Test
public void assertThatEndOfScriptNotExplicitlySetInCodeReturnsAVirtualOperation() { public void assertThatEndOfScriptNotExplicitlySetInCodeReturnsAVirtualOperation() {
final Bytes noEnd = Bytes.fromHexString("0x60203560003555606035604035556000"); 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()); final Operation operation = evm.operationAtOffset(code, code.getSize());
assertThat(operation).isNotNull(); assertThat(operation).isNotNull();
assertThat(operation.isVirtualOperation()).isTrue(); assertThat(operation.isVirtualOperation()).isTrue();
@ -59,7 +59,7 @@ public class EVMTest {
@Test @Test
public void assertThatEndOfScriptExplicitlySetInCodeDoesNotReturnAVirtualOperation() { public void assertThatEndOfScriptExplicitlySetInCodeDoesNotReturnAVirtualOperation() {
final Bytes ends = Bytes.fromHexString("0x6020356000355560603560403555600000"); 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)); when(operationRegistry.get(anyByte())).thenReturn(new StopOperation(gasCalculator));
final Operation operation = evm.operationAtOffset(code, code.getSize() - 1); final Operation operation = evm.operationAtOffset(code, code.getSize() - 1);
assertThat(operation).isNotNull(); assertThat(operation).isNotNull();

@ -25,6 +25,7 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
@ -56,6 +57,7 @@ public class Create2OperationTest {
private final WorldUpdater worldUpdater = mock(WorldUpdater.class); private final WorldUpdater worldUpdater = mock(WorldUpdater.class);
private final WrappedEvmAccount account = mock(WrappedEvmAccount.class); private final WrappedEvmAccount account = mock(WrappedEvmAccount.class);
private final MutableAccount mutableAccount = mock(MutableAccount.class); private final MutableAccount mutableAccount = mock(MutableAccount.class);
private final EVM evm = mock(EVM.class);
private final Create2Operation operation = private final Create2Operation operation =
new Create2Operation(new ConstantinopleGasCalculator()); new Create2Operation(new ConstantinopleGasCalculator());
@ -141,7 +143,7 @@ public class Create2OperationTest {
.sender(Address.fromHexString(sender)) .sender(Address.fromHexString(sender))
.value(Wei.ZERO) .value(Wei.ZERO)
.apparentValue(Wei.ZERO) .apparentValue(Wei.ZERO)
.code(new Code(codeBytes, Hash.hash(codeBytes))) .code(Code.createLegacyCode(codeBytes, Hash.hash(codeBytes)))
.depth(1) .depth(1)
.completer(__ -> {}) .completer(__ -> {})
.address(Address.fromHexString(sender)) .address(Address.fromHexString(sender))
@ -164,6 +166,10 @@ public class Create2OperationTest {
when(mutableAccount.getBalance()).thenReturn(Wei.ZERO); when(mutableAccount.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account); when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater); when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any()))
.thenAnswer(
invocation ->
Code.createLegacyCode(invocation.getArgument(1), invocation.getArgument(0)));
} }
@Test @Test
@ -174,7 +180,7 @@ public class Create2OperationTest {
@Test @Test
public void shouldCalculateGasPrice() { public void shouldCalculateGasPrice() {
final OperationResult result = operation.execute(messageFrame, null); final OperationResult result = operation.execute(messageFrame, evm);
assertThat(result.getHaltReason()).isEmpty(); assertThat(result.getHaltReason()).isEmpty();
assertThat(result.getGasCost()).contains(Gas.of(expectedGas)); assertThat(result.getGasCost()).contains(Gas.of(expectedGas));
} }

@ -88,7 +88,7 @@ public class CreateOperationTest {
.sender(Address.fromHexString(SENDER)) .sender(Address.fromHexString(SENDER))
.value(Wei.ZERO) .value(Wei.ZERO)
.apparentValue(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) .depth(1)
.completer(__ -> {}) .completer(__ -> {})
.address(Address.fromHexString(SENDER)) .address(Address.fromHexString(SENDER))

@ -96,7 +96,7 @@ public class JumpOperationTest {
final MessageFrame frame = final MessageFrame frame =
createMessageFrameBuilder(Gas.of(10_000)) createMessageFrameBuilder(Gas.of(10_000))
.pushStackItem(UInt256.fromHexString("0x03")) .pushStackItem(UInt256.fromHexString("0x03"))
.code(new Code(jumpBytes, Hash.hash(jumpBytes))) .code(Code.createLegacyCode(jumpBytes, Hash.hash(jumpBytes)))
.build(); .build();
frame.setPC(CURRENT_PC); frame.setPC(CURRENT_PC);
@ -111,7 +111,7 @@ public class JumpOperationTest {
final MessageFrame frame = final MessageFrame frame =
createMessageFrameBuilder(Gas.of(10_000)) createMessageFrameBuilder(Gas.of(10_000))
.pushStackItem(UInt256.fromHexString("0x03")) .pushStackItem(UInt256.fromHexString("0x03"))
.code(new Code(jumpBytes, Hash.hash(jumpBytes))) .code(Code.createLegacyCode(jumpBytes, Hash.hash(jumpBytes)))
.build(); .build();
frame.setPC(CURRENT_PC); frame.setPC(CURRENT_PC);
@ -126,7 +126,7 @@ public class JumpOperationTest {
final MessageFrame frameDestinationGreaterThanCodeSize = final MessageFrame frameDestinationGreaterThanCodeSize =
createMessageFrameBuilder(Gas.of(100)) createMessageFrameBuilder(Gas.of(100))
.pushStackItem(UInt256.fromHexString("0xFFFFFFFF")) .pushStackItem(UInt256.fromHexString("0xFFFFFFFF"))
.code(new Code(jumpBytes, Hash.hash(jumpBytes))) .code(Code.createLegacyCode(jumpBytes, Hash.hash(jumpBytes)))
.build(); .build();
frameDestinationGreaterThanCodeSize.setPC(CURRENT_PC); frameDestinationGreaterThanCodeSize.setPC(CURRENT_PC);
@ -136,7 +136,7 @@ public class JumpOperationTest {
final MessageFrame frameDestinationEqualsToCodeSize = final MessageFrame frameDestinationEqualsToCodeSize =
createMessageFrameBuilder(Gas.of(100)) createMessageFrameBuilder(Gas.of(100))
.pushStackItem(UInt256.fromHexString("0x04")) .pushStackItem(UInt256.fromHexString("0x04"))
.code(new Code(badJump, Hash.hash(badJump))) .code(Code.createLegacyCode(badJump, Hash.hash(badJump)))
.build(); .build();
frameDestinationEqualsToCodeSize.setPC(CURRENT_PC); frameDestinationEqualsToCodeSize.setPC(CURRENT_PC);
@ -154,7 +154,7 @@ public class JumpOperationTest {
final MessageFrame longContract = final MessageFrame longContract =
createMessageFrameBuilder(Gas.of(100)) createMessageFrameBuilder(Gas.of(100))
.pushStackItem(UInt256.fromHexString("0x12c")) .pushStackItem(UInt256.fromHexString("0x12c"))
.code(new Code(longCode, Hash.hash(longCode))) .code(Code.createLegacyCode(longCode, Hash.hash(longCode)))
.build(); .build();
longContract.setPC(255); longContract.setPC(255);
@ -166,7 +166,7 @@ public class JumpOperationTest {
public void shouldReuseJumpDestMap() { public void shouldReuseJumpDestMap() {
final JumpOperation operation = new JumpOperation(gasCalculator); final JumpOperation operation = new JumpOperation(gasCalculator);
final Bytes jumpBytes = Bytes.fromHexString("0x6003565b00"); 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 = MessageFrame frame =
createMessageFrameBuilder(Gas.of(10_000)) createMessageFrameBuilder(Gas.of(10_000))
.pushStackItem(UInt256.fromHexString("0x03")) .pushStackItem(UInt256.fromHexString("0x03"))

@ -213,6 +213,7 @@ public class EvmToolCommand implements Runnable {
final PrecompileContractRegistry precompileContractRegistry = final PrecompileContractRegistry precompileContractRegistry =
protocolSpec.getPrecompileContractRegistry(); protocolSpec.getPrecompileContractRegistry();
final EVM evm = protocolSpec.getEvm(); final EVM evm = protocolSpec.getEvm();
Code code = evm.getCode(Hash.hash(codeHexString), codeHexString);
final Stopwatch stopwatch = Stopwatch.createUnstarted(); final Stopwatch stopwatch = Stopwatch.createUnstarted();
long lastTime = 0; long lastTime = 0;
do { do {
@ -242,7 +243,7 @@ public class EvmToolCommand implements Runnable {
.inputData(callData) .inputData(callData)
.value(ethValue) .value(ethValue)
.apparentValue(ethValue) .apparentValue(ethValue)
.code(new Code(codeHexString, Hash.hash(codeHexString))) .code(code)
.blockValues(blockHeader) .blockValues(blockHeader)
.depth(0) .depth(0)
.completer(c -> {}) .completer(c -> {})

@ -19,11 +19,14 @@ import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.hyperledger.besu.evm.operation.PushOperation; import org.hyperledger.besu.evm.operation.PushOperation;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.errorprone.annotations.RestrictedApi;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
/** Represents EVM code associated with an account. */ /** Represents EVM code associated with an account. */
public class Code { public class Code {
public static final Code EMPTY_CODE = new Code(Bytes.EMPTY, Hash.EMPTY);
/** The bytes representing the code. */ /** The bytes representing the code. */
private final Bytes bytes; private final Bytes bytes;
@ -42,19 +45,17 @@ public class Code {
* @param bytes The byte representation of the code. * @param bytes The byte representation of the code.
* @param codeHash the Hash of the bytes in 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.bytes = bytes;
this.codeHash = codeHash; this.codeHash = codeHash;
} }
public Code(final Bytes bytecode, final Hash codeHash, final long[] validJumpDestinations) { @RestrictedApi(
this.bytes = bytecode; explanation = "To be used for testing purpose only",
this.validJumpDestinations = validJumpDestinations; link = "",
this.codeHash = codeHash; allowedOnPath = ".*/src/test/.*")
} public static Code createLegacyCode(final Bytes bytes, final Hash codeHash) {
return new Code(bytes, codeHash);
public Code() {
this(Bytes.EMPTY, Hash.EMPTY);
} }
/** /**
@ -88,24 +89,24 @@ public class Code {
} }
public long[] calculateJumpDests() { public long[] calculateJumpDests() {
int size = getSize(); final int size = getSize();
long[] bitmap = new long[(size >> 6) + 1]; final long[] bitmap = new long[(size >> 6) + 1];
byte[] rawCode = getBytes().toArrayUnsafe(); final byte[] rawCode = getBytes().toArrayUnsafe();
int length = rawCode.length; final int length = rawCode.length;
for (int i = 0; i < length; ) { for (int i = 0; i < length; ) {
long thisEntry = 0L; long thisEntry = 0L;
int entryPos = i >> 6; final int entryPos = i >> 6;
int max = Math.min(64, length - (entryPos << 6)); final int max = Math.min(64, length - (entryPos << 6));
int j = i & 0x3F; int j = i & 0x3F;
for (; j < max; i++, j++) { for (; j < max; i++, j++) {
byte operationNum = rawCode[i]; final byte operationNum = rawCode[i];
if (operationNum == JumpDestOperation.OPCODE) { if (operationNum == JumpDestOperation.OPCODE) {
thisEntry |= 1L << j; thisEntry |= 1L << j;
} else if (operationNum > PushOperation.PUSH_BASE) { } else if (operationNum > PushOperation.PUSH_BASE) {
// not needed - && operationNum <= PushOperation.PUSH_MAX // not needed - && operationNum <= PushOperation.PUSH_MAX
// Java quirk, all bytes are signed, and PUSH32 is 127, which is Byte.MAX_VALUE // 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 // 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; j += multiByteDataLen;
i += multiByteDataLen; i += multiByteDataLen;
} }
@ -129,7 +130,16 @@ public class Code {
return codeHash; return codeHash;
} }
public long[] getValidJumpDestinations() { public boolean isJumpDestInvalid(final int jumpDestination) {
return validJumpDestinations; 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;
} }
} }

@ -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;
import org.hyperledger.besu.evm.frame.MessageFrame.State; import org.hyperledger.besu.evm.frame.MessageFrame.State;
import org.hyperledger.besu.evm.gascalculator.GasCalculator; 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.EvmConfiguration;
import org.hyperledger.besu.evm.internal.FixedStack.OverflowException; import org.hyperledger.besu.evm.internal.FixedStack.OverflowException;
import org.hyperledger.besu.evm.internal.FixedStack.UnderflowException; 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.InvalidOperation;
import org.hyperledger.besu.evm.operation.Operation; import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult; import org.hyperledger.besu.evm.operation.Operation.OperationResult;
@ -51,7 +51,7 @@ public class EVM {
private final OperationRegistry operations; private final OperationRegistry operations;
private final GasCalculator gasCalculator; private final GasCalculator gasCalculator;
private final Operation endOfScriptStop; private final Operation endOfScriptStop;
private final JumpDestCache jumpDestCache; private final CodeCache codeCache;
public EVM( public EVM(
final OperationRegistry operations, final OperationRegistry operations,
@ -60,7 +60,7 @@ public class EVM {
this.operations = operations; this.operations = operations;
this.gasCalculator = gasCalculator; this.gasCalculator = gasCalculator;
this.endOfScriptStop = new VirtualOperation(new StopOperation(gasCalculator)); this.endOfScriptStop = new VirtualOperation(new StopOperation(gasCalculator));
this.jumpDestCache = new JumpDestCache(evmConfiguration); this.codeCache = new CodeCache(evmConfiguration);
} }
public GasCalculator getGasCalculator() { public GasCalculator getGasCalculator() {
@ -142,29 +142,12 @@ public class EVM {
} }
} }
/** public Code getCode(final Hash codeHash, final Bytes codeBytes) {
* Determine whether a specified destination is a valid jump target. Code result = codeCache.getIfPresent(codeHash);
* if (result == null) {
* @param jumpDestination The destination we're checking for validity. result = new Code(codeBytes, codeHash);
* @param code The code within which we are looking for the destination. codeCache.put(codeHash, result);
* @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");
}
}
} }
long targetLong = validJumpDestinations[jumpDestination >>> 6]; return result;
long targetBit = 1L << (jumpDestination & 0x3F);
return (targetLong & targetBit) != 0L;
} }
} }

@ -14,6 +14,8 @@
*/ */
package org.hyperledger.besu.evm.fluent; 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.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
@ -48,8 +50,8 @@ import org.apache.tuweni.bytes.Bytes32;
public class EVMExecutor { public class EVMExecutor {
private final EVM evm;
private PrecompileContractRegistry precompileContractRegistry; private PrecompileContractRegistry precompileContractRegistry;
private EVM evm;
private boolean commitWorldState = false; private boolean commitWorldState = false;
private WorldUpdater worldUpdater = new SimpleWorld(); private WorldUpdater worldUpdater = new SimpleWorld();
private Gas gas = Gas.MAX_VALUE; private Gas gas = Gas.MAX_VALUE;
@ -58,7 +60,7 @@ public class EVMExecutor {
private Wei gasPriceGWei = Wei.ZERO; private Wei gasPriceGWei = Wei.ZERO;
private Bytes callData = Bytes.EMPTY; private Bytes callData = Bytes.EMPTY;
private Wei ethValue = Wei.ZERO; 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 BlockValues blockValues = new SimpleBlockValues();
private OperationTracer tracer = OperationTracer.NO_TRACING; private OperationTracer tracer = OperationTracer.NO_TRACING;
private boolean requireDeposit = true; private boolean requireDeposit = true;
@ -71,15 +73,17 @@ public class EVMExecutor {
private MessageCallProcessor messageCallProcessor = null; private MessageCallProcessor messageCallProcessor = null;
private ContractCreationProcessor contractCreationProcessor = 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) { public static EVMExecutor evm(final EVM evm) {
EVMExecutor executor = new EVMExecutor(); return new EVMExecutor(evm);
executor.evm = evm;
return executor;
} }
public static EVMExecutor frontier(final EvmConfiguration evmConfiguration) { public static EVMExecutor frontier(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.frontier(evmConfiguration));
executor.evm = MainnetEVMs.frontier(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(); executor.contractValidationRules = List.of();
@ -89,8 +93,7 @@ public class EVMExecutor {
} }
public static EVMExecutor homestead(final EvmConfiguration evmConfiguration) { public static EVMExecutor homestead(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.homestead(evmConfiguration));
executor.evm = MainnetEVMs.homestead(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(); executor.contractValidationRules = List.of();
@ -99,8 +102,7 @@ public class EVMExecutor {
} }
public static EVMExecutor spuriousDragon(final EvmConfiguration evmConfiguration) { public static EVMExecutor spuriousDragon(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.spuriousDragon(evmConfiguration));
executor.evm = MainnetEVMs.spuriousDragon(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@ -108,8 +110,7 @@ public class EVMExecutor {
} }
public static EVMExecutor tangerineWhistle(final EvmConfiguration evmConfiguration) { public static EVMExecutor tangerineWhistle(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.tangerineWhistle(evmConfiguration));
executor.evm = MainnetEVMs.tangerineWhistle(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@ -117,8 +118,7 @@ public class EVMExecutor {
} }
public static EVMExecutor byzantium(final EvmConfiguration evmConfiguration) { public static EVMExecutor byzantium(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.byzantium(evmConfiguration));
executor.evm = MainnetEVMs.byzantium(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@ -126,8 +126,7 @@ public class EVMExecutor {
} }
public static EVMExecutor constantinople(final EvmConfiguration evmConfiguration) { public static EVMExecutor constantinople(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.constantinople(evmConfiguration));
executor.evm = MainnetEVMs.constantinople(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@ -135,8 +134,7 @@ public class EVMExecutor {
} }
public static EVMExecutor petersburg(final EvmConfiguration evmConfiguration) { public static EVMExecutor petersburg(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.petersburg(evmConfiguration));
executor.evm = MainnetEVMs.petersburg(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@ -144,8 +142,7 @@ public class EVMExecutor {
} }
public static EVMExecutor istanbul(final EvmConfiguration evmConfiguration) { public static EVMExecutor istanbul(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.istanbul(evmConfiguration));
executor.evm = MainnetEVMs.istanbul(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@ -153,8 +150,7 @@ public class EVMExecutor {
} }
public static EVMExecutor berlin(final EvmConfiguration evmConfiguration) { public static EVMExecutor berlin(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.berlin(evmConfiguration));
executor.evm = MainnetEVMs.berlin(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000)); executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@ -162,8 +158,7 @@ public class EVMExecutor {
} }
public static EVMExecutor london(final EvmConfiguration evmConfiguration) { public static EVMExecutor london(final EvmConfiguration evmConfiguration) {
EVMExecutor executor = new EVMExecutor(); final EVMExecutor executor = new EVMExecutor(MainnetEVMs.london(evmConfiguration));
executor.evm = MainnetEVMs.istanbul(evmConfiguration);
executor.precompileContractRegistry = executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator()); MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
return executor; return executor;
@ -198,7 +193,7 @@ public class EVMExecutor {
public Bytes execute( public Bytes execute(
final Bytes codeBytes, final Bytes inputData, final Wei value, final Address receiver) { 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.callData = inputData;
this.ethValue = value; this.ethValue = value;
this.receiver = receiver; this.receiver = receiver;
@ -206,10 +201,10 @@ public class EVMExecutor {
} }
public Bytes execute() { public Bytes execute() {
MessageCallProcessor mcp = thisMessageCallProcessor(); final MessageCallProcessor mcp = thisMessageCallProcessor();
ContractCreationProcessor ccp = thisContractCreationProcessor(); final ContractCreationProcessor ccp = thisContractCreationProcessor();
final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>(); final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
MessageFrame initialMessageFrame = final MessageFrame initialMessageFrame =
MessageFrame.builder() MessageFrame.builder()
.type(MessageFrame.Type.MESSAGE_CALL) .type(MessageFrame.Type.MESSAGE_CALL)
.messageFrameStack(messageFrameStack) .messageFrameStack(messageFrameStack)
@ -302,7 +297,7 @@ public class EVMExecutor {
} }
public EVMExecutor code(final Bytes codeBytes, final Hash hash) { public EVMExecutor code(final Bytes codeBytes, final Hash hash) {
this.code = new Code(codeBytes, hash); this.code = evm.getCode(hash, codeBytes);
return this; return this;
} }

@ -16,20 +16,21 @@
package org.hyperledger.besu.evm.internal; package org.hyperledger.besu.evm.internal;
import org.hyperledger.besu.datatypes.Hash; 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.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
public class JumpDestCache { public class CodeCache {
private final Cache<Hash, long[]> cache; private final Cache<Hash, Code> cache;
private final long weightLimit; private final long weightLimit;
public JumpDestCache(final EvmConfiguration config) { public CodeCache(final EvmConfiguration config) {
this(config.getJumpDestCacheWeightBytes()); this(config.getJumpDestCacheWeightBytes());
} }
private JumpDestCache(final long maxWeightBytes) { private CodeCache(final long maxWeightBytes) {
this.weightLimit = maxWeightBytes; this.weightLimit = maxWeightBytes;
this.cache = this.cache =
Caffeine.newBuilder().maximumWeight(maxWeightBytes).weigher(new CodeScale()).build(); Caffeine.newBuilder().maximumWeight(maxWeightBytes).weigher(new CodeScale()).build();
@ -43,11 +44,11 @@ public class JumpDestCache {
this.cache.cleanUp(); this.cache.cleanUp();
} }
public long[] getIfPresent(final Hash codeHash) { public Code getIfPresent(final Hash codeHash) {
return cache.getIfPresent(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); cache.put(key, value);
} }

@ -16,12 +16,13 @@
package org.hyperledger.besu.evm.internal; package org.hyperledger.besu.evm.internal;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.Code;
import com.github.benmanes.caffeine.cache.Weigher; import com.github.benmanes.caffeine.cache.Weigher;
class CodeScale implements Weigher<Hash, long[]> { class CodeScale implements Weigher<Hash, Code> {
@Override @Override
public int weigh(final Hash key, final long[] value) { public int weigh(final Hash key, final Code code) {
return (value.length * 8) + key.size(); return ((code.getSize() * 9 + 7) / 8) + key.size();
} }
} }

@ -15,7 +15,6 @@
package org.hyperledger.besu.evm.operation; package org.hyperledger.besu.evm.operation;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.EVM;
@ -185,6 +184,11 @@ public abstract class AbstractCallOperation extends AbstractOperation {
final Bytes inputData = final Bytes inputData =
frame.readMutableMemory(inputDataOffset(frame), inputDataLength(frame)); frame.readMutableMemory(inputDataOffset(frame), inputDataLength(frame));
final Code code =
contract == null
? Code.EMPTY_CODE
: evm.getCode(contract.getCodeHash(), contract.getCode());
final MessageFrame childFrame = final MessageFrame childFrame =
MessageFrame.builder() MessageFrame.builder()
.type(MessageFrame.Type.MESSAGE_CALL) .type(MessageFrame.Type.MESSAGE_CALL)
@ -199,10 +203,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
.sender(sender(frame)) .sender(sender(frame))
.value(value(frame)) .value(value(frame))
.apparentValue(apparentValue(frame)) .apparentValue(apparentValue(frame))
.code( .code(code)
new Code(
contract != null ? contract.getCode() : Bytes.EMPTY,
contract != null ? contract.getCodeHash() : Hash.EMPTY))
.blockValues(frame.getBlockValues()) .blockValues(frame.getBlockValues())
.depth(frame.getMessageStackDepth() + 1) .depth(frame.getMessageStackDepth() + 1)
.isStatic(isStatic(frame)) .isStatic(isStatic(frame))

@ -19,7 +19,6 @@ import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.account.MutableAccount; 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) { if (value.compareTo(account.getBalance()) > 0 || frame.getMessageStackDepth() >= 1024) {
fail(frame); fail(frame);
} else { } else {
spawnChildMessage(frame); spawnChildMessage(frame, evm);
} }
} }
@ -95,7 +94,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
frame.pushStackItem(UInt256.ZERO); 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 // memory cost needs to be calculated prior to memory expansion
final Gas cost = cost(frame); final Gas cost = cost(frame);
frame.decrementRemainingGas(cost); frame.decrementRemainingGas(cost);
@ -129,7 +128,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
.sender(frame.getRecipientAddress()) .sender(frame.getRecipientAddress())
.value(value) .value(value)
.apparentValue(value) .apparentValue(value)
.code(new Code(inputData, Hash.EMPTY)) .code(evm.getCode(Hash.hash(inputData), inputData))
.blockValues(frame.getBlockValues()) .blockValues(frame.getBlockValues())
.depth(frame.getMessageStackDepth() + 1) .depth(frame.getMessageStackDepth() + 1)
.completer(child -> complete(frame, child)) .completer(child -> complete(frame, child))

@ -48,7 +48,7 @@ public class JumpOperation extends AbstractFixedCostOperation {
return invalidJumpResponse; return invalidJumpResponse;
} }
final Code code = frame.getCode(); final Code code = frame.getCode();
if (!evm.isValidJumpDestination(jumpDestination, code)) { if (code.isJumpDestInvalid(jumpDestination)) {
return invalidJumpResponse; return invalidJumpResponse;
} else { } else {
frame.setPC(jumpDestination); frame.setPC(jumpDestination);

@ -53,7 +53,7 @@ public class JumpiOperation extends AbstractFixedCostOperation {
return invalidJumpResponse; return invalidJumpResponse;
} }
final Code code = frame.getCode(); final Code code = frame.getCode();
if (!evm.isValidJumpDestination(jumpDestination, code)) { if (code.isJumpDestInvalid(jumpDestination)) {
return invalidJumpResponse; return invalidJumpResponse;
} }
frame.setPC(jumpDestination); frame.setPC(jumpDestination);

@ -15,6 +15,8 @@
package org.hyperledger.besu.evm.processor; package org.hyperledger.besu.evm.processor;
import org.hyperledger.besu.datatypes.Address; 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.EVM;
import org.hyperledger.besu.evm.ModificationNotAllowedException; import org.hyperledger.besu.evm.ModificationNotAllowedException;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
@ -26,6 +28,8 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes;
/** /**
* A skeletal class for instantiating message processors. * A skeletal class for instantiating message processors.
* *
@ -193,4 +197,8 @@ public abstract class AbstractMessageProcessor {
completedFailed(frame); completedFailed(frame);
} }
} }
public Code getCodeFromEVM(final Hash codeHash, final Bytes codeBytes) {
return evm.getCode(codeHash, codeBytes);
}
} }

@ -24,19 +24,18 @@ import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.junit.Test; import org.junit.Test;
public class JumpDestCacheTest { public class CodeCacheTest {
private final String op = Bytes.of(JumpDestOperation.OPCODE).toUnprefixedHexString(); private final String op = Bytes.of(JumpDestOperation.OPCODE).toUnprefixedHexString();
@Test @Test
public void testScale() { public void testScale() {
Bytes contractBytes = final Bytes contractBytes =
Bytes.fromHexString("0xDEAD" + op + "BEEF" + op + "B0B0" + op + "C0DE" + op + "FACE"); Bytes.fromHexString("0xDEAD" + op + "BEEF" + op + "B0B0" + op + "C0DE" + op + "FACE");
// 3rd bit, 6th bit, 9th bit, 12th bit final CodeScale scale = new CodeScale();
long[] jumpDests = {4 + 32 + 256 + 2048}; final Code contractCode = Code.createLegacyCode(contractBytes, Hash.hash(contractBytes));
CodeScale scale = new CodeScale(); final int weight = scale.weigh(contractCode.getCodeHash(), contractCode);
Code contractCode = new Code(contractBytes, Hash.hash(contractBytes), jumpDests); assertThat(weight)
int weight = scale.weigh(contractCode.getCodeHash(), contractCode.getValidJumpDestinations()); .isEqualTo(contractCode.getCodeHash().size() + (contractBytes.size() * 9 + 7) / 8);
assertThat(weight).isEqualTo(contractCode.getCodeHash().size() + jumpDests.length * 8);
} }
} }

@ -66,7 +66,7 @@ public class Benchmarks {
.sender(Address.ZERO) .sender(Address.ZERO)
.value(Wei.ZERO) .value(Wei.ZERO)
.apparentValue(Wei.ZERO) .apparentValue(Wei.ZERO)
.code(new Code(Bytes.EMPTY, org.hyperledger.besu.datatypes.Hash.EMPTY)) .code(Code.EMPTY_CODE)
.depth(1) .depth(1)
.completer(__ -> {}) .completer(__ -> {})
.address(Address.ZERO) .address(Address.ZERO)

@ -144,6 +144,7 @@ public class EvmToyCommand implements Runnable {
int repeat = this.repeat; int repeat = this.repeat;
final EVM evm = MainnetEVMs.berlin(EvmConfiguration.DEFAULT); final EVM evm = MainnetEVMs.berlin(EvmConfiguration.DEFAULT);
final Code code = evm.getCode(Hash.hash(codeBytes), codeBytes);
final PrecompileContractRegistry precompileContractRegistry = new PrecompileContractRegistry(); final PrecompileContractRegistry precompileContractRegistry = new PrecompileContractRegistry();
MainnetPrecompiledContracts.populateForIstanbul( MainnetPrecompiledContracts.populateForIstanbul(
precompileContractRegistry, evm.getGasCalculator()); precompileContractRegistry, evm.getGasCalculator());
@ -172,7 +173,7 @@ public class EvmToyCommand implements Runnable {
.inputData(callData) .inputData(callData)
.value(ethValue) .value(ethValue)
.apparentValue(ethValue) .apparentValue(ethValue)
.code(new Code(codeBytes, Hash.hash(codeBytes))) .code(code)
.blockValues(new ToyBlockValues()) .blockValues(new ToyBlockValues())
.depth(0) .depth(0)
.completer(c -> {}) .completer(c -> {})

Loading…
Cancel
Save