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. 41
      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 ## 21.10.0-RC1
### Additions and Improvements ### 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) * 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 ### Bug Fixes

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

@ -76,26 +76,28 @@ dependencies {
implementation 'org.apache.tuweni:tuweni-units' implementation 'org.apache.tuweni:tuweni-units'
implementation 'org.web3j:abi' 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: ':crypto', configuration: 'testSupportArtifacts')
testImplementation project(path: ':config', configuration: 'testSupportArtifacts') testImplementation project(path: ':config', configuration: 'testSupportArtifacts')
testImplementation project(path: ':consensus:common', configuration: 'testArtifacts') testImplementation project(path: ':consensus:common', configuration: 'testArtifacts')
testImplementation project(path: ':consensus:common', configuration: 'testSupportArtifacts') testImplementation project(path: ':consensus:common', configuration: 'testSupportArtifacts')
testImplementation project(':crypto')
testImplementation project(':ethereum:core') testImplementation project(':ethereum:core')
testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
testImplementation project(':crypto')
testImplementation project(':evm')
testImplementation project(':metrics:core') testImplementation project(':metrics:core')
testImplementation project(':testutil') 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(':crypto')
integrationTestImplementation project(path: ':crypto', configuration: 'testSupportArtifacts') 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(':metrics:core')
integrationTestImplementation project(':testutil') integrationTestImplementation project(':testutil')
@ -103,6 +105,13 @@ dependencies {
integrationTestImplementation 'org.assertj:assertj-core' integrationTestImplementation 'org.assertj:assertj-core'
integrationTestImplementation 'org.mockito:mockito-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(':crypto')
referenceTestImplementation project(path: ':crypto', configuration: 'testSupportArtifacts') referenceTestImplementation project(path: ':crypto', configuration: 'testSupportArtifacts')
referenceTestImplementation project(':consensus:common') referenceTestImplementation project(':consensus:common')
@ -112,14 +121,6 @@ dependencies {
referenceTestImplementation project(':config') referenceTestImplementation project(':config')
referenceTestImplementation project(':testutil') 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' testSupportImplementation 'org.mockito:mockito-core'
} }

@ -15,6 +15,7 @@
package org.hyperledger.besu.datatypes; package org.hyperledger.besu.datatypes;
import static com.google.common.base.Preconditions.checkArgument; 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.crypto.SECPPublicKey;
import org.hyperledger.besu.ethereum.rlp.RLP; 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 com.fasterxml.jackson.annotation.JsonCreator;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.DelegatingBytes; import org.apache.tuweni.bytes.DelegatingBytes;
/** A 160-bits account address. */ /** 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. * </code> function from Appendix F (Signing Transactions) of the Ethereum Yellow Paper.
* @return The ethereum address from the provided hash. * @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)); return wrap(hash.slice(12, 20));
} }
public static Address extract(final SECPPublicKey publicKey) { 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. * @return The generated address of the created contract.
*/ */
public static Address contractAddress(final Address senderAddress, final long nonce) { public static Address contractAddress(final Address senderAddress, final long nonce) {
return extract( return Address.extract(
Hash.hash( keccak256(
RLP.encode( RLP.encode(
out -> { out -> {
out.startList(); out.startList();
@ -174,8 +176,8 @@ public class Address extends DelegatingBytes implements org.hyperledger.besu.plu
*/ */
public static Address privateContractAddress( public static Address privateContractAddress(
final Address senderAddress, final long nonce, final Bytes privacyGroupId) { final Address senderAddress, final long nonce, final Bytes privacyGroupId) {
return extract( return Address.extract(
Hash.hash( keccak256(
RLP.encode( RLP.encode(
out -> { out -> {
out.startList(); 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); 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); 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); 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); public static final Hash EMPTY = hash(Bytes.EMPTY);
private Hash(final Bytes32 bytes) { 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) { 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.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater; import org.hyperledger.besu.evm.worldstate.StackedUpdater;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater.StackedUpdater;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.List; 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 we have no prior updater, it must be the first TX, so use the block's initial state
if (chainedUpdater == null) { if (chainedUpdater == null) {
chainedUpdater = mutableWorldState.updater(); chainedUpdater = mutableWorldState.updater();
} else if (chainedUpdater instanceof AbstractWorldUpdater.StackedUpdater) { } else if (chainedUpdater instanceof StackedUpdater) {
((StackedUpdater) chainedUpdater).markTransactionBoundary(); ((StackedUpdater) chainedUpdater).markTransactionBoundary();
} }
// create an updater for just this tx // 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.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.tracing.StandardJsonTracer; 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 org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.io.File; import java.io.File;
@ -105,8 +105,7 @@ public class TransactionTracer {
WorldUpdater stackedUpdater = worldState.updater().updater(); WorldUpdater stackedUpdater = worldState.updater().updater();
final List<String> traces = new ArrayList<>(); final List<String> traces = new ArrayList<>();
for (int i = 0; i < body.getTransactions().size(); i++) { for (int i = 0; i < body.getTransactions().size(); i++) {
((AbstractWorldUpdater.StackedUpdater<?, ?>) stackedUpdater) ((StackedUpdater<?, ?>) stackedUpdater).markTransactionBoundary();
.markTransactionBoundary();
final Transaction transaction = body.getTransactions().get(i); final Transaction transaction = body.getTransactions().get(i);
if (selectedHash.isEmpty() if (selectedHash.isEmpty()
|| selectedHash.filter(isEqual(transaction.getHash())).isPresent()) { || selectedHash.filter(isEqual(transaction.getHash())).isPresent()) {

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

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

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

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

@ -17,7 +17,7 @@
package org.hyperledger.besu.ethereum.bonsai; package org.hyperledger.besu.ethereum.bonsai;
import org.hyperledger.besu.datatypes.Hash; 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 { 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.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain; 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.core.MutableWorldState;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -180,7 +180,7 @@ public class BonsaiLayeredWorldState implements MutableWorldState, BonsaiWorldVi
if (!results.containsKey(entry.getKey())) { if (!results.containsKey(entry.getKey())) {
final UInt256 value = entry.getValue().getUpdated(); final UInt256 value = entry.getValue().getUpdated();
// yes, store the nulls. If it was deleted it should stay deleted // 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.Address;
import org.hyperledger.besu.datatypes.Hash; 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.core.MutableWorldState;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; 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.exception.StorageException;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; 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.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain; 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.core.MutableWorldState;
import org.hyperledger.besu.ethereum.proof.WorldStateProof; import org.hyperledger.besu.ethereum.proof.WorldStateProof;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;

@ -310,8 +310,7 @@ public class BlockHeader extends SealableBlockHeader
return new org.hyperledger.besu.ethereum.core.BlockHeader( return new org.hyperledger.besu.ethereum.core.BlockHeader(
Hash.fromHexString(pluginBlockHeader.getParentHash().toHexString()), Hash.fromHexString(pluginBlockHeader.getParentHash().toHexString()),
Hash.fromHexString(pluginBlockHeader.getOmmersHash().toHexString()), Hash.fromHexString(pluginBlockHeader.getOmmersHash().toHexString()),
org.hyperledger.besu.datatypes.Address.fromHexString( Address.fromHexString(pluginBlockHeader.getCoinbase().toHexString()),
pluginBlockHeader.getCoinbase().toHexString()),
Hash.fromHexString(pluginBlockHeader.getStateRoot().toHexString()), Hash.fromHexString(pluginBlockHeader.getStateRoot().toHexString()),
Hash.fromHexString(pluginBlockHeader.getTransactionsRoot().toHexString()), Hash.fromHexString(pluginBlockHeader.getTransactionsRoot().toHexString()),
Hash.fromHexString(pluginBlockHeader.getReceiptsRoot().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.MutableWorldView;
import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.data.BlockHeader;
public interface MutableWorldState extends WorldState, MutableWorldView { 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.Gas;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.internal.MemoryEntry; import org.hyperledger.besu.evm.internal.MemoryEntry;
import org.hyperledger.besu.evm.internal.StorageEntry;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.Map; import java.util.Map;
@ -56,7 +57,7 @@ public class TraceFrame {
private Gas gasRemainingPostExecution; private Gas gasRemainingPostExecution;
private final boolean virtualOperation; private final boolean virtualOperation;
private final Optional<MemoryEntry> maybeUpdatedMemory; private final Optional<MemoryEntry> maybeUpdatedMemory;
private final Optional<MemoryEntry> maybeUpdatedStorage; private final Optional<StorageEntry> maybeUpdatedStorage;
private Optional<Gas> precompiledGasCost; private Optional<Gas> precompiledGasCost;
public TraceFrame( public TraceFrame(
@ -82,7 +83,7 @@ public class TraceFrame {
final Optional<Bytes32[]> stackPostExecution, final Optional<Bytes32[]> stackPostExecution,
final boolean virtualOperation, final boolean virtualOperation,
final Optional<MemoryEntry> maybeUpdatedMemory, final Optional<MemoryEntry> maybeUpdatedMemory,
final Optional<MemoryEntry> maybeUpdatedStorage) { final Optional<StorageEntry> maybeUpdatedStorage) {
this.pc = pc; this.pc = pc;
this.opcode = opcode; this.opcode = opcode;
this.gasRemaining = gasRemaining; this.gasRemaining = gasRemaining;
@ -224,7 +225,7 @@ public class TraceFrame {
return maybeUpdatedMemory; return maybeUpdatedMemory;
} }
public Optional<MemoryEntry> getMaybeUpdatedStorage() { public Optional<StorageEntry> getMaybeUpdatedStorage() {
return maybeUpdatedStorage; return maybeUpdatedStorage;
} }

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

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

@ -14,6 +14,8 @@
*/ */
package org.hyperledger.besu.ethereum.vm; 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.Address;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.debug.TraceFrame; import org.hyperledger.besu.ethereum.debug.TraceFrame;
@ -38,8 +40,6 @@ import org.apache.tuweni.units.bigints.UInt256;
public class DebugOperationTracer implements OperationTracer { public class DebugOperationTracer implements OperationTracer {
private static final UInt256 UINT256_32 = UInt256.valueOf(32);
private final TraceOptions options; private final TraceOptions options;
private List<TraceFrame> traceFrames = new ArrayList<>(); private List<TraceFrame> traceFrames = new ArrayList<>();
private TraceFrame lastFrame; private TraceFrame lastFrame;
@ -200,9 +200,9 @@ public class DebugOperationTracer implements OperationTracer {
if (!options.isMemoryEnabled()) { if (!options.isMemoryEnabled()) {
return Optional.empty(); 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++) { 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); return Optional.of(memoryContents);
} }
@ -215,7 +215,7 @@ public class DebugOperationTracer implements OperationTracer {
final Bytes32[] stackContents = new Bytes32[frame.stackSize()]; final Bytes32[] stackContents = new Bytes32[frame.stackSize()];
for (int i = 0; i < stackContents.length; i++) { for (int i = 0; i < stackContents.length; i++) {
// Record stack contents in reverse // 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); 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.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPException; 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.MerklePatriciaTrie;
import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.AccountState;
import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater; import org.hyperledger.besu.evm.worldstate.AbstractWorldUpdater;
import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount; import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount;
import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -151,7 +150,7 @@ public class DefaultMutableWorldState implements MutableWorldState {
.map( .map(
entry -> { entry -> {
final Optional<Address> address = getAccountTrieKeyPreimage(entry.getKey()); final Optional<Address> address = getAccountTrieKeyPreimage(entry.getKey());
final AccountState account = final WorldStateAccount account =
deserializeAccount( deserializeAccount(
address.orElse(Address.ZERO), Hash.wrap(entry.getKey()), entry.getValue()); address.orElse(Address.ZERO), Hash.wrap(entry.getKey()), entry.getValue());
return new StreamableAccount(address, account); 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.Address;
import org.hyperledger.besu.datatypes.Hash; 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.core.MutableWorldState;
import org.hyperledger.besu.ethereum.proof.WorldStateProof; import org.hyperledger.besu.ethereum.proof.WorldStateProof;
import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider; import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider;
import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie;
import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.List; import java.util.List;
import java.util.Optional; 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.Address;
import org.hyperledger.besu.datatypes.Hash; 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.core.MutableWorldState;
import org.hyperledger.besu.ethereum.proof.WorldStateProof; import org.hyperledger.besu.ethereum.proof.WorldStateProof;
import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.MerklePatriciaTrie;
import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.data.BlockHeader;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;

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

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

@ -58,7 +58,7 @@ public abstract class AbstractRetryingTest {
public void execution() { public void execution() {
try { try {
runTest(); runTest();
} catch (final AssertionError e) { } catch (final RuntimeException | AssertionError e) {
if (!"trace".equalsIgnoreCase(originalRootLogLevel) if (!"trace".equalsIgnoreCase(originalRootLogLevel)
|| !"trace".equalsIgnoreCase(originalEvmLogLevel)) { || !"trace".equalsIgnoreCase(originalEvmLogLevel)) {
// try again, this time with more logging so we can capture more information. // 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 word1 = Bytes32.fromHexString("0x01");
final Bytes32 word2 = Bytes32.fromHexString("0x02"); final Bytes32 word2 = Bytes32.fromHexString("0x02");
final Bytes32 word3 = Bytes32.fromHexString("0x03"); final Bytes32 word3 = Bytes32.fromHexString("0x03");
frame.writeMemory(UInt256.ZERO, UInt256.valueOf(32), word1); frame.writeMemory(0, 32, word1);
frame.writeMemory(UInt256.valueOf(32), UInt256.valueOf(32), word2); frame.writeMemory(32, 32, word2);
frame.writeMemory(UInt256.valueOf(64), UInt256.valueOf(32), word3); frame.writeMemory(64, 32, word3);
final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(false, true, false)); final TraceFrame traceFrame = traceFrame(frame, new TraceOptions(false, true, false));
assertThat(traceFrame.getMemory()).isPresent(); assertThat(traceFrame.getMemory()).isPresent();
assertThat(traceFrame.getMemory().get()).containsExactly(word1, word2, word3); assertThat(traceFrame.getMemory().get()).containsExactly(word1, word2, word3);
@ -221,9 +221,9 @@ public class DebugOperationTracerTest {
final Bytes32 word1 = Bytes32.fromHexString("0x01"); final Bytes32 word1 = Bytes32.fromHexString("0x01");
final Bytes32 word2 = Bytes32.fromHexString("0x02"); final Bytes32 word2 = Bytes32.fromHexString("0x02");
final Bytes32 word3 = Bytes32.fromHexString("0x03"); final Bytes32 word3 = Bytes32.fromHexString("0x03");
frame.writeMemory(UInt256.ZERO, UInt256.valueOf(32), word1); frame.writeMemory(0, 32, word1);
frame.writeMemory(UInt256.valueOf(32), UInt256.valueOf(32), word2); frame.writeMemory(32, 32, word2);
frame.writeMemory(UInt256.valueOf(64), UInt256.valueOf(32), word3); frame.writeMemory(64, 32, word3);
return updatedStorage; return updatedStorage;
} }
} }

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

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

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

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

@ -71,7 +71,7 @@ public class ExtCodeHashOperationTest {
@Test @Test
public void shouldReturnZeroWhenAccountDoesNotExist() { public void shouldReturnZeroWhenAccountDoesNotExist() {
final Bytes32 result = executeOperation(REQUESTED_ADDRESS); final Bytes result = executeOperation(REQUESTED_ADDRESS);
assertThat(result).isEqualTo(Bytes32.ZERO); assertThat(result).isEqualTo(Bytes32.ZERO);
} }
@ -121,7 +121,7 @@ public class ExtCodeHashOperationTest {
assertThat(frame.getStackItem(0)).isEqualTo(Hash.hash(code)); 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); final MessageFrame frame = createMessageFrame(requestedAddress);
operation.execute(frame, null); operation.execute(frame, null);
return frame.getStackItem(0); 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.Code;
import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.OperationRegistry;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
import org.hyperledger.besu.evm.operation.JumpDestOperation; import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.hyperledger.besu.evm.operation.JumpOperation; import org.hyperledger.besu.evm.operation.JumpOperation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult; import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
@ -132,4 +132,21 @@ public class JumpOperationTest {
final OperationResult result2 = operation.execute(frameDestinationEqualsToCodeSize, null); final OperationResult result2 = operation.execute(frameDestinationEqualsToCodeSize, null);
assertThat(result2.getHaltReason()).contains(ExceptionalHaltReason.INVALID_JUMP_DESTINATION); 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; package org.hyperledger.besu.ethereum.vm.operations;
import static org.assertj.core.api.Assertions.assertThat; 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 static org.mockito.Mockito.when;
import org.hyperledger.besu.evm.Gas; import org.hyperledger.besu.evm.Gas;
@ -46,10 +46,9 @@ public class RevertOperationTest {
when(messageFrame.popStackItem()) when(messageFrame.popStackItem())
.thenReturn(UInt256.fromHexString("0x00")) .thenReturn(UInt256.fromHexString("0x00"))
.thenReturn(UInt256.fromHexString("0x0e")); .thenReturn(UInt256.fromHexString("0x0e"));
final UInt256 uint256_14 = UInt256.valueOf(0x0e); when(messageFrame.readMemory(0, 14)).thenReturn(revertReasonBytes);
when(messageFrame.readMemory(UInt256.ZERO, uint256_14)).thenReturn(revertReasonBytes); when(messageFrame.memoryWordSize()).thenReturn(0);
when(messageFrame.memoryWordSize()).thenReturn(UInt256.ZERO); when(messageFrame.calculateMemoryExpansion(anyLong(), anyLong())).thenReturn(14L);
when(messageFrame.calculateMemoryExpansion(any(), any())).thenReturn(uint256_14);
when(messageFrame.getRemainingGas()).thenReturn(Gas.of(10_000)); 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 * Returns the block number that the message requests or {@link OptionalLong#empty()} if the
* specifies a block hash. * request specifies a block hash.
* *
* @return Block Number Requested or {@link OptionalLong#EMPTY} * @return Block Number Requested or {@link OptionalLong#empty()}
*/ */
public OptionalLong blockNumber() { public OptionalLong blockNumber() {
return getBlockHeadersData().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. * specifies a block number.
* *
* @return Block Hash Requested or {@link Optional#EMPTY} * @return Block Hash Requested or {@link Optional#empty()}
*/ */
public Optional<Hash> hash() { public Optional<Hash> hash() {
return getBlockHeadersData().blockHash; return getBlockHeadersData().blockHash;

@ -64,9 +64,10 @@ public class BlockchainModule {
final MutableWorldState mutableWorldState = final MutableWorldState mutableWorldState =
new DefaultMutableWorldState(worldStateStorage, worldStatePreimageStorage); new DefaultMutableWorldState(worldStateStorage, worldStatePreimageStorage);
genesisState.writeStateTo(mutableWorldState); genesisState.writeStateTo(mutableWorldState);
return mutableWorldState; return (MutableWorldView) mutableWorldState;
} else { } 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) ? new StandardJsonTracer(System.out, !noMemory)
: OperationTracer.NO_TRACING; : OperationTracer.NO_TRACING;
var updater = component.getWorldUpdater();
updater.getOrCreate(sender);
updater.getOrCreate(receiver);
final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>(); final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
messageFrameStack.add( messageFrameStack.add(
MessageFrame.builder() MessageFrame.builder()
.type(MessageFrame.Type.MESSAGE_CALL) .type(MessageFrame.Type.MESSAGE_CALL)
.messageFrameStack(messageFrameStack) .messageFrameStack(messageFrameStack)
.worldUpdater(component.getWorldUpdater()) .worldUpdater(updater)
.initialGas(gas) .initialGas(gas)
.contract(Address.ZERO) .contract(Address.ZERO)
.address(receiver) .address(receiver)
@ -284,6 +288,10 @@ public class EvmToolCommand implements Runnable {
protocolSpec protocolSpec
.getGasCalculator() .getGasCalculator()
.transactionIntrinsicGasCost(tx.getPayload(), tx.isContractCreation()); .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()); final Gas evmGas = gas.minus(messageFrame.getRemainingGas());
out.println(); out.println();
out.println( out.println(
@ -291,7 +299,13 @@ public class EvmToolCommand implements Runnable {
.put("gasUser", evmGas.asUInt256().toShortHexString()) .put("gasUser", evmGas.asUInt256().toShortHexString())
.put("timens", lastTime) .put("timens", lastTime)
.put("time", lastTime / 1000) .put("time", lastTime / 1000)
.put("gasTotal", evmGas.plus(intrinsicGasCost).asUInt256().toShortHexString())); .put(
"gasTotal",
evmGas
.plus(intrinsicGasCost)
.plus(accessListCost)
.asUInt256()
.toShortHexString()));
} }
} }
lastTime = stopwatch.elapsed().toNanos(); lastTime = stopwatch.elapsed().toNanos();

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

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

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

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

@ -18,7 +18,6 @@ import static java.lang.String.format;
import java.util.function.Consumer; import java.util.function.Consumer;
import io.vertx.core.buffer.Buffer;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.MutableBytes; import org.apache.tuweni.bytes.MutableBytes;
@ -59,27 +58,6 @@ public abstract class RLP {
return new BytesValueRLPInput(encoded, lenient); 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 * Creates a {@link RLPOutput}, pass it to the provided consumer for writing, and then return the
* RLP encoded result of that writing. * RLP encoded result of that writing.

@ -17,28 +17,48 @@ package org.hyperledger.besu.evm;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
@JsonSerialize(using = AccessListEntrySerializer.class)
@JsonDeserialize(using = AccessListEntryDeserializer.class)
public class AccessListEntry { public class AccessListEntry {
private final Address address; private final Address address;
private final List<Bytes32> storageKeys; private final List<Bytes32> storageKeys;
public AccessListEntry(final Address address, final List<Bytes32> storageKeys) { public AccessListEntry(final Address address, final List<Bytes32> storageKeys) {
this.address = address; this.address = address;
this.storageKeys = storageKeys; 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() { public Address getAddress() {
return address; return address;
} }
@JsonIgnore
public List<Bytes32> getStorageKeys() { public List<Bytes32> getStorageKeys() {
return storageKeys; 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.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.JumpDestOperation; import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.hyperledger.besu.evm.operation.Operation; import org.hyperledger.besu.evm.operation.PushOperation;
import java.util.BitSet;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
@ -31,7 +29,8 @@ public class Code {
private final Bytes bytes; private final Bytes bytes;
/** Used to cache valid jump destinations. */ /** Used to cache valid jump destinations. */
private BitSet validJumpDestinations; // private BitSet validJumpDestinations;
long[] validJumpDestinations;
/** /**
* Public constructor. * Public constructor.
@ -93,16 +92,34 @@ public class Code {
if (validJumpDestinations == null) { if (validJumpDestinations == null) {
// Calculate valid jump destinations // Calculate valid jump destinations
validJumpDestinations = new BitSet(getSize()); int size = getSize();
evm.forEachOperation( validJumpDestinations = new long[(size >> 6) + 1];
this, byte[] rawCode = getBytes().toArrayUnsafe();
(final Operation op, final Integer offset) -> { int length = rawCode.length;
if (op.getOpcode() == JumpDestOperation.OPCODE) { for (int i = 0; i < length; ) {
validJumpDestinations.set(offset); 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() { 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.InvalidOperation;
import org.hyperledger.besu.evm.operation.Operation; import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult; import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.operation.StopOperation; import org.hyperledger.besu.evm.operation.StopOperation;
import org.hyperledger.besu.evm.operation.VirtualOperation; import org.hyperledger.besu.evm.operation.VirtualOperation;
import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.OperationTracer;
@ -47,13 +48,19 @@ public class EVM {
Optional.empty(), Optional.of(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS)); Optional.empty(), Optional.of(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS));
private final OperationRegistry operations; private final OperationRegistry operations;
private final GasCalculator gasCalculator;
private final Operation endOfScriptStop; private final Operation endOfScriptStop;
public EVM(final OperationRegistry operations, final GasCalculator gasCalculator) { public EVM(final OperationRegistry operations, final GasCalculator gasCalculator) {
this.operations = operations; this.operations = operations;
this.gasCalculator = gasCalculator;
this.endOfScriptStop = new VirtualOperation(new StopOperation(gasCalculator)); this.endOfScriptStop = new VirtualOperation(new StopOperation(gasCalculator));
} }
public GasCalculator getGasCalculator() {
return gasCalculator;
}
public void runToHalt(final MessageFrame frame, final OperationTracer operationTracer) { public void runToHalt(final MessageFrame frame, final OperationTracer operationTracer) {
while (frame.getState() == MessageFrame.State.CODE_EXECUTING) { while (frame.getState() == MessageFrame.State.CODE_EXECUTING) {
executeNextOperation(frame, operationTracer); executeNextOperation(frame, operationTracer);

@ -20,6 +20,7 @@ import java.math.BigInteger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import com.google.common.primitives.Longs; import com.google.common.primitives.Longs;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256; 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 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); 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) { 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) { public static Gas fromHexString(final String str) {
try { try {
final long value = Long.decode(str); final long value = Long.decode(str);
return of(value); return Gas.of(value);
} catch (final NumberFormatException e) { } catch (final NumberFormatException e) {
return MAX_VALUE; 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.MulOperation;
import org.hyperledger.besu.evm.operation.NotOperation; import org.hyperledger.besu.evm.operation.NotOperation;
import org.hyperledger.besu.evm.operation.NumberOperation; 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.OrOperation;
import org.hyperledger.besu.evm.operation.OriginOperation; import org.hyperledger.besu.evm.operation.OriginOperation;
import org.hyperledger.besu.evm.operation.PCOperation; 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_OPERATION("Bad instruction"),
INVALID_RETURN_DATA_BUFFER_ACCESS("Out of bounds"), INVALID_RETURN_DATA_BUFFER_ACCESS("Out of bounds"),
TOO_MANY_STACK_ITEMS("Out of stack"), 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; String description;

@ -14,16 +14,12 @@
*/ */
package org.hyperledger.besu.evm.frame; package org.hyperledger.besu.evm.frame;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.MutableBytes; 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 * <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. * the Yellow Paper Revision 59dccd.
@ -37,13 +33,12 @@ public class Memory {
* The data stored within the 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 * <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. * trillion gas. So this is likely a reasonable limitation, at least at first.
*/ */
private MutableBytes data; private MutableBytes data;
private UInt256 activeWords; private int activeWords;
private int dataSize256;
public Memory() { public Memory() {
data = MutableBytes.EMPTY; data = MutableBytes.EMPTY;
@ -51,8 +46,7 @@ public class Memory {
} }
private void updateSize() { private void updateSize() {
dataSize256 = data.size() / Bytes32.SIZE; activeWords = data.size() / Bytes32.SIZE;
activeWords = UInt256.valueOf(dataSize256);
} }
private static RuntimeException overflow(final long v) { private static RuntimeException overflow(final long v) {
@ -72,76 +66,48 @@ public class Memory {
if (v < 0 || v >= MAX_BYTES) throw overflow(v); if (v < 0 || v >= MAX_BYTES) throw overflow(v);
} }
private int asByteIndex(final UInt256 w) { private int asByteIndex(final long w) {
try { try {
final long v = w.toLong(); final long v = Math.toIntExact(w);
checkByteIndex(v); checkByteIndex(v);
return (int) v; return (int) v;
} catch (final IllegalStateException e) { } 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 { try {
// While we can theoretically support up to 32 * Integer.MAX_VALUE due to storing words, and return Math.toIntExact(l);
// so an index in memory need to be a long internally, we simply cannot load/store more than } catch (final ArithmeticException e) {
// Integer.MAX_VALUE bytes at a time (Bytes has an int size). throw overflow(l);
return l.intValue();
} catch (final IllegalStateException e) {
throw overflow(l.toString());
} }
} }
/** /**
* For use in memoryExpansionGasCost() of GasCost. Returns the number of new active words that * 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 * <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. * up with an Out-of-Gas error.
* *
* @param location The offset in memory from which we want to accommodate {@code numBytes}. * @param location The offset in memory from which we want to accommodate {@code numBytes}.
* @param numBytes The minimum number of bytes in memory. * @param numBytes The minimum number of bytes in memory.
* @return The number of active words that accommodate at least the number of specified bytes. * @return The number of active words that accommodate at least the number of specified bytes.
*/ */
UInt256 calculateNewActiveWords(final UInt256 location, final UInt256 numBytes) { long calculateNewActiveWords(final long location, final long numBytes) {
if (numBytes.isZero()) { if (numBytes == 0) {
return activeWords; return activeWords;
} }
if (location.fitsInt() && numBytes.fitsInt()) { try {
// Fast common path (note that we work on int but use long arithmetic to avoid issues) final long byteSize = Math.addExact(Math.addExact(location, numBytes), 31);
final long byteSize = location.toLong() + numBytes.toLong(); long wordSize = byteSize / 32;
int wordSize = Math.toIntExact(byteSize / Bytes32.SIZE); return Math.max(wordSize, activeWords);
if (byteSize % Bytes32.SIZE != 0) wordSize += 1; } catch (ArithmeticException ae) {
return wordSize > dataSize256 ? UInt256.valueOf(wordSize) : activeWords; return Long.MAX_VALUE >> 5;
} 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));
}
} }
/**
* 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 UInt256 offset, final UInt256 numBytes) {
if (!offset.fitsInt()) return;
if (!numBytes.fitsInt()) return;
ensureCapacityForBytes(offset.intValue(), numBytes.intValue());
} }
/** /**
@ -150,15 +116,15 @@ public class Memory {
* @param offset The location in memory to start with. * @param offset The location in memory to start with.
* @param numBytes The number of bytes to get. * @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 // Do not increase the memory capacity if no bytes are being written
// regardless of what the address may be. // regardless of what the address may be.
if (numBytes == 0) { if (numBytes == 0) {
return; return;
} }
final int lastByteIndex = Math.addExact(offset, numBytes); final long lastByteIndex = Math.addExact(offset, numBytes);
final int lastWordRequired = ((lastByteIndex - 1) / Bytes32.SIZE); final long lastWordRequired = ((lastByteIndex - 1) / Bytes32.SIZE);
maybeExpandCapacity(lastWordRequired + 1); maybeExpandCapacity((int) lastWordRequired + 1);
} }
/** /**
@ -167,7 +133,7 @@ public class Memory {
* @param newActiveWords The new number of active words to expand to. * @param newActiveWords The new number of active words to expand to.
*/ */
private void maybeExpandCapacity(final int newActiveWords) { 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. // Require full capacity to guarantee we don't resize more than once.
final MutableBytes newData = MutableBytes.create(newActiveWords * Bytes32.SIZE); 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. * @return The current number of active words stored in memory.
*/ */
UInt256 getActiveWords() { int getActiveWords() {
return activeWords; 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 * @return A fresh copy of the bytes from memory starting at {@code location} and extending {@code
* numBytes}. * 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 // 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 // is too big but the length is 0 (which is somewhat nonsensical, but is exercise by some
// tests). // tests).
final int length = asByteLength(numBytes); final int length = asByteLength(numBytes);
@ -236,7 +202,7 @@ public class Memory {
final int start = asByteIndex(location); final int start = asByteIndex(location);
ensureCapacityForBytes(start, length); 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. * copied and so never fails.
* *
* @param memOffset the location in memory at which to start copying the bytes of {@code value}. * @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 offset 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 * @param length the number of bytes to set in memory. Note that this value may differ from {@code
* {@code value.size()}: if {@code numBytes < value.size()} bytes, only {@code numBytes} will * value.size()}: if {@code numBytes < value.size()} bytes, only {@code numBytes} will be
* be copied from {@code value}; if {@code numBytes < value.size()}, then only the bytes in * 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 * {@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 * 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 * 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}. * @param bytes the bytes to copy to memory from {@code location}.
*/ */
public void setBytes( public void setBytes(
final UInt256 memOffset, final long memOffset, final long offset, final long length, final Bytes bytes) {
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;
if (offset >= bytes.size()) { if (offset >= bytes.size()) {
clearBytes(memOffset, numBytes); clearBytes(memOffset, length);
return; return;
} }
final Bytes toCopy = bytes.slice(offset, Math.min(length, bytes.size() - offset)); final Bytes toCopy =
setBytes(memOffset, numBytes, 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). * {@code value} being smaller).
* @param taintedValue the bytes to copy to memory from {@code location}. * @param taintedValue the bytes to copy to memory from {@code location}.
*/ */
public void setBytes(final UInt256 location, final UInt256 numBytes, final Bytes taintedValue) { public void setBytes(final long location, final long numBytes, final Bytes taintedValue) {
if (numBytes.isZero()) { if (numBytes == 0) {
return; return;
} }
@ -316,7 +278,7 @@ public class Memory {
* @param location The location in memory from which to start clearing the bytes. * @param location The location in memory from which to start clearing the bytes.
* @param numBytes The number of bytes to clear. * @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). // See getBytes for why we check length == 0 first, before calling asByteIndex(location).
final int length = asByteLength(numBytes); final int length = asByteLength(numBytes);
if (length == 0) { if (length == 0) {
@ -346,7 +308,7 @@ public class Memory {
* @param location the location of the byte to set. * @param location the location of the byte to set.
* @param value the value to set for the byte at {@code location}. * @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); final int start = asByteIndex(location);
ensureCapacityForBytes(start, 1); ensureCapacityForBytes(start, 1);
data.set(start, value); data.set(start, value);
@ -358,7 +320,7 @@ public class Memory {
* @param location The memory location the 256-bit word begins at. * @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. * @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); final int start = asByteIndex(location);
ensureCapacityForBytes(start, Bytes32.SIZE); ensureCapacityForBytes(start, Bytes32.SIZE);
return Bytes32.wrap(data.slice(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 location the location at which to start setting the bytes.
* @param bytes the 32 bytes to copy at {@code location}. * @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); final int start = asByteIndex(location);
ensureCapacityForBytes(start, Bytes32.SIZE); ensureCapacityForBytes(start, Bytes32.SIZE);
data.set(start, bytes); 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.FixedStack.UnderflowException;
import org.hyperledger.besu.evm.internal.MemoryEntry; import org.hyperledger.besu.evm.internal.MemoryEntry;
import org.hyperledger.besu.evm.internal.OperandStack; 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.log.Log;
import org.hyperledger.besu.evm.operation.Operation; import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@ -212,8 +213,8 @@ public class MessageFrame {
private Gas gasRefund; private Gas gasRefund;
private final Set<Address> selfDestructs; private final Set<Address> selfDestructs;
private final Map<Address, Wei> refunds; private final Map<Address, Wei> refunds;
private Set<Address> warmedUpAddresses; private final Set<Address> warmedUpAddresses;
private Multimap<Address, Bytes32> warmedUpStorage; private final Multimap<Address, Bytes32> warmedUpStorage;
// Execution Environment fields. // Execution Environment fields.
private final Address recipient; private final Address recipient;
@ -227,6 +228,7 @@ public class MessageFrame {
private final Code code; private final Code code;
private final BlockValues blockValues; private final BlockValues blockValues;
private final int depth; private final int depth;
private final MessageFrame parentMessageFrame;
private final Deque<MessageFrame> messageFrameStack; private final Deque<MessageFrame> messageFrameStack;
private final Address miningBeneficiary; private final Address miningBeneficiary;
private Optional<Bytes> revertReason; private Optional<Bytes> revertReason;
@ -239,7 +241,7 @@ public class MessageFrame {
private Optional<Gas> gasCost = Optional.empty(); private Optional<Gas> gasCost = Optional.empty();
private final Consumer<MessageFrame> completer; private final Consumer<MessageFrame> completer;
private Optional<MemoryEntry> maybeUpdatedMemory = Optional.empty(); private Optional<MemoryEntry> maybeUpdatedMemory = Optional.empty();
private Optional<MemoryEntry> maybeUpdatedStorage = Optional.empty(); private Optional<StorageEntry> maybeUpdatedStorage = Optional.empty();
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
@ -272,6 +274,7 @@ public class MessageFrame {
final Multimap<Address, Bytes32> accessListWarmStorage) { final Multimap<Address, Bytes32> accessListWarmStorage) {
this.type = type; this.type = type;
this.messageFrameStack = messageFrameStack; this.messageFrameStack = messageFrameStack;
this.parentMessageFrame = messageFrameStack.peek();
this.worldUpdater = worldUpdater; this.worldUpdater = worldUpdater;
this.gasRemaining = initialGas; this.gasRemaining = initialGas;
this.blockHashLookup = blockHashLookup; this.blockHashLookup = blockHashLookup;
@ -435,7 +438,7 @@ public class MessageFrame {
* @return The item at the specified offset in the stack * @return The item at the specified offset in the stack
* @throws UnderflowException if the offset is out of range * @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); return stack.get(offset);
} }
@ -445,7 +448,7 @@ public class MessageFrame {
* @return the item at the top of the stack * @return the item at the top of the stack
* @throws UnderflowException if the stack is empty * @throws UnderflowException if the stack is empty
*/ */
public UInt256 popStackItem() { public Bytes popStackItem() {
return stack.pop(); return stack.pop();
} }
@ -463,7 +466,7 @@ public class MessageFrame {
* *
* @param value The value to push onto the stack. * @param value The value to push onto the stack.
*/ */
public void pushStackItem(final UInt256 value) { public void pushStackItem(final Bytes value) {
stack.push(value); stack.push(value);
} }
@ -474,7 +477,7 @@ public class MessageFrame {
* @param value The value to set the stack item to * @param value The value to set the stack item to
* @throws IllegalStateException if the stack is too small * @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); stack.set(offset, value);
} }
@ -503,7 +506,7 @@ public class MessageFrame {
* @param length The length of the memory access * @param length The length of the memory access
* @return the memory size for specified 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); return memory.calculateNewActiveWords(offset, length);
} }
@ -513,7 +516,7 @@ public class MessageFrame {
* @param offset The offset in memory * @param offset The offset in memory
* @param length The length of the memory access * @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); memory.ensureCapacityForBytes(offset, length);
} }
@ -531,7 +534,7 @@ public class MessageFrame {
* *
* @return the number of words in memory * @return the number of words in memory
*/ */
public UInt256 memoryWordSize() { public int memoryWordSize() {
return memory.getActiveWords(); return memory.getActiveWords();
} }
@ -556,7 +559,7 @@ public class MessageFrame {
* @param length The length of the bytes to read * @param length The length of the bytes to read
* @return The bytes in the specified range * @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); return readMutableMemory(offset, length, false);
} }
@ -567,7 +570,7 @@ public class MessageFrame {
* @param length The length of the bytes to read * @param length The length of the bytes to read
* @return The bytes in the specified range * @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(); return readMutableMemory(offset, length, false).copy();
} }
@ -581,7 +584,7 @@ public class MessageFrame {
* @return The bytes in the specified range * @return The bytes in the specified range
*/ */
public Bytes readMutableMemory( 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); final Bytes value = memory.getBytes(offset, length);
if (explicitMemoryRead) { if (explicitMemoryRead) {
setUpdatedMemory(offset, value); setUpdatedMemory(offset, value);
@ -596,8 +599,7 @@ public class MessageFrame {
* @param value The value to set in memory * @param value The value to set in memory
* @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise * @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise
*/ */
public void writeMemory( public void writeMemory(final long offset, final byte value, final boolean explicitMemoryUpdate) {
final UInt256 offset, final byte value, final boolean explicitMemoryUpdate) {
memory.setByte(offset, value); memory.setByte(offset, value);
if (explicitMemoryUpdate) { if (explicitMemoryUpdate) {
setUpdatedMemory(offset, Bytes.of(value)); setUpdatedMemory(offset, Bytes.of(value));
@ -611,7 +613,7 @@ public class MessageFrame {
* @param length The length of the bytes to write * @param length The length of the bytes to write
* @param value The value 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); writeMemory(offset, length, value, false);
} }
@ -624,13 +626,10 @@ public class MessageFrame {
* @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise * @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise
*/ */
public void writeMemory( public void writeMemory(
final UInt256 offset, final long offset, final long length, final Bytes value, final boolean explicitMemoryUpdate) {
final UInt256 length,
final Bytes value,
final boolean explicitMemoryUpdate) {
memory.setBytes(offset, length, value); memory.setBytes(offset, length, value);
if (explicitMemoryUpdate) { 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 * @param value The value to write
*/ */
public void writeMemory( 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); writeMemory(offset, sourceOffset, length, value, false);
} }
@ -657,42 +656,40 @@ public class MessageFrame {
* @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise * @param explicitMemoryUpdate true if triggered by a memory opcode, false otherwise
*/ */
public void writeMemory( public void writeMemory(
final UInt256 offset, final long offset,
final UInt256 sourceOffset, final long sourceOffset,
final UInt256 length, final long length,
final Bytes value, final Bytes value,
final boolean explicitMemoryUpdate) { final boolean explicitMemoryUpdate) {
memory.setBytes(offset, sourceOffset, length, value); memory.setBytes(offset, sourceOffset, length, value);
if (explicitMemoryUpdate && length.toLong() > 0) { if (explicitMemoryUpdate && length > 0) {
setUpdatedMemory(offset, sourceOffset, length, value); setUpdatedMemory(offset, sourceOffset, length, value);
} }
} }
private void setUpdatedMemory( private void setUpdatedMemory(
final UInt256 offset, final UInt256 sourceOffset, final UInt256 length, final Bytes value) { final long offset, final long sourceOffset, final long length, final Bytes value) {
final int srcOff = sourceOffset.fitsInt() ? sourceOffset.intValue() : Integer.MAX_VALUE; final long endIndex = sourceOffset + length;
final int len = length.fitsInt() ? length.intValue() : Integer.MAX_VALUE; if (sourceOffset >= 0 && endIndex > 0) {
final int endIndex = srcOff + len;
if (srcOff >= 0 && endIndex > 0) {
final int srcSize = value.size(); final int srcSize = value.size();
if (endIndex > srcSize) { if (endIndex > srcSize) {
final MutableBytes paddedAnswer = MutableBytes.create(len); final MutableBytes paddedAnswer = MutableBytes.create((int) length);
if (srcOff < srcSize) { if (sourceOffset < srcSize) {
value.slice(srcOff, srcSize - srcOff).copyTo(paddedAnswer, 0); value.slice((int) sourceOffset, (int) (srcSize - sourceOffset)).copyTo(paddedAnswer, 0);
} }
setUpdatedMemory(offset, paddedAnswer.copy()); setUpdatedMemory(offset, paddedAnswer.copy());
} else { } 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)); maybeUpdatedMemory = Optional.of(new MemoryEntry(offset, value));
} }
public void storageWasUpdated(final UInt256 storageAddress, final Bytes 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. * Accumulate a log.
@ -807,7 +804,22 @@ public class MessageFrame {
* @return true if the address was already warmed up * @return true if the address was already warmed up
*/ */
public boolean warmUpAddress(final Address address) { 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 * @return true if the storage slot was already warmed up
*/ */
public boolean warmUpStorage(final Address address, final Bytes32 slot) { 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;
} }
warmedUpAddresses = new HashSet<>(parentFrame.warmedUpAddresses); private boolean isWarm(final Address address, final Bytes32 slot) {
warmedUpStorage = HashMultimap.create(parentFrame.warmedUpStorage); MessageFrame frame = this;
while (frame != null) {
if (frame.warmedUpStorage.containsEntry(address, slot)) {
return true;
}
frame = frame.parentMessageFrame;
}
return false;
} }
public void mergeWarmedUpFields(final MessageFrame childFrame) { public void mergeWarmedUpFields(final MessageFrame childFrame) {
@ -835,8 +853,8 @@ public class MessageFrame {
return; return;
} }
warmedUpAddresses = childFrame.warmedUpAddresses; warmedUpAddresses.addAll(childFrame.warmedUpAddresses);
warmedUpStorage = childFrame.warmedUpStorage; warmedUpStorage.putAll(childFrame.warmedUpStorage);
} }
/** /**
@ -1048,7 +1066,7 @@ public class MessageFrame {
return maybeUpdatedMemory; return maybeUpdatedMemory;
} }
public Optional<MemoryEntry> getMaybeUpdatedStorage() { public Optional<StorageEntry> getMaybeUpdatedStorage() {
return maybeUpdatedStorage; return maybeUpdatedStorage;
} }

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

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

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

@ -161,10 +161,10 @@ public interface GasCalculator {
Gas callOperationGasCost( Gas callOperationGasCost(
MessageFrame frame, MessageFrame frame,
Gas stipend, Gas stipend,
UInt256 inputDataOffset, long inputDataOffset,
UInt256 inputDataLength, long inputDataLength,
UInt256 outputDataOffset, long outputDataOffset,
UInt256 outputDataLength, long outputDataLength,
Wei transferValue, Wei transferValue,
Account recipient, Account recipient,
Address contract); Address contract);
@ -215,7 +215,7 @@ public interface GasCalculator {
* @param length The length of the data being copied into memory * @param length The length of the data being copied into memory
* @return the amount of gas consumed by the data copy operation * @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. * 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 * @param length the length of the memory access
* @return The gas required to expand memory for the specified 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 // Specific Non-call Operation Calculations
@ -259,7 +259,7 @@ public interface GasCalculator {
* @param length The length of the code being copied into memory * @param length The length of the code being copied into memory
* @return the cost for executing the external code size operation * @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}. * Returns the cost for executing a {@link ExtCodeHashOperation}.
@ -291,8 +291,7 @@ public interface GasCalculator {
* @param numTopics The number of topics in the log * @param numTopics The number of topics in the log
* @return the cost for executing the external code size operation * @return the cost for executing the external code size operation
*/ */
Gas logOperationGasCost( Gas logOperationGasCost(MessageFrame frame, long dataOffset, long dataLength, int numTopics);
MessageFrame frame, UInt256 dataOffset, UInt256 dataLength, int numTopics);
/** /**
* Returns the cost for executing a {@link MLoadOperation}. * 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 * @param offset The offset in memory where the access takes place
* @return the cost for executing the memory load operation * @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}. * 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 * @param offset The offset in memory where the access takes place
* @return the cost for executing the memory store operation * @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}. * 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 * @param offset The offset in memory where the access takes place
* @return the cost for executing the memory byte store operation * @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}. * Returns the cost for executing a {@link SelfDestructOperation}.
@ -338,7 +337,7 @@ public interface GasCalculator {
* @param length The hashed data length * @param length The hashed data length
* @return the cost for executing the memory byte store operation * @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}. * 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.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
import org.apache.tuweni.units.bigints.UInt256;
public class SpuriousDragonGasCalculator extends TangerineWhistleGasCalculator { public class SpuriousDragonGasCalculator extends TangerineWhistleGasCalculator {
private static final Gas EXP_OPERATION_BYTE_GAS_COST = Gas.of(50L); private static final Gas EXP_OPERATION_BYTE_GAS_COST = Gas.of(50L);
@ -30,10 +28,10 @@ public class SpuriousDragonGasCalculator extends TangerineWhistleGasCalculator {
public Gas callOperationGasCost( public Gas callOperationGasCost(
final MessageFrame frame, final MessageFrame frame,
final Gas stipend, final Gas stipend,
final UInt256 inputDataOffset, final long inputDataOffset,
final UInt256 inputDataLength, final long inputDataLength,
final UInt256 outputDataOffset, final long outputDataOffset,
final UInt256 outputDataLength, final long outputDataLength,
final Wei transferValue, final Wei transferValue,
final Account recipient, final Account recipient,
final Address to) { 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.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
import org.apache.tuweni.units.bigints.UInt256;
public class TangerineWhistleGasCalculator extends HomesteadGasCalculator { public class TangerineWhistleGasCalculator extends HomesteadGasCalculator {
private static final Gas BALANCE_OPERATION_GAS_COST = Gas.of(400L); private static final Gas BALANCE_OPERATION_GAS_COST = Gas.of(400L);
@ -55,10 +53,10 @@ public class TangerineWhistleGasCalculator extends HomesteadGasCalculator {
public Gas callOperationGasCost( public Gas callOperationGasCost(
final MessageFrame frame, final MessageFrame frame,
final Gas stipend, final Gas stipend,
final UInt256 inputDataOffset, final long inputDataOffset,
final UInt256 inputDataLength, final long inputDataLength,
final UInt256 outputDataOffset, final long outputDataOffset,
final UInt256 outputDataLength, final long outputDataLength,
final Wei transferValue, final Wei transferValue,
final Account recipient, final Account recipient,
final Address to) { final Address to) {

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

@ -16,11 +16,11 @@
package org.hyperledger.besu.evm.internal; 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) { 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 // 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; 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 * @param frame The current message frame
* @return the memory offset the input data starts at * @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. * 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 * @param frame The current message frame
* @return the length of the input data to read from memory. * @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. * 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 * @param frame The current message frame
* @return the memory offset the offset data starts at * @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. * 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 * @param frame The current message frame
* @return the length of the output data to read from memory. * @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 * Returns the account address the call operation is being performed on
@ -174,7 +174,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
frame.clearReturnData(); frame.clearReturnData();
final Address to = to(frame); 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 Account account = frame.getWorldUpdater().get(frame.getRecipientAddress());
final Wei balance = account == null ? Wei.ZERO : account.getBalance(); final Wei balance = account == null ? Wei.ZERO : account.getBalance();
@ -216,7 +216,6 @@ public abstract class AbstractCallOperation extends AbstractOperation {
.maxStackSize(frame.getMaxStackSize()) .maxStackSize(frame.getMaxStackSize())
.build(); .build();
frame.incrementRemainingGas(cost); frame.incrementRemainingGas(cost);
childFrame.copyWarmedUpFields(frame);
frame.getMessageFrameStack().addFirst(childFrame); frame.getMessageFrameStack().addFirst(childFrame);
frame.setState(MessageFrame.State.CODE_SUSPENDED); 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) { public void complete(final MessageFrame frame, final MessageFrame childFrame) {
frame.setState(MessageFrame.State.CODE_EXECUTING); frame.setState(MessageFrame.State.CODE_EXECUTING);
final UInt256 outputOffset = outputDataOffset(frame); final long outputOffset = outputDataOffset(frame);
final UInt256 outputSize = outputDataLength(frame); final long outputSize = outputDataLength(frame);
final Bytes outputData = childFrame.getOutputData(); final Bytes outputData = childFrame.getOutputData();
final int outputSizeAsInt = outputSize.intValue();
if (outputSizeAsInt > outputData.size()) { if (outputSize > outputData.size()) {
frame.expandMemory(outputOffset, outputSize); frame.expandMemory(outputOffset, outputSize);
frame.writeMemory(outputOffset, UInt256.valueOf(outputData.size()), outputData, true); frame.writeMemory(outputOffset, outputData.size(), outputData, true);
} else { } else {
frame.writeMemory(outputOffset, outputSize, outputData, true); frame.writeMemory(outputOffset, outputSize, outputData, true);
} }

@ -14,6 +14,8 @@
*/ */
package org.hyperledger.besu.evm.operation; 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.Address;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.Code;
@ -93,8 +95,8 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
protected abstract Address targetContractAddress(MessageFrame frame); protected abstract Address targetContractAddress(MessageFrame frame);
private void fail(final MessageFrame frame) { private void fail(final MessageFrame frame) {
final UInt256 inputOffset = frame.getStackItem(1); final long inputOffset = clampedToLong(frame.getStackItem(1));
final UInt256 inputSize = frame.getStackItem(2); final long inputSize = clampedToLong(frame.getStackItem(2));
frame.readMutableMemory(inputOffset, inputSize); frame.readMutableMemory(inputOffset, inputSize);
frame.popStackItems(getStackItemsConsumed()); frame.popStackItems(getStackItemsConsumed());
frame.pushStackItem(UInt256.ZERO); frame.pushStackItem(UInt256.ZERO);
@ -111,8 +113,8 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
account.incrementNonce(); account.incrementNonce();
final Wei value = Wei.wrap(frame.getStackItem(0)); final Wei value = Wei.wrap(frame.getStackItem(0));
final UInt256 inputOffset = frame.getStackItem(1); final long inputOffset = clampedToLong(frame.getStackItem(1));
final UInt256 inputSize = frame.getStackItem(2); final long inputSize = clampedToLong(frame.getStackItem(2));
final Bytes inputData = frame.readMutableMemory(inputOffset, inputSize); final Bytes inputData = frame.readMutableMemory(inputOffset, inputSize);
final Address contractAddress = targetContractAddress(frame); final Address contractAddress = targetContractAddress(frame);
@ -144,7 +146,6 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
.build(); .build();
frame.incrementRemainingGas(cost); frame.incrementRemainingGas(cost);
childFrame.copyWarmedUpFields(frame);
frame.getMessageFrameStack().addFirst(childFrame); frame.getMessageFrameStack().addFirst(childFrame);
frame.setState(MessageFrame.State.CODE_SUSPENDED); 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.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator; 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; import org.apache.tuweni.units.bigints.UInt256;
public class AddModOperation extends AbstractFixedCostOperation { public class AddModOperation extends AbstractFixedCostOperation {
@ -27,16 +31,29 @@ public class AddModOperation extends AbstractFixedCostOperation {
} }
@Override @Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) { public Operation.OperationResult executeFixedCostOperation(
final UInt256 value0 = frame.popStackItem(); final MessageFrame frame, final EVM evm) {
final UInt256 value1 = frame.popStackItem(); final Bytes value0 = frame.popStackItem();
final UInt256 value2 = frame.popStackItem(); final Bytes value1 = frame.popStackItem();
final Bytes value2 = frame.popStackItem();
if (value2.isZero()) { if (value2.isZero()) {
frame.pushStackItem(UInt256.ZERO); frame.pushStackItem(UInt256.ZERO);
} else { } else {
final UInt256 result = value0.addMod(value1, value2); BigInteger b0 = new BigInteger(1, value0.toArrayUnsafe());
frame.pushStackItem(result); 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; return successResponse;
} }

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

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

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

@ -53,7 +53,7 @@ public class BalanceOperation extends AbstractOperation {
optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS)); optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
} else { } else {
final Account account = frame.getWorldUpdater().get(address); 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()); return new OperationResult(optionalCost, Optional.empty());
} }
} catch (final UnderflowException ufe) { } catch (final UnderflowException ufe) {

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

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

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

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

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

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

@ -28,7 +28,8 @@ public class CallDataSizeOperation extends AbstractFixedCostOperation {
} }
@Override @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(); final Bytes callData = frame.getInputData();
frame.pushStackItem(UInt256.valueOf(callData.size())); frame.pushStackItem(UInt256.valueOf(callData.size()));

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

@ -26,7 +26,8 @@ public class CallValueOperation extends AbstractFixedCostOperation {
} }
@Override @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(); final Wei value = frame.getApparentValue();
frame.pushStackItem(value.toUInt256()); frame.pushStackItem(value.toUInt256());

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

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

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

@ -28,7 +28,8 @@ public class CodeSizeOperation extends AbstractFixedCostOperation {
} }
@Override @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(); final Code code = frame.getCode();
frame.pushStackItem(UInt256.valueOf(code.getSize())); 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.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
public class CoinbaseOperation extends AbstractFixedCostOperation { public class CoinbaseOperation extends AbstractFixedCostOperation {
@ -27,9 +26,10 @@ public class CoinbaseOperation extends AbstractFixedCostOperation {
} }
@Override @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(); final Address coinbase = frame.getMiningBeneficiary();
frame.pushStackItem(Words.fromAddress(coinbase)); frame.pushStackItem(coinbase);
return successResponse; return successResponse;
} }

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

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

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

@ -18,6 +18,9 @@ import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
public class DivOperation extends AbstractFixedCostOperation { public class DivOperation extends AbstractFixedCostOperation {
@ -27,15 +30,27 @@ public class DivOperation extends AbstractFixedCostOperation {
} }
@Override @Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) { public Operation.OperationResult executeFixedCostOperation(
final UInt256 value0 = frame.popStackItem(); final MessageFrame frame, final EVM evm) {
final UInt256 value1 = frame.popStackItem(); final Bytes value0 = frame.popStackItem();
final Bytes value1 = frame.popStackItem();
if (value1.isZero()) { if (value1.isZero()) {
frame.pushStackItem(UInt256.ZERO); frame.pushStackItem(UInt256.ZERO);
} else { } else {
final UInt256 result = value0.divide(value1); BigInteger b1 = new BigInteger(1, value0.toArrayUnsafe());
frame.pushStackItem(result); 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; return successResponse;

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

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

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

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

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

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

@ -26,7 +26,8 @@ public class GasPriceOperation extends AbstractFixedCostOperation {
} }
@Override @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(); final Wei gasPrice = frame.getGasPrice();
frame.pushStackItem(gasPrice.toUInt256()); frame.pushStackItem(gasPrice.toUInt256());

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

Loading…
Cancel
Save