Evm speedup (#2796)

Broad reaching optimizations to speed up EVM calculations

* Generally speaking, use int and long where it is more appropriate than UInt256 (memory indexes mostly)
* Move the internal stack to Bytes from UInt256
* Re-work the flow of many operations to account for the above

Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
pull/2804/head
Danno Ferrin 3 years ago committed by GitHub
parent 2541b155f8
commit 2415000caf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 1
      consensus/ibft/build.gradle
  3. 35
      consensus/qbft/build.gradle
  4. 14
      datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java
  5. 12
      datatypes/src/main/java/org/hyperledger/besu/datatypes/Hash.java
  6. 2
      datatypes/src/main/java/org/hyperledger/besu/datatypes/Wei.java
  7. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java
  8. 5
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java
  9. 13
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/flat/FlatTraceGenerator.java
  10. 6
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/vm/Mem.java
  11. 8
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/tracing/vm/VmTraceGenerator.java
  12. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java
  13. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiInMemoryWorldState.java
  14. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiLayeredWorldState.java
  15. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java
  16. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchive.java
  17. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java
  18. 1
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MutableWorldState.java
  19. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/debug/TraceFrame.java
  20. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/markertransaction/SigningPrivateMarkerTransactionFactory.java
  21. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  22. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracer.java
  23. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultMutableWorldState.java
  24. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DefaultWorldStateArchive.java
  25. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateArchive.java
  26. 4
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionEIP1559Test.java
  27. 10
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java
  28. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/AbstractRetryingTest.java
  29. 12
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/DebugOperationTracerTest.java
  30. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/EVMTest.java
  31. 111
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/MemoryTest.java
  32. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/BlockHashOperationTest.java
  33. 5
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/Create2OperationTest.java
  34. 4
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/ExtCodeHashOperationTest.java
  35. 19
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/JumpOperationTest.java
  36. 9
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/RevertOperationTest.java
  37. 10
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/GetBlockHeadersMessage.java
  38. 5
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BlockchainModule.java
  39. 18
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java
  40. 8
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java
  41. 6
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/Packet.java
  42. 1
      ethereum/permissioning/build.gradle
  43. 1
      ethereum/rlp/build.gradle
  44. 22
      ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLP.java
  45. 30
      evm/src/main/java/org/hyperledger/besu/evm/AccessListEntry.java
  46. 54
      evm/src/main/java/org/hyperledger/besu/evm/AccessListEntryDeserializer.java
  47. 52
      evm/src/main/java/org/hyperledger/besu/evm/AccessListEntrySerializer.java
  48. 43
      evm/src/main/java/org/hyperledger/besu/evm/Code.java
  49. 7
      evm/src/main/java/org/hyperledger/besu/evm/EVM.java
  50. 20
      evm/src/main/java/org/hyperledger/besu/evm/Gas.java
  51. 1
      evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
  52. 383
      evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java
  53. 158
      evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java
  54. 21
      evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleBlockValues.java
  55. 109
      evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java
  56. 3
      evm/src/main/java/org/hyperledger/besu/evm/frame/ExceptionalHaltReason.java
  57. 128
      evm/src/main/java/org/hyperledger/besu/evm/frame/Memory.java
  58. 114
      evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java
  59. 10
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/BerlinGasCalculator.java
  60. 4
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/ConstantinopleGasCalculator.java
  61. 52
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java
  62. 25
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java
  63. 10
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/SpuriousDragonGasCalculator.java
  64. 10
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/TangerineWhistleGasCalculator.java
  65. 7
      evm/src/main/java/org/hyperledger/besu/evm/internal/MemoryEntry.java
  66. 6
      evm/src/main/java/org/hyperledger/besu/evm/internal/OperandStack.java
  67. 37
      evm/src/main/java/org/hyperledger/besu/evm/internal/StorageEntry.java
  68. 23
      evm/src/main/java/org/hyperledger/besu/evm/internal/Words.java
  69. 20
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java
  70. 11
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java
  71. 29
      evm/src/main/java/org/hyperledger/besu/evm/operation/AddModOperation.java
  72. 7
      evm/src/main/java/org/hyperledger/besu/evm/operation/AddOperation.java
  73. 8
      evm/src/main/java/org/hyperledger/besu/evm/operation/AddressOperation.java
  74. 7
      evm/src/main/java/org/hyperledger/besu/evm/operation/AndOperation.java
  75. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/BalanceOperation.java
  76. 10
      evm/src/main/java/org/hyperledger/besu/evm/operation/BaseFeeOperation.java
  77. 9
      evm/src/main/java/org/hyperledger/besu/evm/operation/BlockHashOperation.java
  78. 7
      evm/src/main/java/org/hyperledger/besu/evm/operation/ByteOperation.java
  79. 30
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallCodeOperation.java
  80. 9
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallDataCopyOperation.java
  81. 5
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallDataLoadOperation.java
  82. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallDataSizeOperation.java
  83. 30
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallOperation.java
  84. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallValueOperation.java
  85. 8
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallerOperation.java
  86. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/ChainIdOperation.java
  87. 10
      evm/src/main/java/org/hyperledger/besu/evm/operation/CodeCopyOperation.java
  88. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/CodeSizeOperation.java
  89. 6
      evm/src/main/java/org/hyperledger/besu/evm/operation/CoinbaseOperation.java
  90. 12
      evm/src/main/java/org/hyperledger/besu/evm/operation/Create2Operation.java
  91. 30
      evm/src/main/java/org/hyperledger/besu/evm/operation/DelegateCallOperation.java
  92. 4
      evm/src/main/java/org/hyperledger/besu/evm/operation/DifficultyOperation.java
  93. 25
      evm/src/main/java/org/hyperledger/besu/evm/operation/DivOperation.java
  94. 7
      evm/src/main/java/org/hyperledger/besu/evm/operation/DupOperation.java
  95. 7
      evm/src/main/java/org/hyperledger/besu/evm/operation/EqOperation.java
  96. 4
      evm/src/main/java/org/hyperledger/besu/evm/operation/ExpOperation.java
  97. 9
      evm/src/main/java/org/hyperledger/besu/evm/operation/ExtCodeCopyOperation.java
  98. 10
      evm/src/main/java/org/hyperledger/besu/evm/operation/GasLimitOperation.java
  99. 9
      evm/src/main/java/org/hyperledger/besu/evm/operation/GasOperation.java
  100. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/GasPriceOperation.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -3,6 +3,7 @@
## 21.10.0-RC1
### Additions and Improvements
* The EVM has been factored out into a standalone module, suitable for inclusion as a library. [#2790](https://github.com/hyperledger/besu/pull/2790)
* Low level performance improvements changes to cut worst-case EVM performance in half. [#2796](https://github.com/hyperledger/besu/pull/2796)
### Bug Fixes

@ -53,6 +53,7 @@ dependencies {
testImplementation project(path: ':config', configuration: 'testSupportArtifacts')
testImplementation project(path: ':consensus:common', configuration: 'testArtifacts')
testImplementation project(path: ':consensus:common', configuration: 'testSupportArtifacts')
testImplementation project(':evm')
testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
testImplementation project(':metrics:core')
testImplementation project(':testutil')

@ -76,26 +76,28 @@ dependencies {
implementation 'org.apache.tuweni:tuweni-units'
implementation 'org.web3j:abi'
integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts')
integrationTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
testImplementation 'junit:junit'
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-core'
testImplementation project(path: ':crypto', configuration: 'testSupportArtifacts')
testImplementation project(path: ':config', configuration: 'testSupportArtifacts')
testImplementation project(path: ':consensus:common', configuration: 'testArtifacts')
testImplementation project(path: ':consensus:common', configuration: 'testSupportArtifacts')
testImplementation project(':crypto')
testImplementation project(':ethereum:core')
testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
testImplementation project(':crypto')
testImplementation project(':evm')
testImplementation project(':metrics:core')
testImplementation project(':testutil')
testImplementation 'junit:junit'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.mockito:mockito-core'
integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts')
integrationTestImplementation project(path: ':consensus:common', configuration: 'testSupportArtifacts')
integrationTestImplementation project(':crypto')
integrationTestImplementation project(path: ':crypto', configuration: 'testSupportArtifacts')
integrationTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
integrationTestImplementation project(path: ':consensus:common', configuration: 'testSupportArtifacts')
integrationTestImplementation project(':evm')
integrationTestImplementation project(':metrics:core')
integrationTestImplementation project(':testutil')
@ -103,6 +105,13 @@ dependencies {
integrationTestImplementation 'org.assertj:assertj-core'
integrationTestImplementation 'org.mockito:mockito-core'
referenceTestImplementation 'junit:junit'
referenceTestImplementation 'com.google.guava:guava'
referenceTestImplementation 'org.assertj:assertj-core'
referenceTestImplementation 'org.mockito:mockito-core'
referenceTestImplementation 'com.fasterxml.jackson.core:jackson-databind'
referenceTestImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8'
referenceTestImplementation 'org.apache.tuweni:tuweni-bytes'
referenceTestImplementation project(':crypto')
referenceTestImplementation project(path: ':crypto', configuration: 'testSupportArtifacts')
referenceTestImplementation project(':consensus:common')
@ -112,14 +121,6 @@ dependencies {
referenceTestImplementation project(':config')
referenceTestImplementation project(':testutil')
referenceTestImplementation 'com.fasterxml.jackson.core:jackson-databind'
referenceTestImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8'
referenceTestImplementation 'com.google.guava:guava'
referenceTestImplementation 'junit:junit'
referenceTestImplementation 'org.apache.tuweni:tuweni-bytes'
referenceTestImplementation 'org.assertj:assertj-core'
referenceTestImplementation 'org.mockito:mockito-core'
testSupportImplementation 'org.mockito:mockito-core'
}

@ -15,6 +15,7 @@
package org.hyperledger.besu.datatypes;
import static com.google.common.base.Preconditions.checkArgument;
import static org.hyperledger.besu.crypto.Hash.keccak256;
import org.hyperledger.besu.crypto.SECPPublicKey;
import org.hyperledger.besu.ethereum.rlp.RLP;
@ -23,6 +24,7 @@ import org.hyperledger.besu.ethereum.rlp.RLPInput;
import com.fasterxml.jackson.annotation.JsonCreator;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.DelegatingBytes;
/** A 160-bits account address. */
@ -88,12 +90,12 @@ public class Address extends DelegatingBytes implements org.hyperledger.besu.plu
* </code> function from Appendix F (Signing Transactions) of the Ethereum Yellow Paper.
* @return The ethereum address from the provided hash.
*/
public static Address extract(final Hash hash) {
public static Address extract(final Bytes32 hash) {
return wrap(hash.slice(12, 20));
}
public static Address extract(final SECPPublicKey publicKey) {
return extract(Hash.hash(publicKey.getEncodedBytes()));
return Address.extract(keccak256(publicKey.getEncodedBytes()));
}
/**
@ -153,8 +155,8 @@ public class Address extends DelegatingBytes implements org.hyperledger.besu.plu
* @return The generated address of the created contract.
*/
public static Address contractAddress(final Address senderAddress, final long nonce) {
return extract(
Hash.hash(
return Address.extract(
keccak256(
RLP.encode(
out -> {
out.startList();
@ -174,8 +176,8 @@ public class Address extends DelegatingBytes implements org.hyperledger.besu.plu
*/
public static Address privateContractAddress(
final Address senderAddress, final long nonce, final Bytes privacyGroupId) {
return extract(
Hash.hash(
return Address.extract(
keccak256(
RLP.encode(
out -> {
out.startList();

@ -28,10 +28,22 @@ public class Hash extends DelegatingBytes32 implements org.hyperledger.besu.plug
public static final Hash ZERO = new Hash(Bytes32.ZERO);
/**
* Hash of an RLP encoded trie hash with no content, or
* "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
*/
public static final Hash EMPTY_TRIE_HASH = Hash.hash(RLP.NULL);
/**
* Hash of a zero length RLP list, or
* "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
*/
public static final Hash EMPTY_LIST_HASH = Hash.hash(RLP.EMPTY_LIST);
/**
* Hash of an empty string, or
* "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
*/
public static final Hash EMPTY = hash(Bytes.EMPTY);
private Hash(final Bytes32 bytes) {

@ -94,6 +94,6 @@ public final class Wei extends BaseUInt256Value<Wei> implements Quantity {
}
public static Wei fromQuantity(final Quantity quantity) {
return Wei.of(quantity.getAsBigInteger());
return Wei.wrap((Bytes) quantity);
}
}

@ -20,8 +20,7 @@ import org.hyperledger.besu.ethereum.debug.TraceFrame;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater.StackedUpdater;
import org.hyperledger.besu.evm.worldstate.StackedUpdater;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.List;
@ -52,7 +51,7 @@ public class BlockTracer {
// if we have no prior updater, it must be the first TX, so use the block's initial state
if (chainedUpdater == null) {
chainedUpdater = mutableWorldState.updater();
} else if (chainedUpdater instanceof AbstractWorldUpdater.StackedUpdater) {
} else if (chainedUpdater instanceof StackedUpdater) {
((StackedUpdater) chainedUpdater).markTransactionBoundary();
}
// create an updater for just this tx

@ -29,7 +29,7 @@ import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.tracing.StandardJsonTracer;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater;
import org.hyperledger.besu.evm.worldstate.StackedUpdater;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.io.File;
@ -105,8 +105,7 @@ public class TransactionTracer {
WorldUpdater stackedUpdater = worldState.updater().updater();
final List<String> traces = new ArrayList<>();
for (int i = 0; i < body.getTransactions().size(); i++) {
((AbstractWorldUpdater.StackedUpdater<?, ?>) stackedUpdater)
.markTransactionBoundary();
((StackedUpdater<?, ?>) stackedUpdater).markTransactionBoundary();
final Transaction transaction = body.getTransactions().get(i);
if (selectedHash.isEmpty()
|| selectedHash.filter(isEqual(transaction.getHash())).isPresent()) {

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.flat;
import static org.hyperledger.besu.evm.internal.Words.toAddress;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace;
@ -30,7 +32,6 @@ import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
@ -45,7 +46,6 @@ import java.util.stream.Stream;
import com.google.common.collect.Streams;
import com.google.common.util.concurrent.Atomics;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
public class FlatTraceGenerator {
@ -259,7 +259,7 @@ public class FlatTraceGenerator {
final long cumulativeGasCost,
final Deque<FlatTrace.Context> tracesContexts,
final String opcodeString) {
final Bytes32[] stack = traceFrame.getStack().orElseThrow();
final Bytes[] stack = traceFrame.getStack().orElseThrow();
final FlatTrace.Context lastContext = tracesContexts.peekLast();
final String callingAddress = calculateCallingAddress(lastContext);
@ -370,7 +370,7 @@ public class FlatTraceGenerator {
currentContext.setGasUsed(gasUsed.toLong());
final Bytes32[] stack = traceFrame.getStack().orElseThrow();
final Bytes[] stack = traceFrame.getStack().orElseThrow();
final Address refundAddress = toAddress(stack[stack.length - 1]);
final FlatTrace.Builder subTraceBuilder =
FlatTrace.builder()
@ -595,11 +595,6 @@ public class FlatTraceGenerator {
return nextTraceFrame.map(TraceFrame::getGasRemaining).orElse(Gas.ZERO);
}
private static Address toAddress(final Bytes32 value) {
return Address.wrap(
Bytes.of(Arrays.copyOfRange(value.toArray(), Bytes32.SIZE - Address.SIZE, Bytes32.SIZE)));
}
private static List<Integer> calculateTraceAddress(final Deque<FlatTrace.Context> contexts) {
return contexts.stream()
.map(context -> context.getBuilder().getSubtraces())

@ -17,9 +17,9 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.vm;
public class Mem {
private final String data;
private final int off;
private final long off;
public Mem(final String data, final int off) {
public Mem(final String data, final long off) {
this.data = data;
this.off = off;
}
@ -28,7 +28,7 @@ public class Mem {
return data;
}
public int getOff() {
public long getOff() {
return off;
}
}

@ -160,9 +160,7 @@ public class VmTraceGenerator {
if (!currentOperation.startsWith("CREATE")) {
lastFrameInCall
.getMaybeUpdatedMemory()
.map(
mem ->
new Mem(mem.getValue().toHexString(), mem.getOffset().intValue()))
.map(mem -> new Mem(mem.getValue().toHexString(), mem.getOffset()))
.ifPresent(report::setMem);
}
});
@ -231,9 +229,7 @@ public class VmTraceGenerator {
.getMaybeUpdatedMemory()
.map(
updatedMemory ->
new Mem(
updatedMemory.getValue().toHexString(),
updatedMemory.getOffset().intValue()))
new Mem(updatedMemory.getValue().toHexString(), updatedMemory.getOffset()))
.ifPresent(report::setMem);
break;
default:

@ -37,7 +37,7 @@ import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.tracing.StandardJsonTracer;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater;
import org.hyperledger.besu.evm.worldstate.StackedUpdater;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.io.IOException;
@ -256,7 +256,7 @@ public class TransactionTracerTest {
final WorldUpdater updater = mock(WorldUpdater.class);
when(mutableWorldState.updater()).thenReturn(updater);
final WorldUpdater stackedUpdater = mock(AbstractWorldUpdater.StackedUpdater.class);
final WorldUpdater stackedUpdater = mock(StackedUpdater.class);
when(updater.updater()).thenReturn(stackedUpdater);
final Address coinbase = blockHeader.getCoinbase();
when(transactionProcessor.processTransaction(

@ -17,7 +17,7 @@
package org.hyperledger.besu.ethereum.bonsai;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeader;
public class BonsaiInMemoryWorldState extends BonsaiPersistedWorldState {

@ -19,12 +19,12 @@ package org.hyperledger.besu.ethereum.bonsai;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.HashMap;
import java.util.Map;
@ -180,7 +180,7 @@ public class BonsaiLayeredWorldState implements MutableWorldState, BonsaiWorldVi
if (!results.containsKey(entry.getKey())) {
final UInt256 value = entry.getValue().getUpdated();
// yes, store the nulls. If it was deleted it should stay deleted
results.put(entry.getKey(), value == null ? null : value);
results.put(entry.getKey(), value);
}
});
}

@ -22,13 +22,13 @@ import static org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateKeyValueStora
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;

@ -21,12 +21,12 @@ import static org.hyperledger.besu.datatypes.Hash.fromPlugin;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.proof.WorldStateProof;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.ArrayList;
import java.util.HashMap;

@ -310,8 +310,7 @@ public class BlockHeader extends SealableBlockHeader
return new org.hyperledger.besu.ethereum.core.BlockHeader(
Hash.fromHexString(pluginBlockHeader.getParentHash().toHexString()),
Hash.fromHexString(pluginBlockHeader.getOmmersHash().toHexString()),
org.hyperledger.besu.datatypes.Address.fromHexString(
pluginBlockHeader.getCoinbase().toHexString()),
Address.fromHexString(pluginBlockHeader.getCoinbase().toHexString()),
Hash.fromHexString(pluginBlockHeader.getStateRoot().toHexString()),
Hash.fromHexString(pluginBlockHeader.getTransactionsRoot().toHexString()),
Hash.fromHexString(pluginBlockHeader.getReceiptsRoot().toHexString()),

@ -16,7 +16,6 @@ package org.hyperledger.besu.ethereum.core;
import org.hyperledger.besu.evm.worldstate.MutableWorldView;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.data.BlockHeader;
public interface MutableWorldState extends WorldState, MutableWorldView {

@ -20,6 +20,7 @@ import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.internal.MemoryEntry;
import org.hyperledger.besu.evm.internal.StorageEntry;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.Map;
@ -56,7 +57,7 @@ public class TraceFrame {
private Gas gasRemainingPostExecution;
private final boolean virtualOperation;
private final Optional<MemoryEntry> maybeUpdatedMemory;
private final Optional<MemoryEntry> maybeUpdatedStorage;
private final Optional<StorageEntry> maybeUpdatedStorage;
private Optional<Gas> precompiledGasCost;
public TraceFrame(
@ -82,7 +83,7 @@ public class TraceFrame {
final Optional<Bytes32[]> stackPostExecution,
final boolean virtualOperation,
final Optional<MemoryEntry> maybeUpdatedMemory,
final Optional<MemoryEntry> maybeUpdatedStorage) {
final Optional<StorageEntry> maybeUpdatedStorage) {
this.pc = pc;
this.opcode = opcode;
this.gasRemaining = gasRemaining;
@ -224,7 +225,7 @@ public class TraceFrame {
return maybeUpdatedMemory;
}
public Optional<MemoryEntry> getMaybeUpdatedStorage() {
public Optional<StorageEntry> getMaybeUpdatedStorage() {
return maybeUpdatedStorage;
}

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.privacy.markertransaction;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
@ -35,9 +36,7 @@ public class SigningPrivateMarkerTransactionFactory {
.gasPrice(
unsignedPrivateMarkerTransaction.getGasPrice().map(Wei::fromQuantity).orElse(null))
.gasLimit(unsignedPrivateMarkerTransaction.getGasLimit())
.to(
org.hyperledger.besu.datatypes.Address.fromPlugin(
unsignedPrivateMarkerTransaction.getTo().get()))
.to(Address.fromPlugin(unsignedPrivateMarkerTransaction.getTo().get()))
.value(Wei.fromQuantity(unsignedPrivateMarkerTransaction.getValue()))
.payload(unsignedPrivateMarkerTransaction.getPayload())
.signAndBuild(signingKey);

@ -234,7 +234,7 @@ public class TransactionSimulator {
// fail.
if (GoQuorumOptions.goQuorumCompatibilityMode && value.isZero()) {
Gas privateGasEstimateAndState =
protocolSpec.getGasCalculator().getMaximumTransactionCost(32);
protocolSpec.getGasCalculator().getMaximumTransactionCost(64);
if (privateGasEstimateAndState.toLong() > result.getEstimateGasUsedByTransaction()) {
// modify the result to have the larger estimate
TransactionProcessingResult resultPmt =

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.vm;
import static org.apache.tuweni.bytes.Bytes32.leftPad;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.debug.TraceFrame;
@ -38,8 +40,6 @@ import org.apache.tuweni.units.bigints.UInt256;
public class DebugOperationTracer implements OperationTracer {
private static final UInt256 UINT256_32 = UInt256.valueOf(32);
private final TraceOptions options;
private List<TraceFrame> traceFrames = new ArrayList<>();
private TraceFrame lastFrame;
@ -200,9 +200,9 @@ public class DebugOperationTracer implements OperationTracer {
if (!options.isMemoryEnabled()) {
return Optional.empty();
}
final Bytes[] memoryContents = new Bytes32[frame.memoryWordSize().intValue()];
final Bytes[] memoryContents = new Bytes[frame.memoryWordSize()];
for (int i = 0; i < memoryContents.length; i++) {
memoryContents[i] = frame.readMemory(UInt256.valueOf(i * 32L), UINT256_32);
memoryContents[i] = frame.readMemory(i * 32L, 32);
}
return Optional.of(memoryContents);
}
@ -215,7 +215,7 @@ public class DebugOperationTracer implements OperationTracer {
final Bytes32[] stackContents = new Bytes32[frame.stackSize()];
for (int i = 0; i < stackContents.length; i++) {
// Record stack contents in reverse
stackContents[i] = frame.getStackItem(stackContents.length - i - 1);
stackContents[i] = leftPad(frame.getStackItem(stackContents.length - i - 1));
}
return Optional.of(stackContents);
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.worldstate;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPException;
@ -24,13 +25,11 @@ import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie;
import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.AccountState;
import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater;
import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.ArrayList;
import java.util.Collection;
@ -151,7 +150,7 @@ public class DefaultMutableWorldState implements MutableWorldState {
.map(
entry -> {
final Optional<Address> address = getAccountTrieKeyPreimage(entry.getKey());
final AccountState account =
final WorldStateAccount account =
deserializeAccount(
address.orElse(Address.ZERO), Hash.wrap(entry.getKey()), entry.getValue());
return new StreamableAccount(address, account);

@ -17,12 +17,12 @@ package org.hyperledger.besu.ethereum.worldstate;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.proof.WorldStateProof;
import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider;
import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.List;
import java.util.Optional;

@ -16,11 +16,11 @@ package org.hyperledger.besu.ethereum.worldstate;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.proof.WorldStateProof;
import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie;
import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.List;
import java.util.Optional;

@ -67,8 +67,8 @@ public class TransactionEIP1559Test {
final String raw = out.encoded().toHexString();
final Transaction decoded = Transaction.readFrom(RLP.input(Bytes.fromHexString(raw)));
System.out.println(decoded);
System.out.println(decoded.getAccessList().orElseThrow().get(0).getAddress().toHexString());
System.out.println(decoded.getAccessList().orElseThrow().get(0).getStorageKeys());
System.out.println(decoded.getAccessList().orElseThrow().get(0).getAddressString());
System.out.println(decoded.getAccessList().orElseThrow().get(0).getStorageKeysString());
}
private static KeyPair keyPair(final String privateKey) {

@ -83,7 +83,7 @@ public class MainnetTransactionValidatorTest {
.gasLimit(10)
.chainId(Optional.empty())
.createTransaction(senderKeys);
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(50L));
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(50));
assertThat(validator.validate(transaction, Optional.empty(), transactionValidationParams))
.isEqualTo(
@ -365,7 +365,7 @@ public class MainnetTransactionValidatorTest {
frontierValidator.validate(transaction, Optional.empty(), transactionValidationParams))
.isEqualTo(ValidationResult.invalid(TransactionInvalidReason.INVALID_TRANSACTION_FORMAT));
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(0L));
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(0));
assertThat(eip1559Validator.validate(transaction, Optional.of(1L), transactionValidationParams))
.isEqualTo(ValidationResult.valid());
@ -411,7 +411,7 @@ public class MainnetTransactionValidatorTest {
.chainId(Optional.of(BigInteger.ONE))
.createTransaction(senderKeys);
final Optional<Long> basefee = Optional.of(150000L);
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(50L));
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(50));
assertThat(validator.validate(transaction, basefee, transactionValidationParams))
.isEqualTo(ValidationResult.valid());
@ -434,7 +434,7 @@ public class MainnetTransactionValidatorTest {
.type(TransactionType.EIP1559)
.chainId(Optional.of(BigInteger.ONE))
.createTransaction(senderKeys);
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(50L));
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(50));
assertThat(
validator.validate(
@ -474,7 +474,7 @@ public class MainnetTransactionValidatorTest {
.chainId(Optional.empty())
.createTransaction(senderKeys);
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(50L));
when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(Gas.of(50));
assertThat(
validator

@ -58,7 +58,7 @@ public abstract class AbstractRetryingTest {
public void execution() {
try {
runTest();
} catch (final AssertionError e) {
} catch (final RuntimeException | AssertionError e) {
if (!"trace".equalsIgnoreCase(originalRootLogLevel)
|| !"trace".equalsIgnoreCase(originalEvmLogLevel)) {
// try again, this time with more logging so we can capture more information.

@ -124,9 +124,9 @@ public class DebugOperationTracerTest {
final Bytes32 word1 = Bytes32.fromHexString("0x01");
final Bytes32 word2 = Bytes32.fromHexString("0x02");
final Bytes32 word3 = Bytes32.fromHexString("0x03");
frame.writeMemory(UInt256.ZERO, UInt256.valueOf(32), word1);
frame.writeMemory(UInt256.valueOf(32), UInt256.valueOf(32), word2);
frame.writeMemory(UInt256.valueOf(64), UInt256.valueOf(32), word3);
frame.writeMemory(0, 32, word1);
frame.writeMemory(32, 32, word2);
frame.writeMemory(64, 32, word3);
final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(false, true, false));
assertThat(traceFrame.getMemory()).isPresent();
assertThat(traceFrame.getMemory().get()).containsExactly(word1, word2, word3);
@ -221,9 +221,9 @@ public class DebugOperationTracerTest {
final Bytes32 word1 = Bytes32.fromHexString("0x01");
final Bytes32 word2 = Bytes32.fromHexString("0x02");
final Bytes32 word3 = Bytes32.fromHexString("0x03");
frame.writeMemory(UInt256.ZERO, UInt256.valueOf(32), word1);
frame.writeMemory(UInt256.valueOf(32), UInt256.valueOf(32), word2);
frame.writeMemory(UInt256.valueOf(64), UInt256.valueOf(32), word3);
frame.writeMemory(0, 32, word1);
frame.writeMemory(32, 32, word2);
frame.writeMemory(64, 32, word3);
return updatedStorage;
}
}

@ -20,10 +20,10 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.OperationRegistry;
import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.operation.StopOperation;
import org.apache.tuweni.bytes.Bytes;

@ -21,7 +21,6 @@ import org.hyperledger.besu.evm.frame.Memory;
import com.google.common.base.Strings;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
import org.junit.Test;
public class MemoryTest {
@ -34,7 +33,7 @@ public class MemoryTest {
@Test
public void shouldSetAndGetMemoryByWord() {
final UInt256 index = UInt256.valueOf(20);
final int index = 20;
final Bytes32 value = Bytes32.fromHexString("0xABCDEF");
memory.setWord(index, value);
assertThat(memory.getWord(index)).isEqualTo(value);
@ -43,59 +42,59 @@ public class MemoryTest {
@Test
public void shouldSetMemoryWhenLengthEqualToSourceLength() {
final Bytes value = Bytes.concatenate(WORD1, WORD2, WORD3);
memory.setBytes(UInt256.ZERO, UInt256.valueOf(value.size()), value);
assertThat(memory.getWord(UInt256.ZERO)).isEqualTo(WORD1);
assertThat(memory.getWord(UInt256.valueOf(32))).isEqualTo(WORD2);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
memory.setBytes(0, value.size(), value);
assertThat(memory.getWord(0)).isEqualTo(WORD1);
assertThat(memory.getWord(32)).isEqualTo(WORD2);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
}
@Test
public void shouldSetMemoryWhenLengthLessThanSourceLength() {
final Bytes value = Bytes.concatenate(WORD1, WORD2, WORD3);
memory.setBytes(UInt256.ZERO, UInt256.valueOf(64), value);
assertThat(memory.getWord(UInt256.ZERO)).isEqualTo(WORD1);
assertThat(memory.getWord(UInt256.valueOf(32))).isEqualTo(WORD2);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(Bytes32.ZERO);
memory.setBytes(0, 64, value);
assertThat(memory.getWord(0)).isEqualTo(WORD1);
assertThat(memory.getWord(32)).isEqualTo(WORD2);
assertThat(memory.getWord(64)).isEqualTo(Bytes32.ZERO);
}
@Test
public void shouldSetMemoryWhenLengthGreaterThanSourceLength() {
final Bytes value = Bytes.concatenate(WORD1, WORD2);
memory.setBytes(UInt256.ZERO, UInt256.valueOf(96), value);
assertThat(memory.getWord(UInt256.ZERO)).isEqualTo(WORD1);
assertThat(memory.getWord(UInt256.valueOf(32))).isEqualTo(WORD2);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(Bytes32.ZERO);
memory.setBytes(0, 96, value);
assertThat(memory.getWord(0)).isEqualTo(WORD1);
assertThat(memory.getWord(32)).isEqualTo(WORD2);
assertThat(memory.getWord(64)).isEqualTo(Bytes32.ZERO);
}
@Test
public void shouldClearMemoryAfterSourceDataWhenLengthGreaterThanSourceLength() {
memory.setWord(UInt256.valueOf(64), WORD3);
memory.setWord(UInt256.valueOf(96), WORD4);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
assertThat(memory.getWord(UInt256.valueOf(96))).isEqualTo(WORD4);
memory.setWord(64, WORD3);
memory.setWord(96, WORD4);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
assertThat(memory.getWord(96)).isEqualTo(WORD4);
final Bytes value = Bytes.concatenate(WORD1, WORD2);
memory.setBytes(UInt256.ZERO, UInt256.valueOf(96), value);
assertThat(memory.getWord(UInt256.ZERO)).isEqualTo(WORD1);
assertThat(memory.getWord(UInt256.valueOf(32))).isEqualTo(WORD2);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(UInt256.valueOf(96))).isEqualTo(WORD4);
memory.setBytes(0, 96, value);
assertThat(memory.getWord(0)).isEqualTo(WORD1);
assertThat(memory.getWord(32)).isEqualTo(WORD2);
assertThat(memory.getWord(64)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(96)).isEqualTo(WORD4);
}
@Test
public void shouldClearMemoryAfterSourceDataWhenLengthGreaterThanSourceLengthWithMemoryOffset() {
memory.setWord(UInt256.valueOf(64), WORD3);
memory.setWord(UInt256.valueOf(96), WORD4);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
assertThat(memory.getWord(UInt256.valueOf(96))).isEqualTo(WORD4);
memory.setWord(64, WORD3);
memory.setWord(96, WORD4);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
assertThat(memory.getWord(96)).isEqualTo(WORD4);
final Bytes value = Bytes.concatenate(WORD1, WORD2);
memory.setBytes(UInt256.valueOf(10), UInt256.valueOf(96), value);
assertThat(memory.getWord(UInt256.valueOf(10))).isEqualTo(WORD1);
assertThat(memory.getWord(UInt256.valueOf(42))).isEqualTo(WORD2);
assertThat(memory.getWord(UInt256.valueOf(74))).isEqualTo(Bytes32.ZERO);
memory.setBytes(10, 96, value);
assertThat(memory.getWord(10)).isEqualTo(WORD1);
assertThat(memory.getWord(42)).isEqualTo(WORD2);
assertThat(memory.getWord(74)).isEqualTo(Bytes32.ZERO);
// Word 4 got partially cleared because of the starting offset.
assertThat(memory.getWord(UInt256.valueOf(106)))
assertThat(memory.getWord(106))
.isEqualTo(
Bytes32.fromHexString(
"0x4444444444444444444444444444444444444444444400000000000000000000"));
@ -103,50 +102,50 @@ public class MemoryTest {
@Test
public void shouldClearMemoryAfterSourceDataWhenSourceOffsetPlusLengthGreaterThanSourceLength() {
memory.setWord(UInt256.valueOf(64), WORD3);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
memory.setWord(64, WORD3);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
final Bytes value = Bytes.concatenate(WORD1, WORD2);
memory.setBytes(UInt256.ZERO, UInt256.valueOf(32), UInt256.valueOf(64), value);
assertThat(memory.getWord(UInt256.ZERO)).isEqualTo(WORD2);
assertThat(memory.getWord(UInt256.valueOf(32))).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
memory.setBytes(0, 32, 64, value);
assertThat(memory.getWord(0)).isEqualTo(WORD2);
assertThat(memory.getWord(32)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
}
@Test
public void shouldClearMemoryWhenSourceOffsetIsGreaterThanSourceLength() {
memory.setWord(UInt256.valueOf(64), WORD3);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
memory.setWord(64, WORD3);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
final Bytes value = Bytes.concatenate(WORD1, WORD2);
memory.setBytes(UInt256.ZERO, UInt256.valueOf(94), UInt256.valueOf(64), value);
assertThat(memory.getWord(UInt256.ZERO)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(UInt256.valueOf(32))).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
memory.setBytes(0, 94, 64, value);
assertThat(memory.getWord(0)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(32)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
}
@Test
public void shouldClearMemoryWhenSourceDataIsEmpty() {
memory.setWord(UInt256.valueOf(64), WORD3);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
memory.setWord(64, WORD3);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
memory.setBytes(UInt256.ZERO, UInt256.valueOf(96), Bytes.EMPTY);
memory.setBytes(0, 96, Bytes.EMPTY);
assertThat(memory.getWord(UInt256.ZERO)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(UInt256.valueOf(32))).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(0)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(32)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(64)).isEqualTo(Bytes32.ZERO);
}
@Test
public void shouldClearMemoryWhenSourceDataIsEmptyWithSourceOffset() {
memory.setWord(UInt256.valueOf(64), WORD3);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(WORD3);
memory.setWord(64, WORD3);
assertThat(memory.getWord(64)).isEqualTo(WORD3);
memory.setBytes(UInt256.ZERO, UInt256.ZERO, UInt256.valueOf(96), Bytes.EMPTY);
memory.setBytes(0, 0, 96, Bytes.EMPTY);
assertThat(memory.getWord(UInt256.ZERO)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(UInt256.valueOf(32))).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(UInt256.valueOf(64))).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(0)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(32)).isEqualTo(Bytes32.ZERO);
assertThat(memory.getWord(64)).isEqualTo(Bytes32.ZERO);
}
private static Bytes32 fillBytes32(final long value) {

@ -103,7 +103,7 @@ public class BlockHashOperationTest {
.pushStackItem(UInt256.fromBytes(input))
.build();
blockHashOperation.execute(frame, null);
final Bytes32 result = frame.popStackItem();
final Bytes result = frame.popStackItem();
assertThat(result).isEqualTo(expectedOutput);
assertThat(frame.stackSize()).isZero();
}

@ -157,9 +157,8 @@ public class Create2OperationTest {
messageFrame.pushStackItem(memoryLength);
messageFrame.pushStackItem(memoryOffset);
messageFrame.pushStackItem(UInt256.ZERO);
messageFrame.expandMemory(UInt256.ZERO, UInt256.valueOf(500));
messageFrame.writeMemory(
UInt256.fromBytes(memoryOffset), UInt256.valueOf(code.length()), codeBytes);
messageFrame.expandMemory(0, 500);
messageFrame.writeMemory(memoryOffset.trimLeadingZeros().toInt(), code.length(), codeBytes);
when(mutableAccount.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account);

@ -71,7 +71,7 @@ public class ExtCodeHashOperationTest {
@Test
public void shouldReturnZeroWhenAccountDoesNotExist() {
final Bytes32 result = executeOperation(REQUESTED_ADDRESS);
final Bytes result = executeOperation(REQUESTED_ADDRESS);
assertThat(result).isEqualTo(Bytes32.ZERO);
}
@ -121,7 +121,7 @@ public class ExtCodeHashOperationTest {
assertThat(frame.getStackItem(0)).isEqualTo(Hash.hash(code));
}
private Bytes32 executeOperation(final Address requestedAddress) {
private Bytes executeOperation(final Address requestedAddress) {
final MessageFrame frame = createMessageFrame(requestedAddress);
operation.execute(frame, null);
return frame.getStackItem(0);

@ -28,13 +28,13 @@ 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.OperationRegistry;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.hyperledger.besu.evm.operation.JumpOperation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.apache.tuweni.bytes.Bytes;
@ -132,4 +132,21 @@ public class JumpOperationTest {
final OperationResult result2 = operation.execute(frameDestinationEqualsToCodeSize, null);
assertThat(result2.getHaltReason()).contains(ExceptionalHaltReason.INVALID_JUMP_DESTINATION);
}
@Test
public void longContractsValidate() {
final JumpOperation operation = new JumpOperation(gasCalculator);
final MessageFrame longContract =
createMessageFrameBuilder(Gas.of(100))
.pushStackItem(UInt256.fromHexString("0x12c"))
.code(
new Code(
Bytes.fromHexString(
"0x60006000351461001157600050610018565b6101016020525b60016000351461002a5760005061002f565b326020525b60026000351461004157600050610046565b336020525b6003600035146100585760005061005d565b306020525b60046000351461006f57600050610075565b60016020525b60005160005260006020351461008d576000506100b6565b5a600052602051315060165a60005103036000555a600052602051315060165a60005103036001555b6001602035146100c8576000506100f1565b5a6000526020513b5060165a60005103036000555a6000526020513b5060165a60005103036001555b6002602035146101035760005061012c565b5a6000526020513f5060165a60005103036000555a6000526020513f5060165a60005103036001555b60036020351461013e5760005061017a565b6106a5610100525a600052602060006101006020513c60205a60005103036000555a600052602060006101006020513c60205a60005103036001555b00")))
.build();
longContract.setPC(255);
final OperationResult result = operation.execute(longContract, null);
assertThat(result.getHaltReason()).isEmpty();
}
}

@ -15,7 +15,7 @@
package org.hyperledger.besu.ethereum.vm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.evm.Gas;
@ -46,10 +46,9 @@ public class RevertOperationTest {
when(messageFrame.popStackItem())
.thenReturn(UInt256.fromHexString("0x00"))
.thenReturn(UInt256.fromHexString("0x0e"));
final UInt256 uint256_14 = UInt256.valueOf(0x0e);
when(messageFrame.readMemory(UInt256.ZERO, uint256_14)).thenReturn(revertReasonBytes);
when(messageFrame.memoryWordSize()).thenReturn(UInt256.ZERO);
when(messageFrame.calculateMemoryExpansion(any(), any())).thenReturn(uint256_14);
when(messageFrame.readMemory(0, 14)).thenReturn(revertReasonBytes);
when(messageFrame.memoryWordSize()).thenReturn(0);
when(messageFrame.calculateMemoryExpansion(anyLong(), anyLong())).thenReturn(14L);
when(messageFrame.getRemainingGas()).thenReturn(Gas.of(10_000));
}

@ -74,20 +74,20 @@ public final class GetBlockHeadersMessage extends AbstractMessageData {
}
/**
* Returns the block number that the message requests or {@link OptionalLong#EMPTY} if the request
* specifies a block hash.
* Returns the block number that the message requests or {@link OptionalLong#empty()} if the
* request specifies a block hash.
*
* @return Block Number Requested or {@link OptionalLong#EMPTY}
* @return Block Number Requested or {@link OptionalLong#empty()}
*/
public OptionalLong blockNumber() {
return getBlockHeadersData().blockNumber;
}
/**
* Returns the block hash that the message requests or {@link Optional#EMPTY} if the request
* Returns the block hash that the message requests or {@link Optional#empty()} if the request
* specifies a block number.
*
* @return Block Hash Requested or {@link Optional#EMPTY}
* @return Block Hash Requested or {@link Optional#empty()}
*/
public Optional<Hash> hash() {
return getBlockHeadersData().blockHash;

@ -64,9 +64,10 @@ public class BlockchainModule {
final MutableWorldState mutableWorldState =
new DefaultMutableWorldState(worldStateStorage, worldStatePreimageStorage);
genesisState.writeStateTo(mutableWorldState);
return mutableWorldState;
return (MutableWorldView) mutableWorldState;
} else {
return new DefaultMutableWorldState(stateRoot, worldStateStorage, worldStatePreimageStorage);
return (MutableWorldView)
new DefaultMutableWorldState(stateRoot, worldStateStorage, worldStatePreimageStorage);
}
}

@ -222,12 +222,16 @@ public class EvmToolCommand implements Runnable {
? new StandardJsonTracer(System.out, !noMemory)
: OperationTracer.NO_TRACING;
var updater = component.getWorldUpdater();
updater.getOrCreate(sender);
updater.getOrCreate(receiver);
final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
messageFrameStack.add(
MessageFrame.builder()
.type(MessageFrame.Type.MESSAGE_CALL)
.messageFrameStack(messageFrameStack)
.worldUpdater(component.getWorldUpdater())
.worldUpdater(updater)
.initialGas(gas)
.contract(Address.ZERO)
.address(receiver)
@ -284,6 +288,10 @@ public class EvmToolCommand implements Runnable {
protocolSpec
.getGasCalculator()
.transactionIntrinsicGasCost(tx.getPayload(), tx.isContractCreation());
final Gas accessListCost =
tx.getAccessList()
.map(list -> protocolSpec.getGasCalculator().accessListGasCost(list))
.orElse(Gas.ZERO);
final Gas evmGas = gas.minus(messageFrame.getRemainingGas());
out.println();
out.println(
@ -291,7 +299,13 @@ public class EvmToolCommand implements Runnable {
.put("gasUser", evmGas.asUInt256().toShortHexString())
.put("timens", lastTime)
.put("time", lastTime / 1000)
.put("gasTotal", evmGas.plus(intrinsicGasCost).asUInt256().toShortHexString()));
.put(
"gasTotal",
evmGas
.plus(intrinsicGasCost)
.plus(accessListCost)
.asUInt256()
.toShortHexString()));
}
}
lastTime = stopwatch.elapsed().toNanos();

@ -124,7 +124,7 @@ public class StateTestSubCommand implements Runnable {
objectMapper.readValue(file, javaType);
executeStateTest(generalStateTests);
} catch (final JsonProcessingException jpe) {
System.out.println("File content error :" + jpe.toString());
System.out.println("File content error :" + jpe);
}
} else {
System.out.println("File not found:" + fileName);
@ -215,10 +215,8 @@ public class StateTestSubCommand implements Runnable {
final ObjectNode summaryLine = objectMapper.createObjectNode();
summaryLine.put("output", result.getOutput().toUnprefixedHexString());
summaryLine.put(
"gasUsed",
StandardJsonTracer.shortNumber(
UInt256.valueOf(transaction.getGasLimit() - result.getGasRemaining())));
UInt256 gasUsed = UInt256.valueOf(transaction.getGasLimit() - result.getGasRemaining());
summaryLine.put("gasUsed", StandardJsonTracer.shortNumber(gasUsed));
summaryLine.put("time", timer.elapsed(TimeUnit.NANOSECONDS));
// Check the world state root hash.

@ -118,7 +118,11 @@ public class Packet {
final PacketType.Deserializer<?> deserializer = packetType.getDeserializer();
final PacketData packetData;
try {
packetData = deserializer.deserialize(RLP.input(message, PACKET_DATA_INDEX));
packetData =
deserializer.deserialize(
RLP.input(
Bytes.wrapBuffer(
message, PACKET_DATA_INDEX, message.length() - PACKET_DATA_INDEX)));
return new Packet(packetType, packetData, Bytes.wrapBuffer(message));
} catch (final RLPException e) {
throw new PeerDiscoveryPacketDecodingException("Malformed packet of type: " + packetType, e);

@ -46,6 +46,7 @@ dependencies {
testImplementation project(':config')
testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
testImplementation project(':evm')
testImplementation project(':testutil')
testImplementation 'io.vertx:vertx-core'
testImplementation 'junit:junit'

@ -34,7 +34,6 @@ dependencies {
api project(':util')
implementation 'com.google.guava:guava'
implementation 'io.vertx:vertx-core'
implementation 'org.apache.tuweni:tuweni-bytes'
implementation 'org.apache.tuweni:tuweni-units'

@ -18,7 +18,6 @@ import static java.lang.String.format;
import java.util.function.Consumer;
import io.vertx.core.buffer.Buffer;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.MutableBytes;
@ -59,27 +58,6 @@ public abstract class RLP {
return new BytesValueRLPInput(encoded, lenient);
}
/**
* Creates a new {@link RLPInput} suitable for decoding an RLP value encoded in the provided
* Vert.x {@link Buffer}.
*
* <p>The created input is strict, in that exceptions will be thrown for any malformed input,
* either by this method or by future reads from the returned input.
*
* @param buffer A buffer containing the RLP encoded data to decode.
* @param offset The offset in {@code encoded} at which the data to decode starts.
* @return A newly created {@link RLPInput} to decode RLP data in {@code encoded} from {@code
* offset}.
* @throws MalformedRLPInputException if {@code encoded} doesn't contain a properly encoded RLP
* item. Note that this only detect malformation on the main item at {@code offset}, but more
* deeply nested corruption/malformation of the input will not be detected by this method
* call, but only later when the input is read.
*/
public static BytesValueRLPInput input(final Buffer buffer, final int offset) {
return new BytesValueRLPInput(
Bytes.wrapBuffer(buffer, offset, buffer.length() - offset), false, false);
}
/**
* Creates a {@link RLPOutput}, pass it to the provided consumer for writing, and then return the
* RLP encoded result of that writing.

@ -17,28 +17,48 @@ package org.hyperledger.besu.evm;
import org.hyperledger.besu.datatypes.Address;
import java.util.List;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
@JsonSerialize(using = AccessListEntrySerializer.class)
@JsonDeserialize(using = AccessListEntryDeserializer.class)
public class AccessListEntry {
private final Address address;
private final List<Bytes32> storageKeys;
public AccessListEntry(final Address address, final List<Bytes32> storageKeys) {
this.address = address;
this.storageKeys = storageKeys;
}
@JsonCreator
public static AccessListEntry createAccessListEntry(
@JsonProperty("address") final Address address,
@JsonProperty("storageKeys") final List<String> storageKeys) {
return new AccessListEntry(
address, storageKeys.stream().map(Bytes32::fromHexString).collect(Collectors.toList()));
}
@JsonIgnore
public Address getAddress() {
return address;
}
@JsonIgnore
public List<Bytes32> getStorageKeys() {
return storageKeys;
}
@JsonProperty("address")
public String getAddressString() {
return address.toHexString();
}
@JsonProperty("storageKeys")
public List<String> getStorageKeysString() {
return storageKeys.stream().map(Bytes::toHexString).collect(Collectors.toList());
}
}

@ -1,54 +0,0 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm;
import static com.google.common.base.Preconditions.checkState;
import org.hyperledger.besu.datatypes.Address;
import java.io.IOException;
import java.util.ArrayList;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.apache.tuweni.bytes.Bytes32;
public class AccessListEntryDeserializer extends StdDeserializer<AccessListEntry> {
private AccessListEntryDeserializer() {
this(null);
}
protected AccessListEntryDeserializer(final Class<?> vc) {
super(vc);
}
@Override
public AccessListEntry deserialize(final JsonParser p, final DeserializationContext ctxt)
throws IOException {
checkState(p.nextFieldName().equals("address"));
final Address address = Address.fromHexString(p.nextTextValue());
checkState(p.nextFieldName().equals("storageKeys"));
checkState(p.nextToken().equals(JsonToken.START_ARRAY));
final ArrayList<Bytes32> storageKeys = new ArrayList<>();
while (!p.nextToken().equals(JsonToken.END_ARRAY)) {
storageKeys.add(Bytes32.fromHexString(p.getText()));
}
p.nextToken(); // consume end of object
return new AccessListEntry(address, storageKeys);
}
}

@ -1,52 +0,0 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm;
import java.io.IOException;
import java.util.List;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.apache.tuweni.bytes.Bytes32;
public class AccessListEntrySerializer extends StdSerializer<AccessListEntry> {
AccessListEntrySerializer() {
this(null);
}
protected AccessListEntrySerializer(final Class<AccessListEntry> t) {
super(t);
}
@Override
public void serialize(
final AccessListEntry accessListEntry,
final JsonGenerator gen,
final SerializerProvider provider)
throws IOException {
gen.writeStartObject();
gen.writeFieldName("address");
gen.writeString(accessListEntry.getAddress().toHexString());
gen.writeFieldName("storageKeys");
final List<Bytes32> storageKeys = accessListEntry.getStorageKeys();
gen.writeArray(
storageKeys.stream().map(Bytes32::toHexString).toArray(String[]::new),
0,
storageKeys.size());
gen.writeEndObject();
}
}

@ -16,9 +16,7 @@ package org.hyperledger.besu.evm;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.hyperledger.besu.evm.operation.Operation;
import java.util.BitSet;
import org.hyperledger.besu.evm.operation.PushOperation;
import com.google.common.base.MoreObjects;
import org.apache.tuweni.bytes.Bytes;
@ -31,7 +29,8 @@ public class Code {
private final Bytes bytes;
/** Used to cache valid jump destinations. */
private BitSet validJumpDestinations;
// private BitSet validJumpDestinations;
long[] validJumpDestinations;
/**
* Public constructor.
@ -93,16 +92,34 @@ public class Code {
if (validJumpDestinations == null) {
// Calculate valid jump destinations
validJumpDestinations = new BitSet(getSize());
evm.forEachOperation(
this,
(final Operation op, final Integer offset) -> {
if (op.getOpcode() == JumpDestOperation.OPCODE) {
validJumpDestinations.set(offset);
}
});
int size = getSize();
validJumpDestinations = new long[(size >> 6) + 1];
byte[] rawCode = getBytes().toArrayUnsafe();
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));
int j = i & 0x3F;
for (; j < max; i++, j++) {
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;
j += multiByteDataLen;
i += multiByteDataLen;
}
}
validJumpDestinations[entryPos] = thisEntry;
}
}
return validJumpDestinations.get(jumpDestination);
long targetLong = validJumpDestinations[jumpDestination >> 6];
long targetBit = 1L << (jumpDestination & 0x3F);
return (targetLong & targetBit) != 0L;
}
public Bytes getBytes() {

@ -25,6 +25,7 @@ import org.hyperledger.besu.evm.internal.FixedStack.UnderflowException;
import org.hyperledger.besu.evm.operation.InvalidOperation;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.operation.StopOperation;
import org.hyperledger.besu.evm.operation.VirtualOperation;
import org.hyperledger.besu.evm.tracing.OperationTracer;
@ -47,13 +48,19 @@ public class EVM {
Optional.empty(), Optional.of(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS));
private final OperationRegistry operations;
private final GasCalculator gasCalculator;
private final Operation endOfScriptStop;
public EVM(final OperationRegistry operations, final GasCalculator gasCalculator) {
this.operations = operations;
this.gasCalculator = gasCalculator;
this.endOfScriptStop = new VirtualOperation(new StopOperation(gasCalculator));
}
public GasCalculator getGasCalculator() {
return gasCalculator;
}
public void runToHalt(final MessageFrame frame, final OperationTracer operationTracer) {
while (frame.getState() == MessageFrame.State.CODE_EXECUTING) {
executeNextOperation(frame, operationTracer);

@ -20,6 +20,7 @@ import java.math.BigInteger;
import javax.annotation.concurrent.Immutable;
import com.google.common.primitives.Longs;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
@ -31,7 +32,7 @@ public final class Gas {
public static final Gas ZERO = of(0);
public static final Gas MAX_VALUE = Gas.of(Long.MAX_VALUE);
public static final Gas MAX_VALUE = of(Long.MAX_VALUE);
private static final BigInteger MAX_VALUE_BIGINT = BigInteger.valueOf(Long.MAX_VALUE);
@ -60,13 +61,26 @@ public final class Gas {
}
public static Gas of(final Bytes32 value) {
return Gas.of(UInt256.fromBytes(value));
return Gas.of((Bytes) value);
}
public static Gas of(final Bytes value) {
if (value.size() > 8 && value.trimLeadingZeros().size() > 8) {
return MAX_VALUE;
} else {
long gas = value.toLong();
if (gas < 0) {
return MAX_VALUE;
} else {
return Gas.of(gas);
}
}
}
public static Gas fromHexString(final String str) {
try {
final long value = Long.decode(str);
return of(value);
return Gas.of(value);
} catch (final NumberFormatException e) {
return MAX_VALUE;
}

@ -74,6 +74,7 @@ import org.hyperledger.besu.evm.operation.MulModOperation;
import org.hyperledger.besu.evm.operation.MulOperation;
import org.hyperledger.besu.evm.operation.NotOperation;
import org.hyperledger.besu.evm.operation.NumberOperation;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.operation.OrOperation;
import org.hyperledger.besu.evm.operation.OriginOperation;
import org.hyperledger.besu.evm.operation.PCOperation;

@ -0,0 +1,383 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm.fluent;
import org.hyperledger.besu.datatypes.Address;
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.MainnetEVMs;
import org.hyperledger.besu.evm.contractvalidation.ContractValidationRule;
import org.hyperledger.besu.evm.contractvalidation.MaxCodeSizeRule;
import org.hyperledger.besu.evm.contractvalidation.PrefixCodeRule;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.precompile.MainnetPrecompiledContracts;
import org.hyperledger.besu.evm.precompile.PrecompileContractRegistry;
import org.hyperledger.besu.evm.processor.ContractCreationProcessor;
import org.hyperledger.besu.evm.processor.MessageCallProcessor;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
public class EVMExecutor {
private PrecompileContractRegistry precompileContractRegistry;
private EVM evm;
private boolean commitWorldState = false;
private WorldUpdater worldUpdater = new SimpleWorld();
private Gas gas = Gas.MAX_VALUE;
private Address receiver = Address.ZERO;
private Address sender = Address.ZERO;
private Wei gasPriceGWei = Wei.ZERO;
private Bytes callData = Bytes.EMPTY;
private Wei ethValue = Wei.ZERO;
private Code code = new Code(Bytes.EMPTY);
private BlockValues blockValues = new SimpleBlockValues();
private OperationTracer tracer = OperationTracer.NO_TRACING;
private boolean requireDeposit = true;
private List<ContractValidationRule> contractValidationRules =
List.of(MaxCodeSizeRule.of(0x6000), PrefixCodeRule.of());
private long initialNonce = 0;
private Collection<Address> forceCommitAddresses = List.of(Address.fromHexString("0x03"));
private Set<Address> accessListWarmAddresses = Set.of();
private Multimap<Address, Bytes32> accessListWarmStorage = HashMultimap.create();
private MessageCallProcessor messageCallProcessor = null;
private ContractCreationProcessor contractCreationProcessor = null;
public static EVMExecutor evm(final EVM evm) {
EVMExecutor executor = new EVMExecutor();
executor.evm = evm;
return executor;
}
public static EVMExecutor frontier() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.frontier();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of();
executor.requireDeposit = false;
executor.forceCommitAddresses = List.of();
return executor;
}
public static EVMExecutor homestead() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.homestead();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of();
executor.forceCommitAddresses = List.of();
return executor;
}
public static EVMExecutor spuriousDragon() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.spuriousDragon();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
return executor;
}
public static EVMExecutor tangerineWhistle() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.tangerineWhistle();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
return executor;
}
public static EVMExecutor byzantium() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.byzantium();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
return executor;
}
public static EVMExecutor constantinople() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.constantinople();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
return executor;
}
public static EVMExecutor petersburg() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.petersburg();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
return executor;
}
public static EVMExecutor istanbul() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.istanbul();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
return executor;
}
public static EVMExecutor berlin() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.berlin();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
return executor;
}
public static EVMExecutor london() {
EVMExecutor executor = new EVMExecutor();
executor.evm = MainnetEVMs.istanbul();
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
return executor;
}
private MessageCallProcessor thisMessageCallProcessor() {
return Objects.requireNonNullElseGet(
messageCallProcessor, () -> new MessageCallProcessor(evm, precompileContractRegistry));
}
private ContractCreationProcessor thisContractCreationProcessor() {
return Objects.requireNonNullElseGet(
contractCreationProcessor,
() ->
new ContractCreationProcessor(
evm.getGasCalculator(),
evm,
requireDeposit,
contractValidationRules,
initialNonce,
forceCommitAddresses));
}
public Bytes execute(
final Code code, final Bytes inputData, final Wei value, final Address receiver) {
this.code = code;
this.callData = inputData;
this.ethValue = value;
this.receiver = receiver;
return execute();
}
public Bytes execute(
final Bytes codeBytes, final Bytes inputData, final Wei value, final Address receiver) {
this.code = new Code(codeBytes);
this.callData = inputData;
this.ethValue = value;
this.receiver = receiver;
return execute();
}
public Bytes execute() {
MessageCallProcessor mcp = thisMessageCallProcessor();
ContractCreationProcessor ccp = thisContractCreationProcessor();
final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
MessageFrame initialMessageFrame =
MessageFrame.builder()
.type(MessageFrame.Type.MESSAGE_CALL)
.messageFrameStack(messageFrameStack)
.worldUpdater(worldUpdater.updater())
.initialGas(gas)
.contract(Address.ZERO)
.address(receiver)
.originator(sender)
.sender(sender)
.gasPrice(gasPriceGWei)
.inputData(callData)
.value(ethValue)
.apparentValue(ethValue)
.code(code)
.blockValues(blockValues)
.depth(0)
.completer(c -> {})
.miningBeneficiary(Address.ZERO)
.blockHashLookup(h -> null)
.accessListWarmAddresses(accessListWarmAddresses)
.accessListWarmStorage(accessListWarmStorage)
.build();
messageFrameStack.add(initialMessageFrame);
while (!messageFrameStack.isEmpty()) {
final MessageFrame messageFrame = messageFrameStack.peek();
switch (messageFrame.getType()) {
case CONTRACT_CREATION:
mcp.process(messageFrame, tracer);
break;
case MESSAGE_CALL:
ccp.process(messageFrame, tracer);
break;
}
}
if (commitWorldState) {
worldUpdater.commit();
}
return initialMessageFrame.getReturnData();
}
public EVMExecutor commitWorldState() {
this.commitWorldState = true;
return this;
}
public EVMExecutor commitWorldState(final boolean commitWorldState) {
this.commitWorldState = commitWorldState;
return this;
}
public EVMExecutor worldUpdater(final WorldUpdater worldUpdater) {
this.worldUpdater = worldUpdater;
return this;
}
public EVMExecutor gas(final Gas gas) {
this.gas = gas;
return this;
}
public EVMExecutor receiver(final Address receiver) {
this.receiver = receiver;
return this;
}
public EVMExecutor sender(final Address sender) {
this.sender = sender;
return this;
}
public EVMExecutor gasPriceGWei(final Wei gasPriceGWei) {
this.gasPriceGWei = gasPriceGWei;
return this;
}
public EVMExecutor callData(final Bytes callData) {
this.callData = callData;
return this;
}
public EVMExecutor ethValue(final Wei ethValue) {
this.ethValue = ethValue;
return this;
}
public EVMExecutor code(final Code code) {
this.code = code;
return this;
}
public EVMExecutor code(final Bytes codeBytes) {
this.code = new Code(codeBytes);
return this;
}
public EVMExecutor blockValues(final BlockValues blockValues) {
this.blockValues = blockValues;
return this;
}
public EVMExecutor tracer(final OperationTracer tracer) {
this.tracer = tracer;
return this;
}
public EVMExecutor precompileContractRegistry(
final PrecompileContractRegistry precompileContractRegistry) {
this.precompileContractRegistry = precompileContractRegistry;
return this;
}
public EVMExecutor requireDeposit(final boolean requireDeposit) {
this.requireDeposit = requireDeposit;
return this;
}
public EVMExecutor initialNonce(final long initialNonce) {
this.initialNonce = initialNonce;
return this;
}
public EVMExecutor contractValidationRules(
final List<ContractValidationRule> contractValidationRules) {
this.contractValidationRules = contractValidationRules;
return this;
}
/**
* List of EIP-718 contracts that require special delete handling. By default, this is only the
* RIPEMD precompile contract.
*
* @see <a
* href="https://github.com/ethereum/EIPs/issues/716">https://github.com/ethereum/EIPs/issues/716</a>
* @param forceCommitAddresses collection of addresses for special handling
* @return fluent executor
*/
public EVMExecutor forceCommitAddresses(final Collection<Address> forceCommitAddresses) {
this.forceCommitAddresses = forceCommitAddresses;
return this;
}
public EVMExecutor accessListWarmAddresses(final Set<Address> accessListWarmAddresses) {
this.accessListWarmAddresses = accessListWarmAddresses;
return this;
}
public EVMExecutor warmAddress(final Address... addresses) {
this.accessListWarmAddresses.addAll(List.of(addresses));
return this;
}
public EVMExecutor accessListWarmStorage(final Multimap<Address, Bytes32> accessListWarmStorage) {
this.accessListWarmStorage = accessListWarmStorage;
return this;
}
public EVMExecutor accessListWarmStorage(final Address address, final Bytes32... slots) {
this.accessListWarmStorage.putAll(address, List.of(slots));
return this;
}
public EVMExecutor messageCallProcessor(final MessageCallProcessor messageCallProcessor) {
this.messageCallProcessor = messageCallProcessor;
return this;
}
public EVMExecutor contractCallProcessor(
final ContractCreationProcessor contractCreationProcessor) {
this.contractCreationProcessor = contractCreationProcessor;
return this;
}
}

@ -0,0 +1,158 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
package org.hyperledger.besu.evm.fluent;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.ModificationNotAllowedException;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.evm.account.EvmAccount;
import org.hyperledger.besu.evm.account.MutableAccount;
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
public class SimpleAccount implements EvmAccount, MutableAccount {
private final Account parent;
private Address address;
private final Supplier<Hash> addressHash =
Suppliers.memoize(() -> address == null ? Hash.ZERO : Hash.hash(address));
private long nonce;
private Wei balance;
private Bytes code;
private Supplier<Hash> codeHash =
Suppliers.memoize(() -> code == null ? Hash.EMPTY : Hash.hash(code));
private final Map<UInt256, UInt256> storage = new HashMap<>();
public SimpleAccount(final Address address, final long nonce, final Wei balance) {
this(null, address, nonce, balance, Bytes.EMPTY);
}
public SimpleAccount(
final Account parent,
final Address address,
final long nonce,
final Wei balance,
final Bytes code) {
this.parent = parent;
this.address = address;
this.nonce = nonce;
this.balance = balance;
this.code = code;
}
@Override
public Address getAddress() {
return address;
}
@Override
public Hash getAddressHash() {
return addressHash.get();
}
@Override
public long getNonce() {
return nonce;
}
@Override
public Wei getBalance() {
return balance;
}
@Override
public Bytes getCode() {
return code;
}
@Override
public Hash getCodeHash() {
return codeHash.get();
}
@Override
public UInt256 getStorageValue(final UInt256 key) {
if (storage.containsKey(key)) {
return storage.get(key);
} else {
return getOriginalStorageValue(key);
}
}
@Override
public UInt256 getOriginalStorageValue(final UInt256 key) {
if (parent != null) {
return parent.getStorageValue(key);
} else {
return UInt256.ZERO;
}
}
@Override
public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom(
final Bytes32 startKeyHash, final int limit) {
throw new UnsupportedOperationException(
"Storage iteration not supported in simple account facade");
}
@Override
public MutableAccount getMutable() throws ModificationNotAllowedException {
return this;
}
@Override
public void setNonce(final long value) {
nonce = value;
}
@Override
public void setBalance(final Wei value) {
balance = value;
}
@Override
public void setCode(final Bytes code) {
this.code = code;
codeHash = Suppliers.memoize(() -> this.code == null ? Hash.EMPTY : Hash.hash(this.code));
}
@Override
public void setStorageValue(final UInt256 key, final UInt256 value) {
storage.put(key, value);
}
@Override
public void clearStorage() {
storage.clear();
}
@Override
public Map<UInt256, UInt256> getUpdatedStorage() {
return storage;
}
}

@ -0,0 +1,21 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
package org.hyperledger.besu.evm.fluent;
import org.hyperledger.besu.evm.frame.BlockValues;
/** A concrete BlockValues object that takes all the defaults */
public class SimpleBlockValues implements BlockValues {}

@ -0,0 +1,109 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
package org.hyperledger.besu.evm.fluent;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.EvmAccount;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
public class SimpleWorld implements WorldUpdater {
SimpleWorld parent;
Map<Address, SimpleAccount> accounts = new HashMap<>();
public SimpleWorld() {
this(null);
}
public SimpleWorld(final SimpleWorld parent) {
this.parent = parent;
}
@Override
public WorldUpdater updater() {
return new SimpleWorld(this);
}
@Override
public Account get(final Address address) {
if (accounts.containsKey(address)) {
return accounts.get(address);
} else if (parent != null) {
return parent.get(address);
} else {
return null;
}
}
@Override
public EvmAccount createAccount(final Address address, final long nonce, final Wei balance) {
SimpleAccount account = new SimpleAccount(address, nonce, balance);
accounts.put(address, account);
return account;
}
@Override
public EvmAccount getAccount(final Address address) {
if (accounts.containsKey(address)) {
return accounts.get(address);
} else if (parent != null) {
return parent.getAccount(address);
} else {
return null;
}
}
@Override
public void deleteAccount(final Address address) {
accounts.put(address, null);
}
@Override
public Collection<? extends Account> getTouchedAccounts() {
return accounts.values();
}
@Override
public Collection<Address> getDeletedAccountAddresses() {
return accounts.entrySet().stream()
.filter(e -> e.getValue() == null)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
@Override
public void revert() {
accounts = new HashMap<>();
}
@Override
public void commit() {
parent.accounts.putAll(accounts);
}
@Override
public Optional<WorldUpdater> parentUpdater() {
return Optional.empty();
}
}

@ -22,7 +22,8 @@ public enum ExceptionalHaltReason {
INVALID_OPERATION("Bad instruction"),
INVALID_RETURN_DATA_BUFFER_ACCESS("Out of bounds"),
TOO_MANY_STACK_ITEMS("Out of stack"),
ILLEGAL_STATE_CHANGE("Illegal state change");
ILLEGAL_STATE_CHANGE("Illegal state change"),
OUT_OF_BOUNDS("Out of bounds");
String description;

@ -14,16 +14,12 @@
*/
package org.hyperledger.besu.evm.frame;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.MutableBytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.apache.tuweni.units.bigints.UInt256s;
/**
* A EVM memory implementation.
* An EVM memory implementation.
*
* <p>Note: this is meant to map to I in Section 9.1 "Basics" and Section 9.4.1 "Machine State" in
* the Yellow Paper Revision 59dccd.
@ -37,13 +33,12 @@ public class Memory {
* The data stored within the memory.
*
* <p>Note that the current Ethereum spec don't put a limit on memory, so we could theoretically
* overflow this. A byte array implementation limits us to 2GiB. But that would cost over 51
* overflow this. A byte array implementation limits us to 2 GiB. But that would cost over 51
* trillion gas. So this is likely a reasonable limitation, at least at first.
*/
private MutableBytes data;
private UInt256 activeWords;
private int dataSize256;
private int activeWords;
public Memory() {
data = MutableBytes.EMPTY;
@ -51,8 +46,7 @@ public class Memory {
}
private void updateSize() {
dataSize256 = data.size() / Bytes32.SIZE;
activeWords = UInt256.valueOf(dataSize256);
activeWords = data.size() / Bytes32.SIZE;
}
private static RuntimeException overflow(final long v) {
@ -72,63 +66,47 @@ public class Memory {
if (v < 0 || v >= MAX_BYTES) throw overflow(v);
}
private int asByteIndex(final UInt256 w) {
private int asByteIndex(final long w) {
try {
final long v = w.toLong();
final long v = Math.toIntExact(w);
checkByteIndex(v);
return (int) v;
} catch (final IllegalStateException e) {
throw overflow(w.toString());
throw overflow(w);
}
}
private static int asByteLength(final UInt256 l) {
private static int asByteLength(final long l) {
try {
// While we can theoretically support up to 32 * Integer.MAX_VALUE due to storing words, and
// so an index in memory need to be a long internally, we simply cannot load/store more than
// Integer.MAX_VALUE bytes at a time (Bytes has an int size).
return l.intValue();
} catch (final IllegalStateException e) {
throw overflow(l.toString());
return Math.toIntExact(l);
} catch (final ArithmeticException e) {
throw overflow(l);
}
}
/**
* For use in memoryExpansionGasCost() of GasCost. Returns the number of new active words that
* accommodate at least the number of specified bytes from the provide memory offset.
* accommodate at least the number of specified bytes from the provided memory offset.
*
* <p>Not that this has to return a UInt256 for Gas calculation, in case someone writes code that
* require a crazy amount of data. Such allocation should get prohibitive however and we will end
* require a crazy amount of data. Such allocation should get prohibitive however, and we will end
* up with an Out-of-Gas error.
*
* @param location The offset in memory from which we want to accommodate {@code numBytes}.
* @param numBytes The minimum number of bytes in memory.
* @return The number of active words that accommodate at least the number of specified bytes.
*/
UInt256 calculateNewActiveWords(final UInt256 location, final UInt256 numBytes) {
if (numBytes.isZero()) {
long calculateNewActiveWords(final long location, final long numBytes) {
if (numBytes == 0) {
return activeWords;
}
if (location.fitsInt() && numBytes.fitsInt()) {
// Fast common path (note that we work on int but use long arithmetic to avoid issues)
final long byteSize = location.toLong() + numBytes.toLong();
int wordSize = Math.toIntExact(byteSize / Bytes32.SIZE);
if (byteSize % Bytes32.SIZE != 0) wordSize += 1;
return wordSize > dataSize256 ? UInt256.valueOf(wordSize) : activeWords;
} else {
// Slow, rare path
// Note that this is one place where, while the result will fit UInt256, we should compute
// without modulo for extreme cases.
final BigInteger byteSize =
location.toUnsignedBigInteger().add(numBytes.toUnsignedBigInteger());
final BigInteger[] result = byteSize.divideAndRemainder(BigInteger.valueOf(Bytes32.SIZE));
BigInteger wordSize = result[0];
if (!result[1].equals(BigInteger.ZERO)) {
wordSize = wordSize.add(BigInteger.ONE);
}
return UInt256s.max(activeWords, UInt256.valueOf(wordSize));
try {
final long byteSize = Math.addExact(Math.addExact(location, numBytes), 31);
long wordSize = byteSize / 32;
return Math.max(wordSize, activeWords);
} catch (ArithmeticException ae) {
return Long.MAX_VALUE >> 5;
}
}
@ -138,27 +116,15 @@ public class Memory {
* @param offset The location in memory to start with.
* @param numBytes The number of bytes to get.
*/
void ensureCapacityForBytes(final UInt256 offset, final UInt256 numBytes) {
if (!offset.fitsInt()) return;
if (!numBytes.fitsInt()) return;
ensureCapacityForBytes(offset.intValue(), numBytes.intValue());
}
/**
* Expands the active words to accommodate the specified byte position.
*
* @param offset The location in memory to start with.
* @param numBytes The number of bytes to get.
*/
void ensureCapacityForBytes(final int offset, final int numBytes) {
void ensureCapacityForBytes(final long offset, final long numBytes) {
// Do not increase the memory capacity if no bytes are being written
// regardless of what the address may be.
if (numBytes == 0) {
return;
}
final int lastByteIndex = Math.addExact(offset, numBytes);
final int lastWordRequired = ((lastByteIndex - 1) / Bytes32.SIZE);
maybeExpandCapacity(lastWordRequired + 1);
final long lastByteIndex = Math.addExact(offset, numBytes);
final long lastWordRequired = ((lastByteIndex - 1) / Bytes32.SIZE);
maybeExpandCapacity((int) lastWordRequired + 1);
}
/**
@ -167,7 +133,7 @@ public class Memory {
* @param newActiveWords The new number of active words to expand to.
*/
private void maybeExpandCapacity(final int newActiveWords) {
if (dataSize256 >= newActiveWords) return;
if (activeWords >= newActiveWords) return;
// Require full capacity to guarantee we don't resize more than once.
final MutableBytes newData = MutableBytes.create(newActiveWords * Bytes32.SIZE);
@ -211,7 +177,7 @@ public class Memory {
*
* @return The current number of active words stored in memory.
*/
UInt256 getActiveWords() {
int getActiveWords() {
return activeWords;
}
@ -223,9 +189,9 @@ public class Memory {
* @return A fresh copy of the bytes from memory starting at {@code location} and extending {@code
* numBytes}.
*/
public Bytes getBytes(final UInt256 location, final UInt256 numBytes) {
public Bytes getBytes(final long location, final long numBytes) {
// Note: if length == 0, we don't require any memory expansion, whatever location is. So
// we we must call asByteIndex(location) after this check so as it doesn't throw if the location
// we must call asByteIndex(location) after this check so as it doesn't throw if the location
// is too big but the length is 0 (which is somewhat nonsensical, but is exercise by some
// tests).
final int length = asByteLength(numBytes);
@ -236,7 +202,7 @@ public class Memory {
final int start = asByteIndex(location);
ensureCapacityForBytes(start, length);
return data.slice(start, numBytes.intValue());
return data.slice(start, length);
}
/**
@ -247,10 +213,10 @@ public class Memory {
* copied and so never fails.
*
* @param memOffset the location in memory at which to start copying the bytes of {@code value}.
* @param sourceOffset the location in the source to start copying.
* @param numBytes the number of bytes to set in memory. Note that this value may differ from
* {@code value.size()}: if {@code numBytes < value.size()} bytes, only {@code numBytes} will
* be copied from {@code value}; if {@code numBytes < value.size()}, then only the bytes in
* @param offset the location in the source to start copying.
* @param length the number of bytes to set in memory. Note that this value may differ from {@code
* value.size()}: if {@code numBytes < value.size()} bytes, only {@code numBytes} will be
* copied from {@code value}; if {@code numBytes < value.size()}, then only the bytes in
* {@code value} will be copied, but the memory will be expanded if necessary to cover {@code
* numBytes} (in other words, {@link #getActiveWords()} will return a value consistent with
* having set {@code numBytes} bytes, even if less than that have been concretely set due to
@ -258,20 +224,16 @@ public class Memory {
* @param bytes the bytes to copy to memory from {@code location}.
*/
public void setBytes(
final UInt256 memOffset,
final UInt256 sourceOffset,
final UInt256 numBytes,
final Bytes bytes) {
final int offset = sourceOffset.fitsInt() ? sourceOffset.intValue() : Integer.MAX_VALUE;
final int length = numBytes.fitsInt() ? numBytes.intValue() : Integer.MAX_VALUE;
final long memOffset, final long offset, final long length, final Bytes bytes) {
if (offset >= bytes.size()) {
clearBytes(memOffset, numBytes);
clearBytes(memOffset, length);
return;
}
final Bytes toCopy = bytes.slice(offset, Math.min(length, bytes.size() - offset));
setBytes(memOffset, numBytes, toCopy);
final Bytes toCopy =
bytes.slice((int) offset, Math.min((int) length, bytes.size() - (int) offset));
setBytes(memOffset, length, toCopy);
}
/**
@ -291,8 +253,8 @@ public class Memory {
* {@code value} being smaller).
* @param taintedValue the bytes to copy to memory from {@code location}.
*/
public void setBytes(final UInt256 location, final UInt256 numBytes, final Bytes taintedValue) {
if (numBytes.isZero()) {
public void setBytes(final long location, final long numBytes, final Bytes taintedValue) {
if (numBytes == 0) {
return;
}
@ -316,7 +278,7 @@ public class Memory {
* @param location The location in memory from which to start clearing the bytes.
* @param numBytes The number of bytes to clear.
*/
private void clearBytes(final UInt256 location, final UInt256 numBytes) {
private void clearBytes(final long location, final long numBytes) {
// See getBytes for why we check length == 0 first, before calling asByteIndex(location).
final int length = asByteLength(numBytes);
if (length == 0) {
@ -346,7 +308,7 @@ public class Memory {
* @param location the location of the byte to set.
* @param value the value to set for the byte at {@code location}.
*/
void setByte(final UInt256 location, final byte value) {
void setByte(final long location, final byte value) {
final int start = asByteIndex(location);
ensureCapacityForBytes(start, 1);
data.set(start, value);
@ -358,7 +320,7 @@ public class Memory {
* @param location The memory location the 256-bit word begins at.
* @return a copy of the 32-bytes word that begins at the specified memory location.
*/
public Bytes32 getWord(final UInt256 location) {
public Bytes32 getWord(final long location) {
final int start = asByteIndex(location);
ensureCapacityForBytes(start, Bytes32.SIZE);
return Bytes32.wrap(data.slice(start, Bytes32.SIZE));
@ -373,7 +335,7 @@ public class Memory {
* @param location the location at which to start setting the bytes.
* @param bytes the 32 bytes to copy at {@code location}.
*/
public void setWord(final UInt256 location, final Bytes32 bytes) {
public void setWord(final long location, final Bytes32 bytes) {
final int start = asByteIndex(location);
ensureCapacityForBytes(start, Bytes32.SIZE);
data.set(start, bytes);

@ -25,6 +25,7 @@ import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.internal.FixedStack.UnderflowException;
import org.hyperledger.besu.evm.internal.MemoryEntry;
import org.hyperledger.besu.evm.internal.OperandStack;
import org.hyperledger.besu.evm.internal.StorageEntry;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@ -212,8 +213,8 @@ public class MessageFrame {
private Gas gasRefund;
private final Set<Address> selfDestructs;
private final Map<Address, Wei> refunds;
private Set<Address> warmedUpAddresses;
private Multimap<Address, Bytes32> warmedUpStorage;
private final Set<Address> warmedUpAddresses;
private final Multimap<Address, Bytes32> warmedUpStorage;
// Execution Environment fields.
private final Address recipient;
@ -227,6 +228,7 @@ public class MessageFrame {
private final Code code;
private final BlockValues blockValues;
private final int depth;
private final MessageFrame parentMessageFrame;
private final Deque<MessageFrame> messageFrameStack;
private final Address miningBeneficiary;
private Optional<Bytes> revertReason;
@ -239,7 +241,7 @@ public class MessageFrame {
private Optional<Gas> gasCost = Optional.empty();
private final Consumer<MessageFrame> completer;
private Optional<MemoryEntry> maybeUpdatedMemory = Optional.empty();
private Optional<MemoryEntry> maybeUpdatedStorage = Optional.empty();
private Optional<StorageEntry> maybeUpdatedStorage = Optional.empty();
public static Builder builder() {
return new Builder();
@ -272,6 +274,7 @@ public class MessageFrame {
final Multimap<Address, Bytes32> accessListWarmStorage) {
this.type = type;
this.messageFrameStack = messageFrameStack;
this.parentMessageFrame = messageFrameStack.peek();
this.worldUpdater = worldUpdater;
this.gasRemaining = initialGas;
this.blockHashLookup = blockHashLookup;
@ -435,7 +438,7 @@ public class MessageFrame {
* @return The item at the specified offset in the stack
* @throws UnderflowException if the offset is out of range
*/
public UInt256 getStackItem(final int offset) {
public Bytes getStackItem(final int offset) {
return stack.get(offset);
}
@ -445,7 +448,7 @@ public class MessageFrame {
* @return the item at the top of the stack
* @throws UnderflowException if the stack is empty
*/
public UInt256 popStackItem() {
public Bytes popStackItem() {
return stack.pop();
}
@ -463,7 +466,7 @@ public class MessageFrame {
*
* @param value The value to push onto the stack.
*/
public void pushStackItem(final UInt256 value) {
public void pushStackItem(final Bytes value) {
stack.push(value);
}
@ -474,7 +477,7 @@ public class MessageFrame {
* @param value The value to set the stack item to
* @throws IllegalStateException if the stack is too small
*/
public void setStackItem(final int offset, final UInt256 value) {
public void setStackItem(final int offset, final Bytes value) {
stack.set(offset, value);
}
@ -503,7 +506,7 @@ public class MessageFrame {
* @param length The length of the memory access
* @return the memory size for specified memory access
*/
public UInt256 calculateMemoryExpansion(final UInt256 offset, final UInt256 length) {
public long calculateMemoryExpansion(final long offset, final long length) {
return memory.calculateNewActiveWords(offset, length);
}
@ -513,7 +516,7 @@ public class MessageFrame {
* @param offset The offset in memory
* @param length The length of the memory access
*/
public void expandMemory(final UInt256 offset, final UInt256 length) {
public void expandMemory(final long offset, final long length) {
memory.ensureCapacityForBytes(offset, length);
}
@ -531,7 +534,7 @@ public class MessageFrame {
*
* @return the number of words in memory
*/
public UInt256 memoryWordSize() {
public int memoryWordSize() {
return memory.getActiveWords();
}
@ -556,7 +559,7 @@ public class MessageFrame {
* @param length The length of the bytes to read
* @return The bytes in the specified range
*/
public Bytes readMutableMemory(final UInt256 offset, final UInt256 length) {
public Bytes readMutableMemory(final long offset, final long length) {
return readMutableMemory(offset, length, false);
}
@ -567,7 +570,7 @@ public class MessageFrame {
* @param length The length of the bytes to read
* @return The bytes in the specified range
*/
public Bytes readMemory(final UInt256 offset, final UInt256 length) {
public Bytes readMemory(final long offset, final long length) {
return readMutableMemory(offset, length, false).copy();
}
@ -581,7 +584,7 @@ public class MessageFrame {
* @return The bytes in the specified range
*/
public Bytes readMutableMemory(
final UInt256 offset, final UInt256 length, final boolean explicitMemoryRead) {
final long offset, final long length, final boolean explicitMemoryRead) {
final Bytes value = memory.getBytes(offset, length);
if (explicitMemoryRead) {
setUpdatedMemory(offset, value);
@ -596,8 +599,7 @@ public class MessageFrame {
* @param value The value to set in memory
* @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise
*/
public void writeMemory(
final UInt256 offset, final byte value, final boolean explicitMemoryUpdate) {
public void writeMemory(final long offset, final byte value, final boolean explicitMemoryUpdate) {
memory.setByte(offset, value);
if (explicitMemoryUpdate) {
setUpdatedMemory(offset, Bytes.of(value));
@ -611,7 +613,7 @@ public class MessageFrame {
* @param length The length of the bytes to write
* @param value The value to write
*/
public void writeMemory(final UInt256 offset, final UInt256 length, final Bytes value) {
public void writeMemory(final long offset, final long length, final Bytes value) {
writeMemory(offset, length, value, false);
}
@ -624,13 +626,10 @@ public class MessageFrame {
* @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise
*/
public void writeMemory(
final UInt256 offset,
final UInt256 length,
final Bytes value,
final boolean explicitMemoryUpdate) {
final long offset, final long length, final Bytes value, final boolean explicitMemoryUpdate) {
memory.setBytes(offset, length, value);
if (explicitMemoryUpdate) {
setUpdatedMemory(offset, UInt256.ZERO, length, value);
setUpdatedMemory(offset, 0, length, value);
}
}
@ -643,7 +642,7 @@ public class MessageFrame {
* @param value The value to write
*/
public void writeMemory(
final UInt256 offset, final UInt256 sourceOffset, final UInt256 length, final Bytes value) {
final long offset, final long sourceOffset, final long length, final Bytes value) {
writeMemory(offset, sourceOffset, length, value, false);
}
@ -657,42 +656,40 @@ public class MessageFrame {
* @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise
*/
public void writeMemory(
final UInt256 offset,
final UInt256 sourceOffset,
final UInt256 length,
final long offset,
final long sourceOffset,
final long length,
final Bytes value,
final boolean explicitMemoryUpdate) {
memory.setBytes(offset, sourceOffset, length, value);
if (explicitMemoryUpdate && length.toLong() > 0) {
if (explicitMemoryUpdate && length > 0) {
setUpdatedMemory(offset, sourceOffset, length, value);
}
}
private void setUpdatedMemory(
final UInt256 offset, final UInt256 sourceOffset, final UInt256 length, final Bytes value) {
final int srcOff = sourceOffset.fitsInt() ? sourceOffset.intValue() : Integer.MAX_VALUE;
final int len = length.fitsInt() ? length.intValue() : Integer.MAX_VALUE;
final int endIndex = srcOff + len;
if (srcOff >= 0 && endIndex > 0) {
final long offset, final long sourceOffset, final long length, final Bytes value) {
final long endIndex = sourceOffset + length;
if (sourceOffset >= 0 && endIndex > 0) {
final int srcSize = value.size();
if (endIndex > srcSize) {
final MutableBytes paddedAnswer = MutableBytes.create(len);
if (srcOff < srcSize) {
value.slice(srcOff, srcSize - srcOff).copyTo(paddedAnswer, 0);
final MutableBytes paddedAnswer = MutableBytes.create((int) length);
if (sourceOffset < srcSize) {
value.slice((int) sourceOffset, (int) (srcSize - sourceOffset)).copyTo(paddedAnswer, 0);
}
setUpdatedMemory(offset, paddedAnswer.copy());
} else {
setUpdatedMemory(offset, value.slice(srcOff, len).copy());
setUpdatedMemory(offset, value.slice((int) sourceOffset, (int) length).copy());
}
}
}
private void setUpdatedMemory(final UInt256 offset, final Bytes value) {
private void setUpdatedMemory(final long offset, final Bytes value) {
maybeUpdatedMemory = Optional.of(new MemoryEntry(offset, value));
}
public void storageWasUpdated(final UInt256 storageAddress, final Bytes value) {
maybeUpdatedStorage = Optional.of(new MemoryEntry(storageAddress, value));
maybeUpdatedStorage = Optional.of(new StorageEntry(storageAddress, value));
}
/**
* Accumulate a log.
@ -807,7 +804,22 @@ public class MessageFrame {
* @return true if the address was already warmed up
*/
public boolean warmUpAddress(final Address address) {
return !warmedUpAddresses.add(address);
if (warmedUpAddresses.add(address)) {
return parentMessageFrame != null && parentMessageFrame.isWarm(address);
} else {
return true;
}
}
private boolean isWarm(final Address address) {
MessageFrame frame = this;
while (frame != null) {
if (frame.warmedUpAddresses.contains(address)) {
return true;
}
frame = frame.parentMessageFrame;
}
return false;
}
/**
@ -818,16 +830,22 @@ public class MessageFrame {
* @return true if the storage slot was already warmed up
*/
public boolean warmUpStorage(final Address address, final Bytes32 slot) {
return !warmedUpStorage.put(address, slot);
if (warmedUpStorage.put(address, slot)) {
return parentMessageFrame != null && parentMessageFrame.isWarm(address, slot);
} else {
return true;
}
}
public void copyWarmedUpFields(final MessageFrame parentFrame) {
if (parentFrame == this) {
return;
private boolean isWarm(final Address address, final Bytes32 slot) {
MessageFrame frame = this;
while (frame != null) {
if (frame.warmedUpStorage.containsEntry(address, slot)) {
return true;
}
frame = frame.parentMessageFrame;
}
warmedUpAddresses = new HashSet<>(parentFrame.warmedUpAddresses);
warmedUpStorage = HashMultimap.create(parentFrame.warmedUpStorage);
return false;
}
public void mergeWarmedUpFields(final MessageFrame childFrame) {
@ -835,8 +853,8 @@ public class MessageFrame {
return;
}
warmedUpAddresses = childFrame.warmedUpAddresses;
warmedUpStorage = childFrame.warmedUpStorage;
warmedUpAddresses.addAll(childFrame.warmedUpAddresses);
warmedUpStorage.putAll(childFrame.warmedUpStorage);
}
/**
@ -1048,7 +1066,7 @@ public class MessageFrame {
return maybeUpdatedMemory;
}
public Optional<MemoryEntry> getMaybeUpdatedStorage() {
public Optional<StorageEntry> getMaybeUpdatedStorage() {
return maybeUpdatedStorage;
}

@ -128,10 +128,10 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
public Gas callOperationGasCost(
final MessageFrame frame,
final Gas stipend,
final UInt256 inputDataOffset,
final UInt256 inputDataLength,
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final long inputDataOffset,
final long inputDataLength,
final long outputDataOffset,
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to) {
@ -153,7 +153,7 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
// defined in Frontier, but re-implemented with no base cost.
@Override
public Gas extCodeCopyOperationGasCost(
final MessageFrame frame, final UInt256 offset, final UInt256 length) {
final MessageFrame frame, final long offset, final long length) {
return copyWordsToMemoryGasCost(frame, Gas.ZERO, COPY_WORD_GAS_COST, offset, length);
}

@ -36,8 +36,8 @@ public class ConstantinopleGasCalculator extends ByzantiumGasCalculator {
@Override
public Gas create2OperationGasCost(final MessageFrame frame) {
final UInt256 initCodeLength = frame.getStackItem(2);
final UInt256 numWords = initCodeLength.divideCeil(Bytes32.SIZE);
final UInt256 initCodeLength = UInt256.fromBytes(frame.getStackItem(2));
final UInt256 numWords = UInt256.fromBytes(initCodeLength.divideCeil(Bytes32.SIZE));
final Gas initCodeHashCost = SHA3_OPERATION_WORD_GAS_COST.times(Gas.of(numWords));
return createOperationGasCost(frame).plus(initCodeHashCost);
}

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.gascalculator;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Gas;
@ -23,7 +25,6 @@ import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.operation.ExpOperation;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
public class FrontierGasCalculator implements GasCalculator {
@ -230,10 +231,10 @@ public class FrontierGasCalculator implements GasCalculator {
public Gas callOperationGasCost(
final MessageFrame frame,
final Gas stipend,
final UInt256 inputDataOffset,
final UInt256 inputDataLength,
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final long inputDataOffset,
final long inputDataLength,
final long outputDataOffset,
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to) {
@ -278,8 +279,8 @@ public class FrontierGasCalculator implements GasCalculator {
@Override
public Gas createOperationGasCost(final MessageFrame frame) {
final UInt256 initCodeOffset = frame.getStackItem(1);
final UInt256 initCodeLength = frame.getStackItem(2);
final long initCodeOffset = clampedToLong(frame.getStackItem(1));
final long initCodeLength = clampedToLong(frame.getStackItem(2));
final Gas memoryGasCost = memoryExpansionGasCost(frame, initCodeOffset, initCodeLength);
return CREATE_OPERATION_GAS_COST.plus(memoryGasCost);
@ -292,14 +293,14 @@ public class FrontierGasCalculator implements GasCalculator {
@Override
public Gas dataCopyOperationGasCost(
final MessageFrame frame, final UInt256 offset, final UInt256 length) {
final MessageFrame frame, final long offset, final long length) {
return copyWordsToMemoryGasCost(
frame, VERY_LOW_TIER_GAS_COST, COPY_WORD_GAS_COST, offset, length);
}
@Override
public Gas memoryExpansionGasCost(
final MessageFrame frame, final UInt256 offset, final UInt256 length) {
final MessageFrame frame, final long offset, final long length) {
final Gas pre = memoryCost(frame.memoryWordSize());
final Gas post = memoryCost(frame.calculateMemoryExpansion(offset, length));
@ -342,7 +343,7 @@ public class FrontierGasCalculator implements GasCalculator {
@Override
public Gas extCodeCopyOperationGasCost(
final MessageFrame frame, final UInt256 offset, final UInt256 length) {
final MessageFrame frame, final long offset, final long length) {
return copyWordsToMemoryGasCost(
frame, extCodeBaseGasCost(), COPY_WORD_GAS_COST, offset, length);
}
@ -365,10 +366,7 @@ public class FrontierGasCalculator implements GasCalculator {
@Override
public Gas logOperationGasCost(
final MessageFrame frame,
final UInt256 dataOffset,
final UInt256 dataLength,
final int numTopics) {
final MessageFrame frame, final long dataOffset, final long dataLength, final int numTopics) {
return Gas.ZERO
.plus(LOG_OPERATION_BASE_GAS_COST)
.plus(LOG_OPERATION_DATA_BYTE_GAS_COST.times(Gas.of(dataLength)))
@ -377,18 +375,18 @@ public class FrontierGasCalculator implements GasCalculator {
}
@Override
public Gas mLoadOperationGasCost(final MessageFrame frame, final UInt256 offset) {
return VERY_LOW_TIER_GAS_COST.plus(memoryExpansionGasCost(frame, offset, UInt256.valueOf(32)));
public Gas mLoadOperationGasCost(final MessageFrame frame, final long offset) {
return VERY_LOW_TIER_GAS_COST.plus(memoryExpansionGasCost(frame, offset, 32));
}
@Override
public Gas mStoreOperationGasCost(final MessageFrame frame, final UInt256 offset) {
return VERY_LOW_TIER_GAS_COST.plus(memoryExpansionGasCost(frame, offset, UInt256.valueOf(32)));
public Gas mStoreOperationGasCost(final MessageFrame frame, final long offset) {
return VERY_LOW_TIER_GAS_COST.plus(memoryExpansionGasCost(frame, offset, 32));
}
@Override
public Gas mStore8OperationGasCost(final MessageFrame frame, final UInt256 offset) {
return VERY_LOW_TIER_GAS_COST.plus(memoryExpansionGasCost(frame, offset, UInt256.ONE));
public Gas mStore8OperationGasCost(final MessageFrame frame, final long offset) {
return VERY_LOW_TIER_GAS_COST.plus(memoryExpansionGasCost(frame, offset, 1));
}
@Override
@ -397,8 +395,7 @@ public class FrontierGasCalculator implements GasCalculator {
}
@Override
public Gas sha3OperationGasCost(
final MessageFrame frame, final UInt256 offset, final UInt256 length) {
public Gas sha3OperationGasCost(final MessageFrame frame, final long offset, final long length) {
return copyWordsToMemoryGasCost(
frame, SHA3_OPERATION_BASE_GAS_COST, SHA3_OPERATION_WORD_GAS_COST, offset, length);
}
@ -439,9 +436,9 @@ public class FrontierGasCalculator implements GasCalculator {
final MessageFrame frame,
final Gas baseGasCost,
final Gas wordGasCost,
final UInt256 offset,
final UInt256 length) {
final UInt256 numWords = length.divideCeil(Bytes32.SIZE);
final long offset,
final long length) {
final long numWords = length / 32 + (length % 32 == 0 ? 0 : 1);
final Gas copyCost = wordGasCost.times(Gas.of(numWords)).plus(baseGasCost);
final Gas memoryCost = memoryExpansionGasCost(frame, offset, length);
@ -449,10 +446,7 @@ public class FrontierGasCalculator implements GasCalculator {
return copyCost.plus(memoryCost);
}
private static Gas memoryCost(final UInt256 length) {
if (!length.fitsInt()) {
return Gas.MAX_VALUE;
}
private static Gas memoryCost(final long length) {
final Gas len = Gas.of(length);
final Gas base = len.times(len).dividedBy(512);

@ -161,10 +161,10 @@ public interface GasCalculator {
Gas callOperationGasCost(
MessageFrame frame,
Gas stipend,
UInt256 inputDataOffset,
UInt256 inputDataLength,
UInt256 outputDataOffset,
UInt256 outputDataLength,
long inputDataOffset,
long inputDataLength,
long outputDataOffset,
long outputDataLength,
Wei transferValue,
Account recipient,
Address contract);
@ -215,7 +215,7 @@ public interface GasCalculator {
* @param length The length of the data being copied into memory
* @return the amount of gas consumed by the data copy operation
*/
Gas dataCopyOperationGasCost(MessageFrame frame, UInt256 offset, UInt256 length);
Gas dataCopyOperationGasCost(MessageFrame frame, long offset, long length);
/**
* Returns the cost of expanding memory for the specified access.
@ -225,7 +225,7 @@ public interface GasCalculator {
* @param length the length of the memory access
* @return The gas required to expand memory for the specified access
*/
Gas memoryExpansionGasCost(MessageFrame frame, UInt256 offset, UInt256 length);
Gas memoryExpansionGasCost(MessageFrame frame, long offset, long length);
// Specific Non-call Operation Calculations
@ -259,7 +259,7 @@ public interface GasCalculator {
* @param length The length of the code being copied into memory
* @return the cost for executing the external code size operation
*/
Gas extCodeCopyOperationGasCost(MessageFrame frame, UInt256 offset, UInt256 length);
Gas extCodeCopyOperationGasCost(MessageFrame frame, long offset, long length);
/**
* Returns the cost for executing a {@link ExtCodeHashOperation}.
@ -291,8 +291,7 @@ public interface GasCalculator {
* @param numTopics The number of topics in the log
* @return the cost for executing the external code size operation
*/
Gas logOperationGasCost(
MessageFrame frame, UInt256 dataOffset, UInt256 dataLength, int numTopics);
Gas logOperationGasCost(MessageFrame frame, long dataOffset, long dataLength, int numTopics);
/**
* Returns the cost for executing a {@link MLoadOperation}.
@ -301,7 +300,7 @@ public interface GasCalculator {
* @param offset The offset in memory where the access takes place
* @return the cost for executing the memory load operation
*/
Gas mLoadOperationGasCost(MessageFrame frame, UInt256 offset);
Gas mLoadOperationGasCost(MessageFrame frame, long offset);
/**
* Returns the cost for executing a {@link MStoreOperation}.
@ -310,7 +309,7 @@ public interface GasCalculator {
* @param offset The offset in memory where the access takes place
* @return the cost for executing the memory store operation
*/
Gas mStoreOperationGasCost(MessageFrame frame, UInt256 offset);
Gas mStoreOperationGasCost(MessageFrame frame, long offset);
/**
* Returns the cost for executing a {@link MStore8Operation}.
@ -319,7 +318,7 @@ public interface GasCalculator {
* @param offset The offset in memory where the access takes place
* @return the cost for executing the memory byte store operation
*/
Gas mStore8OperationGasCost(MessageFrame frame, UInt256 offset);
Gas mStore8OperationGasCost(MessageFrame frame, long offset);
/**
* Returns the cost for executing a {@link SelfDestructOperation}.
@ -338,7 +337,7 @@ public interface GasCalculator {
* @param length The hashed data length
* @return the cost for executing the memory byte store operation
*/
Gas sha3OperationGasCost(MessageFrame frame, UInt256 offset, UInt256 length);
Gas sha3OperationGasCost(MessageFrame frame, long offset, long length);
/**
* Returns the cost for executing a {@link SLoadOperation}.

@ -20,8 +20,6 @@ import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.apache.tuweni.units.bigints.UInt256;
public class SpuriousDragonGasCalculator extends TangerineWhistleGasCalculator {
private static final Gas EXP_OPERATION_BYTE_GAS_COST = Gas.of(50L);
@ -30,10 +28,10 @@ public class SpuriousDragonGasCalculator extends TangerineWhistleGasCalculator {
public Gas callOperationGasCost(
final MessageFrame frame,
final Gas stipend,
final UInt256 inputDataOffset,
final UInt256 inputDataLength,
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final long inputDataOffset,
final long inputDataLength,
final long outputDataOffset,
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to) {

@ -20,8 +20,6 @@ import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.apache.tuweni.units.bigints.UInt256;
public class TangerineWhistleGasCalculator extends HomesteadGasCalculator {
private static final Gas BALANCE_OPERATION_GAS_COST = Gas.of(400L);
@ -55,10 +53,10 @@ public class TangerineWhistleGasCalculator extends HomesteadGasCalculator {
public Gas callOperationGasCost(
final MessageFrame frame,
final Gas stipend,
final UInt256 inputDataOffset,
final UInt256 inputDataLength,
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final long inputDataOffset,
final long inputDataLength,
final long outputDataOffset,
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to) {

@ -16,18 +16,17 @@
package org.hyperledger.besu.evm.internal;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
public class MemoryEntry {
private final UInt256 offset;
private final long offset;
private final Bytes value;
public MemoryEntry(final UInt256 offset, final Bytes value) {
public MemoryEntry(final long offset, final Bytes value) {
this.offset = offset;
this.value = value;
}
public UInt256 getOffset() {
public long getOffset() {
return offset;
}

@ -16,11 +16,11 @@
package org.hyperledger.besu.evm.internal;
import org.apache.tuweni.units.bigints.UInt256;
import org.apache.tuweni.bytes.Bytes;
public class OperandStack extends FixedStack<UInt256> {
public class OperandStack extends FixedStack<Bytes> {
public OperandStack(final int maxSize) {
super(maxSize, UInt256.class);
super(maxSize, Bytes.class);
}
}

@ -0,0 +1,37 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm.internal;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
public class StorageEntry {
private final UInt256 offset;
private final Bytes value;
public StorageEntry(final UInt256 offset, final Bytes value) {
this.offset = offset;
this.value = value;
}
public UInt256 getOffset() {
return offset;
}
public Bytes getValue() {
return value;
}
}

@ -81,4 +81,27 @@ public abstract class Words {
// m/n round up == (m + n - 1)/n: http://www.cs.nott.ac.uk/~psarb2/G51MPC/slides/NumberLogic.pdf
return (input.size() + Bytes32.SIZE - 1) / Bytes32.SIZE;
}
/**
* The value of the bytes as though it was representing an unsigned integer, however if the value
* exceeds Long.MAX_VALUE then Long.MAX_VALUE will be returned.
*
* @param uint the unsigned integer
* @return the least of the integer value or Long.MAX_VALUE
*/
public static long clampedToLong(final Bytes uint) {
if (uint.size() <= 8) {
long result = uint.toLong();
return result < 0 ? Long.MAX_VALUE : result;
}
Bytes trimmed = uint.trimLeadingZeros();
if (trimmed.size() <= 8) {
long result = trimmed.toLong();
return result < 0 ? Long.MAX_VALUE : result;
} else {
// clamp to the largest int.
return Long.MAX_VALUE;
}
}
}

@ -97,7 +97,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
* @param frame The current message frame
* @return the memory offset the input data starts at
*/
protected abstract UInt256 inputDataOffset(MessageFrame frame);
protected abstract long inputDataOffset(MessageFrame frame);
/**
* Returns the length of the input data to read from memory.
@ -105,7 +105,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
* @param frame The current message frame
* @return the length of the input data to read from memory.
*/
protected abstract UInt256 inputDataLength(MessageFrame frame);
protected abstract long inputDataLength(MessageFrame frame);
/**
* Returns the memory offset the offset data starts at.
@ -113,7 +113,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
* @param frame The current message frame
* @return the memory offset the offset data starts at
*/
protected abstract UInt256 outputDataOffset(MessageFrame frame);
protected abstract long outputDataOffset(MessageFrame frame);
/**
* Returns the length of the output data to read from memory.
@ -121,7 +121,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
* @param frame The current message frame
* @return the length of the output data to read from memory.
*/
protected abstract UInt256 outputDataLength(MessageFrame frame);
protected abstract long outputDataLength(MessageFrame frame);
/**
* Returns the account address the call operation is being performed on
@ -174,7 +174,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
frame.clearReturnData();
final Address to = to(frame);
final var contract = frame.getWorldUpdater().get(to);
final Account contract = frame.getWorldUpdater().get(to);
final Account account = frame.getWorldUpdater().get(frame.getRecipientAddress());
final Wei balance = account == null ? Wei.ZERO : account.getBalance();
@ -216,7 +216,6 @@ public abstract class AbstractCallOperation extends AbstractOperation {
.maxStackSize(frame.getMaxStackSize())
.build();
frame.incrementRemainingGas(cost);
childFrame.copyWarmedUpFields(frame);
frame.getMessageFrameStack().addFirst(childFrame);
frame.setState(MessageFrame.State.CODE_SUSPENDED);
@ -229,14 +228,13 @@ public abstract class AbstractCallOperation extends AbstractOperation {
public void complete(final MessageFrame frame, final MessageFrame childFrame) {
frame.setState(MessageFrame.State.CODE_EXECUTING);
final UInt256 outputOffset = outputDataOffset(frame);
final UInt256 outputSize = outputDataLength(frame);
final long outputOffset = outputDataOffset(frame);
final long outputSize = outputDataLength(frame);
final Bytes outputData = childFrame.getOutputData();
final int outputSizeAsInt = outputSize.intValue();
if (outputSizeAsInt > outputData.size()) {
if (outputSize > outputData.size()) {
frame.expandMemory(outputOffset, outputSize);
frame.writeMemory(outputOffset, UInt256.valueOf(outputData.size()), outputData, true);
frame.writeMemory(outputOffset, outputData.size(), outputData, true);
} else {
frame.writeMemory(outputOffset, outputSize, outputData, true);
}

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
@ -93,8 +95,8 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
protected abstract Address targetContractAddress(MessageFrame frame);
private void fail(final MessageFrame frame) {
final UInt256 inputOffset = frame.getStackItem(1);
final UInt256 inputSize = frame.getStackItem(2);
final long inputOffset = clampedToLong(frame.getStackItem(1));
final long inputSize = clampedToLong(frame.getStackItem(2));
frame.readMutableMemory(inputOffset, inputSize);
frame.popStackItems(getStackItemsConsumed());
frame.pushStackItem(UInt256.ZERO);
@ -111,8 +113,8 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
account.incrementNonce();
final Wei value = Wei.wrap(frame.getStackItem(0));
final UInt256 inputOffset = frame.getStackItem(1);
final UInt256 inputSize = frame.getStackItem(2);
final long inputOffset = clampedToLong(frame.getStackItem(1));
final long inputSize = clampedToLong(frame.getStackItem(2));
final Bytes inputData = frame.readMutableMemory(inputOffset, inputSize);
final Address contractAddress = targetContractAddress(frame);
@ -144,7 +146,6 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
.build();
frame.incrementRemainingGas(cost);
childFrame.copyWarmedUpFields(frame);
frame.getMessageFrameStack().addFirst(childFrame);
frame.setState(MessageFrame.State.CODE_SUSPENDED);

@ -18,6 +18,10 @@ import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import java.math.BigInteger;
import java.util.Arrays;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
public class AddModOperation extends AbstractFixedCostOperation {
@ -27,16 +31,29 @@ public class AddModOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final UInt256 value0 = frame.popStackItem();
final UInt256 value1 = frame.popStackItem();
final UInt256 value2 = frame.popStackItem();
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final Bytes value0 = frame.popStackItem();
final Bytes value1 = frame.popStackItem();
final Bytes value2 = frame.popStackItem();
if (value2.isZero()) {
frame.pushStackItem(UInt256.ZERO);
} else {
final UInt256 result = value0.addMod(value1, value2);
frame.pushStackItem(result);
BigInteger b0 = new BigInteger(1, value0.toArrayUnsafe());
BigInteger b1 = new BigInteger(1, value1.toArrayUnsafe());
BigInteger b2 = new BigInteger(1, value2.toArrayUnsafe());
BigInteger result = b0.add(b1).mod(b2);
Bytes resultBytes = Bytes.wrap(result.toByteArray());
if (resultBytes.size() > 32) {
resultBytes = resultBytes.slice(resultBytes.size() - 32, 32);
}
final byte[] padding = new byte[32 - resultBytes.size()];
Arrays.fill(padding, result.signum() < 0 ? (byte) 0xFF : 0x00);
frame.pushStackItem(Bytes.concatenate(Bytes.wrap(padding), resultBytes));
}
return successResponse;
}

@ -27,9 +27,10 @@ public class AddOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final UInt256 value0 = frame.popStackItem();
final UInt256 value1 = frame.popStackItem();
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final UInt256 value0 = UInt256.fromBytes(frame.popStackItem());
final UInt256 value1 = UInt256.fromBytes(frame.popStackItem());
final UInt256 result = value0.add(value1);

@ -14,11 +14,9 @@
*/
package org.hyperledger.besu.evm.operation;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
public class AddressOperation extends AbstractFixedCostOperation {
@ -27,9 +25,9 @@ public class AddressOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Address address = frame.getRecipientAddress();
frame.pushStackItem(Words.fromAddress(address));
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
frame.pushStackItem(frame.getRecipientAddress());
return successResponse;
}

@ -27,9 +27,10 @@ public class AndOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final UInt256 value0 = frame.popStackItem();
final UInt256 value1 = frame.popStackItem();
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final UInt256 value0 = UInt256.fromBytes(frame.popStackItem());
final UInt256 value1 = UInt256.fromBytes(frame.popStackItem());
final UInt256 result = value0.and(value1);
frame.pushStackItem(result);

@ -53,7 +53,7 @@ public class BalanceOperation extends AbstractOperation {
optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
} else {
final Account account = frame.getWorldUpdater().get(address);
frame.pushStackItem(account == null ? UInt256.ZERO : account.getBalance().toUInt256());
frame.pushStackItem(account == null ? UInt256.ZERO : account.getBalance());
return new OperationResult(optionalCost, Optional.empty());
}
} catch (final UnderflowException ufe) {

@ -32,15 +32,15 @@ public class BaseFeeOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
if (frame.getBlockValues().getBaseFee().isEmpty()) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
Optional<Long> maybeBaseFee = frame.getBlockValues().getBaseFee();
if (maybeBaseFee.isEmpty()) {
return new Operation.OperationResult(
Optional.of(gasCost), Optional.of(ExceptionalHaltReason.INVALID_OPERATION));
}
frame.pushStackItem(
frame
.getBlockValues()
.getBaseFee()
maybeBaseFee
.map(Bytes::ofUnsignedLong)
.map(Bytes32::leftPad)
.map(UInt256::fromBytes)

@ -41,8 +41,9 @@ public class BlockHashOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final UInt256 blockArg = frame.popStackItem();
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final UInt256 blockArg = UInt256.fromBytes(frame.popStackItem());
// Short-circuit if value is unreasonably large
if (!blockArg.fitsLong()) {
@ -51,8 +52,8 @@ public class BlockHashOperation extends AbstractFixedCostOperation {
}
final long soughtBlock = blockArg.toLong();
final BlockValues blockHeader = frame.getBlockValues();
final long currentBlockNumber = blockHeader.getNumber();
final BlockValues blockValues = frame.getBlockValues();
final long currentBlockNumber = blockValues.getNumber();
final long mostRecentBlockNumber = currentBlockNumber - 1;
// If the current block is the genesis block or the sought block is

@ -44,9 +44,10 @@ public class ByteOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final UInt256 value0 = frame.popStackItem();
final UInt256 value1 = frame.popStackItem();
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final UInt256 value0 = UInt256.fromBytes(frame.popStackItem());
final UInt256 value1 = UInt256.fromBytes(frame.popStackItem());
// Stack items are reversed for the BYTE operation.
final UInt256 result = getByte(value1, value0);

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Gas;
@ -22,8 +24,6 @@ import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
import org.apache.tuweni.units.bigints.UInt256;
public class CallCodeOperation extends AbstractCallOperation {
public CallCodeOperation(final GasCalculator gasCalculator) {
@ -32,7 +32,7 @@ public class CallCodeOperation extends AbstractCallOperation {
@Override
protected Gas gas(final MessageFrame frame) {
return Gas.of(frame.getStackItem(0));
return Gas.of(frame.getStackItem(0).trimLeadingZeros());
}
@Override
@ -51,23 +51,23 @@ public class CallCodeOperation extends AbstractCallOperation {
}
@Override
protected UInt256 inputDataOffset(final MessageFrame frame) {
return frame.getStackItem(3);
protected long inputDataOffset(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(3));
}
@Override
protected UInt256 inputDataLength(final MessageFrame frame) {
return frame.getStackItem(4);
protected long inputDataLength(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(4));
}
@Override
protected UInt256 outputDataOffset(final MessageFrame frame) {
return frame.getStackItem(5);
protected long outputDataOffset(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(5));
}
@Override
protected UInt256 outputDataLength(final MessageFrame frame) {
return frame.getStackItem(6);
protected long outputDataLength(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(6));
}
@Override
@ -93,10 +93,10 @@ public class CallCodeOperation extends AbstractCallOperation {
@Override
public Gas cost(final MessageFrame frame) {
final Gas stipend = gas(frame);
final UInt256 inputDataOffset = inputDataOffset(frame);
final UInt256 inputDataLength = inputDataLength(frame);
final UInt256 outputDataOffset = outputDataOffset(frame);
final UInt256 outputDataLength = outputDataLength(frame);
final long inputDataOffset = inputDataOffset(frame);
final long inputDataLength = inputDataLength(frame);
final long outputDataOffset = outputDataOffset(frame);
final long outputDataLength = outputDataLength(frame);
final Account recipient = frame.getWorldUpdater().get(address(frame));
return gasCalculator()

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
@ -23,7 +25,6 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
public class CallDataCopyOperation extends AbstractOperation {
@ -33,9 +34,9 @@ public class CallDataCopyOperation extends AbstractOperation {
@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
final UInt256 memOffset = frame.popStackItem();
final UInt256 sourceOffset = frame.popStackItem();
final UInt256 numBytes = frame.popStackItem();
final long memOffset = clampedToLong(frame.popStackItem());
final long sourceOffset = clampedToLong(frame.popStackItem());
final long numBytes = clampedToLong(frame.popStackItem());
final Gas cost = gasCalculator().dataCopyOperationGasCost(frame, memOffset, numBytes);
final Optional<Gas> optionalCost = Optional.of(cost);

@ -31,8 +31,9 @@ public class CallDataLoadOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final UInt256 startWord = frame.popStackItem();
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final UInt256 startWord = UInt256.fromBytes(frame.popStackItem());
// If the start index doesn't fit a int, it comes after anything in data, and so the returned
// word should be zero.

@ -28,7 +28,8 @@ public class CallDataSizeOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final Bytes callData = frame.getInputData();
frame.pushStackItem(UInt256.valueOf(callData.size()));

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.EVM;
@ -26,8 +28,6 @@ import org.hyperledger.besu.evm.internal.Words;
import java.util.Optional;
import org.apache.tuweni.units.bigints.UInt256;
public class CallOperation extends AbstractCallOperation {
public CallOperation(final GasCalculator gasCalculator) {
@ -36,7 +36,7 @@ public class CallOperation extends AbstractCallOperation {
@Override
protected Gas gas(final MessageFrame frame) {
return Gas.of(frame.getStackItem(0));
return Gas.of(frame.getStackItem(0).trimLeadingZeros());
}
@Override
@ -55,23 +55,23 @@ public class CallOperation extends AbstractCallOperation {
}
@Override
protected UInt256 inputDataOffset(final MessageFrame frame) {
return frame.getStackItem(3);
protected long inputDataOffset(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(3));
}
@Override
protected UInt256 inputDataLength(final MessageFrame frame) {
return frame.getStackItem(4);
protected long inputDataLength(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(4));
}
@Override
protected UInt256 outputDataOffset(final MessageFrame frame) {
return frame.getStackItem(5);
protected long outputDataOffset(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(5));
}
@Override
protected UInt256 outputDataLength(final MessageFrame frame) {
return frame.getStackItem(6);
protected long outputDataLength(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(6));
}
@Override
@ -97,10 +97,10 @@ public class CallOperation extends AbstractCallOperation {
@Override
public Gas cost(final MessageFrame frame) {
final Gas stipend = gas(frame);
final UInt256 inputDataOffset = inputDataOffset(frame);
final UInt256 inputDataLength = inputDataLength(frame);
final UInt256 outputDataOffset = outputDataOffset(frame);
final UInt256 outputDataLength = outputDataLength(frame);
final long inputDataOffset = inputDataOffset(frame);
final long inputDataLength = inputDataLength(frame);
final long outputDataOffset = outputDataOffset(frame);
final long outputDataLength = outputDataLength(frame);
final Account recipient = frame.getWorldUpdater().get(address(frame));
return gasCalculator()

@ -26,7 +26,8 @@ public class CallValueOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final Wei value = frame.getApparentValue();
frame.pushStackItem(value.toUInt256());

@ -14,11 +14,9 @@
*/
package org.hyperledger.besu.evm.operation;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
public class CallerOperation extends AbstractFixedCostOperation {
@ -27,9 +25,9 @@ public class CallerOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Address callerAddress = frame.getSenderAddress();
frame.pushStackItem(Words.fromAddress(callerAddress));
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
frame.pushStackItem(frame.getSenderAddress());
return successResponse;
}

@ -31,7 +31,8 @@ public class ChainIdOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
frame.pushStackItem(chainId);
return successResponse;

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.Gas;
@ -23,8 +25,6 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import java.util.Optional;
import org.apache.tuweni.units.bigints.UInt256;
public class CodeCopyOperation extends AbstractOperation {
public CodeCopyOperation(final GasCalculator gasCalculator) {
@ -33,9 +33,9 @@ public class CodeCopyOperation extends AbstractOperation {
@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
final UInt256 memOffset = frame.popStackItem();
final UInt256 sourceOffset = frame.popStackItem();
final UInt256 numBytes = frame.popStackItem();
final long memOffset = clampedToLong(frame.popStackItem());
final long sourceOffset = clampedToLong(frame.popStackItem());
final long numBytes = clampedToLong(frame.popStackItem());
final Gas cost = gasCalculator().dataCopyOperationGasCost(frame, memOffset, numBytes);
final Optional<Gas> optionalCost = Optional.of(cost);

@ -28,7 +28,8 @@ public class CodeSizeOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final Code code = frame.getCode();
frame.pushStackItem(UInt256.valueOf(code.getSize()));

@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
public class CoinbaseOperation extends AbstractFixedCostOperation {
@ -27,9 +26,10 @@ public class CoinbaseOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final Address coinbase = frame.getMiningBeneficiary();
frame.pushStackItem(Words.fromAddress(coinbase));
frame.pushStackItem(coinbase);
return successResponse;
}

@ -14,8 +14,10 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.crypto.Hash.keccak256;
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.evm.Gas;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
@ -35,11 +37,11 @@ public class Create2Operation extends AbstractCreateOperation {
@Override
public Address targetContractAddress(final MessageFrame frame) {
final Address sender = frame.getRecipientAddress();
final UInt256 offset = frame.getStackItem(1);
final UInt256 length = frame.getStackItem(2);
final Bytes32 salt = frame.getStackItem(3);
final long offset = clampedToLong(frame.getStackItem(1));
final long length = clampedToLong(frame.getStackItem(2));
final Bytes32 salt = UInt256.fromBytes(frame.getStackItem(3));
final Bytes initCode = frame.readMutableMemory(offset, length);
final Hash hash = Hash.hash(Bytes.concatenate(PREFIX, sender, salt, Hash.hash(initCode)));
final Bytes32 hash = keccak256(Bytes.concatenate(PREFIX, sender, salt, keccak256(initCode)));
final Address address = Address.extract(hash);
frame.warmUpAddress(address);
return address;

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Gas;
@ -22,8 +24,6 @@ import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
import org.apache.tuweni.units.bigints.UInt256;
public class DelegateCallOperation extends AbstractCallOperation {
public DelegateCallOperation(final GasCalculator gasCalculator) {
@ -32,7 +32,7 @@ public class DelegateCallOperation extends AbstractCallOperation {
@Override
protected Gas gas(final MessageFrame frame) {
return Gas.of(frame.getStackItem(0));
return Gas.of(frame.getStackItem(0).trimLeadingZeros());
}
@Override
@ -51,23 +51,23 @@ public class DelegateCallOperation extends AbstractCallOperation {
}
@Override
protected UInt256 inputDataOffset(final MessageFrame frame) {
return frame.getStackItem(2);
protected long inputDataOffset(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(2));
}
@Override
protected UInt256 inputDataLength(final MessageFrame frame) {
return frame.getStackItem(3);
protected long inputDataLength(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(3));
}
@Override
protected UInt256 outputDataOffset(final MessageFrame frame) {
return frame.getStackItem(4);
protected long outputDataOffset(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(4));
}
@Override
protected UInt256 outputDataLength(final MessageFrame frame) {
return frame.getStackItem(5);
protected long outputDataLength(final MessageFrame frame) {
return clampedToLong(frame.getStackItem(5));
}
@Override
@ -93,10 +93,10 @@ public class DelegateCallOperation extends AbstractCallOperation {
@Override
public Gas cost(final MessageFrame frame) {
final Gas stipend = gas(frame);
final UInt256 inputDataOffset = inputDataOffset(frame);
final UInt256 inputDataLength = inputDataLength(frame);
final UInt256 outputDataOffset = outputDataOffset(frame);
final UInt256 outputDataLength = outputDataLength(frame);
final long inputDataOffset = inputDataOffset(frame);
final long inputDataLength = inputDataLength(frame);
final long outputDataOffset = outputDataOffset(frame);
final long outputDataLength = outputDataLength(frame);
final Account recipient = frame.getWorldUpdater().get(address(frame));
return gasCalculator()

@ -18,8 +18,6 @@ import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.units.bigints.UInt256;
public class DifficultyOperation extends AbstractFixedCostOperation {
public DifficultyOperation(final GasCalculator gasCalculator) {
@ -29,7 +27,7 @@ public class DifficultyOperation extends AbstractFixedCostOperation {
@Override
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
frame.pushStackItem(UInt256.fromBytes(frame.getBlockValues().getDifficultyBytes()));
frame.pushStackItem(frame.getBlockValues().getDifficultyBytes());
return successResponse;
}

@ -18,6 +18,9 @@ import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
public class DivOperation extends AbstractFixedCostOperation {
@ -27,15 +30,27 @@ public class DivOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final UInt256 value0 = frame.popStackItem();
final UInt256 value1 = frame.popStackItem();
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final Bytes value0 = frame.popStackItem();
final Bytes value1 = frame.popStackItem();
if (value1.isZero()) {
frame.pushStackItem(UInt256.ZERO);
} else {
final UInt256 result = value0.divide(value1);
frame.pushStackItem(result);
BigInteger b1 = new BigInteger(1, value0.toArrayUnsafe());
BigInteger b2 = new BigInteger(1, value1.toArrayUnsafe());
final BigInteger result = b1.divide(b2);
// because it's unsigned there is a change a 33 byte result will occur
// there is no toByteArrayUnsigned so we have to check and trim
byte[] resultArray = result.toByteArray();
int length = resultArray.length;
if (length > 32) {
frame.pushStackItem(Bytes.wrap(resultArray, length - 32, 32));
} else {
frame.pushStackItem(Bytes.wrap(resultArray));
}
}
return successResponse;

@ -23,7 +23,7 @@ import java.util.Optional;
public class DupOperation extends AbstractFixedCostOperation {
protected final OperationResult underflowResponse;
protected final Operation.OperationResult underflowResponse;
private final int index;
@ -39,12 +39,13 @@ public class DupOperation extends AbstractFixedCostOperation {
gasCalculator.getVeryLowTierGasCost());
this.index = index;
this.underflowResponse =
new OperationResult(
new Operation.OperationResult(
Optional.of(gasCost), Optional.of(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS));
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
// getStackItem won't throw under/overflows. Check explicitly.
if (frame.stackSize() < getStackItemsConsumed()) {
return underflowResponse;

@ -27,9 +27,10 @@ public class EqOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final UInt256 value0 = frame.popStackItem();
final UInt256 value1 = frame.popStackItem();
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final UInt256 value0 = UInt256.fromBytes(frame.popStackItem());
final UInt256 value1 = UInt256.fromBytes(frame.popStackItem());
final UInt256 result = (value0.equals(value1) ? UInt256.ONE : UInt256.ZERO);

@ -32,8 +32,8 @@ public class ExpOperation extends AbstractOperation {
@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
final UInt256 number = frame.popStackItem();
final UInt256 power = frame.popStackItem();
final UInt256 number = UInt256.fromBytes(frame.popStackItem());
final UInt256 power = UInt256.fromBytes(frame.popStackItem());
final int numBytes = (power.bitLength() + 7) / 8;

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.operation;
import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.Gas;
@ -26,7 +28,6 @@ import org.hyperledger.besu.evm.internal.Words;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
public class ExtCodeCopyOperation extends AbstractOperation {
@ -37,9 +38,9 @@ public class ExtCodeCopyOperation extends AbstractOperation {
@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
final Address address = Words.toAddress(frame.popStackItem());
final UInt256 memOffset = frame.popStackItem();
final UInt256 sourceOffset = frame.popStackItem();
final UInt256 numBytes = frame.popStackItem();
final long memOffset = clampedToLong(frame.popStackItem());
final long sourceOffset = clampedToLong(frame.popStackItem());
final long numBytes = clampedToLong(frame.popStackItem());
final boolean accountIsWarm =
frame.warmUpAddress(address) || gasCalculator().isPrecompile(address);

@ -15,13 +15,10 @@
package org.hyperledger.besu.evm.operation;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
public class GasLimitOperation extends AbstractFixedCostOperation {
@ -30,10 +27,9 @@ public class GasLimitOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Gas gasLimit = Gas.of(frame.getBlockValues().getGasLimit());
final UInt256 value = UInt256.fromBytes(Bytes32.leftPad(Bytes.of(gasLimit.getBytes())));
frame.pushStackItem(value);
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
frame.pushStackItem(Bytes.ofUnsignedLong(frame.getBlockValues().getGasLimit()));
return successResponse;
}

@ -20,8 +20,6 @@ import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
public class GasOperation extends AbstractFixedCostOperation {
@ -30,9 +28,10 @@ public class GasOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Gas gasRemaining = frame.getRemainingGas().minus(gasCost);
final UInt256 value = UInt256.fromBytes(Bytes32.leftPad(Bytes.of(gasRemaining.getBytes())));
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
Gas gasRemaining = frame.getRemainingGas().minus(gasCost);
final Bytes value = Bytes.of(gasRemaining.getBytes());
frame.pushStackItem(value);
return successResponse;

@ -26,7 +26,8 @@ public class GasPriceOperation extends AbstractFixedCostOperation {
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final Wei gasPrice = frame.getGasPrice();
frame.pushStackItem(gasPrice.toUInt256());

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save