Implementation of EIP-2929 (#1387)

* store warmed addresses and slots i the MessageFrame
* update gas calculations for berlin specific rules
* allow state tests in EVMTool to override the forks.
* retesteth should't broadcast re-orgs

Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
pull/1413/head
Danno Ferrin 4 years ago committed by GitHub
parent 6034b89b54
commit 0f69337944
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 29
      ethereum/core/build.gradle
  3. 206
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BerlinGasCalculator.java
  4. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/FrontierGasCalculator.java
  5. 1
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
  6. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/SpuriousDragonGasCalculator.java
  7. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TangerineWhistleGasCalculator.java
  8. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/AbstractCallOperation.java
  9. 46
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/GasCalculator.java
  10. 39
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/MessageFrame.java
  11. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/StandardJsonTracer.java
  12. 1
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/AbstractCreateOperation.java
  13. 44
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/BalanceOperation.java
  14. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/CallCodeOperation.java
  15. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/CallOperation.java
  16. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/Create2Operation.java
  17. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/CreateOperation.java
  18. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/DelegateCallOperation.java
  19. 11
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/ExtCodeCopyOperation.java
  20. 57
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/ExtCodeHashOperation.java
  21. 53
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/ExtCodeSizeOperation.java
  22. 51
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/SLoadOperation.java
  23. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/SStoreOperation.java
  24. 9
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/SelfDestructOperation.java
  25. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/operations/StaticCallOperation.java
  26. 55
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/vm/operations/Create2OperationTest.java
  27. 34
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java
  28. 57
      ethereum/evmtool/src/test/benchmarks/bench-yolov2.sh
  29. 5
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/GeneralStateTestCaseSpec.java
  30. 2
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java

@ -3,8 +3,9 @@
## 1.6.0-RC1
### Additions and Improvements
* Added support for the upcoming YOLOv2 ephemeral testnet and removed the flag for the deprecated YOLOv1 ephemeral testnet.
* Added support for the upcoming YOLOv2 ephemeral testnet and removed the flag for the deprecated YOLOv1 ephemeral testnet. [#1386](https://github.com/hyperledger/besu/pull/1386)
* Added `debug_standardTraceBlockToFile` JSON-RPC API. This API accepts a block hash and will replay the block. It returns a list of files containing the result of the trace (one file per transaction). [\#1392](https://github.com/hyperledger/besu/pull/1392)
* Added support for EIP-2929 to YOLOv2. [#1387](https://github.com/hyperledger/besu/pull/1387)
### Bug Fixes

@ -52,8 +52,8 @@ dependencies {
runtimeOnly 'org.apache.logging.log4j:log4j-core'
testImplementation project(path: ':config', configuration: 'testSupportArtifacts')
testImplementation project(path:':ethereum:referencetests')
testImplementation project(path:':ethereum:referencetests', configuration: 'testOutput')
testImplementation project(path: ':ethereum:referencetests')
testImplementation project(path: ':ethereum:referencetests', configuration: 'testOutput')
testImplementation project(':testutil')
testImplementation 'junit:junit'
@ -95,7 +95,7 @@ dependencies {
}
configurations { testArtifacts }
task testJar (type: Jar) {
task testJar(type: Jar) {
archiveBaseName = "${project.name}-test"
from sourceSets.test.output
}
@ -147,6 +147,17 @@ task blockchainReferenceTestsSetup {
)
}
task legacyBlockchainReferenceTestsSetup {
generateTestFiles(
fileTree('../referencetests/src/test/resources/LegacyTests/Constantinople/BlockchainTests'),
file("./src/test/resources/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTest.java.template"),
"LegacyTests",
"./src/test/java/org/hyperledger/besu/ethereum/vm/blockchain",
"LegacyBlockchainReferenceTest",
("BlockchainTests/InvalidBlocks/bcExpectSection") // exclude test for test filling tool
)
}
task generalstateReferenceTestsSetup {
generateTestFiles(
fileTree("../referencetests/src/test/resources/GeneralStateTests"),
@ -157,6 +168,16 @@ task generalstateReferenceTestsSetup {
)
}
task legacyGeneralstateReferenceTestsSetup {
generateTestFiles(
fileTree('../referencetests/src/test/resources/LegacyTests/Constantinople/GeneralStateTests'),
file("./src/test/resources/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTest.java.template"),
"LegacyTests",
"./src/test/java/org/hyperledger/besu/ethereum/vm/generalstate",
"LegacyGeneralStateReferenceTest"
)
}
task generalstateRegressionReferenceTestsSetup {
generateTestFiles(
fileTree("./src/test/resources/regressions/generalstate"),
@ -180,6 +201,8 @@ clean.dependsOn(cleanupReferenceTests)
task referenceTests(type: Test, dependsOn: [
"blockchainReferenceTestsSetup",
"generalstateReferenceTestsSetup",
"legacyBlockchainReferenceTestsSetup",
"legacyGeneralstateReferenceTestsSetup",
"generalstateRegressionReferenceTestsSetup",
"compileTestJava"
]) {

@ -0,0 +1,206 @@
/*
* 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.ethereum.mainnet;
import static org.hyperledger.besu.ethereum.core.Address.BLS12_MAP_FP2_TO_G2;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.apache.tuweni.units.bigints.UInt256;
public class BerlinGasCalculator extends IstanbulGasCalculator {
// new constants for EIP-2929
private static final Gas COLD_SLOAD_COST = Gas.of(2100);
private static final Gas COLD_ACCOUNT_ACCESS_COST = Gas.of(2600);
private static final Gas WARM_STORAGE_READ_COST = Gas.of(100);
// redefinitions for EIP-2929
private static final Gas SLOAD_GAS = WARM_STORAGE_READ_COST;
private static final Gas SSTORE_RESET_GAS = Gas.of(5000L).minus(COLD_SLOAD_COST);
// unchanged from Istanbul
private static final Gas SSTORE_SET_GAS = Gas.of(20_000);
private static final Gas SSTORE_CLEARS_SCHEDULE = Gas.of(15_000);
private static final Gas SSTORE_SET_GAS_LESS_SLOAD_GAS = SSTORE_SET_GAS.minus(SLOAD_GAS);
private static final Gas SSTORE_RESET_GAS_LESS_SLOAD_GAS = SSTORE_RESET_GAS.minus(SLOAD_GAS);
private static final Gas NEGATIVE_SSTORE_CLEARS_SCHEDULE = Gas.ZERO.minus(SSTORE_CLEARS_SCHEDULE);
// unchanged from Frontier
private static final Gas COPY_WORD_GAS_COST = Gas.of(3L);
private final int maxPrecompile;
protected BerlinGasCalculator(final int maxPrecompile) {
this.maxPrecompile = maxPrecompile;
}
public BerlinGasCalculator() {
this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19]);
}
@Override
public boolean isPrecompile(final Address address) {
final byte[] addressBytes = address.toArrayUnsafe();
for (int i = 0; i < 19; i++) {
if (addressBytes[i] != 0) {
return false;
}
}
final int lastByte = Byte.toUnsignedInt(addressBytes[19]);
return lastByte <= maxPrecompile && lastByte != 0;
}
// new costs
@Override
public Gas getColdSloadCost() {
return COLD_SLOAD_COST;
}
@Override
public Gas getColdAccountAccessCost() {
return COLD_ACCOUNT_ACCESS_COST;
}
@Override
public Gas getWarmStorageReadCost() {
return WARM_STORAGE_READ_COST;
}
// Zeroed out old costs
@Override
public Gas getBalanceOperationGasCost() {
return Gas.ZERO;
}
@Override
protected Gas callOperationBaseGasCost() {
return Gas.ZERO;
}
@Override
public Gas extCodeHashOperationGasCost() {
return Gas.ZERO;
}
@Override
public Gas getExtCodeSizeOperationGasCost() {
return Gas.ZERO;
}
@Override
public Gas getSloadOperationGasCost() {
return Gas.ZERO;
}
// Redefined costs from EIP-2929
@Override
public Gas callOperationGasCost(
final MessageFrame frame,
final Gas stipend,
final UInt256 inputDataOffset,
final UInt256 inputDataLength,
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to) {
final Gas baseCost =
super.callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
transferValue,
recipient,
to);
final boolean accountIsWarm = frame.warmUpAddress(to) || isPrecompile(to);
return baseCost.plus(accountIsWarm ? getWarmStorageReadCost() : getColdAccountAccessCost());
}
// defined in Frontier, but re-implemented with no base cost.
@Override
public Gas extCodeCopyOperationGasCost(
final MessageFrame frame, final UInt256 offset, final UInt256 length) {
return copyWordsToMemoryGasCost(frame, Gas.ZERO, COPY_WORD_GAS_COST, offset, length);
}
// defined in Istanbul, but re-implemented with new constants
@Override
// As per https://eips.ethereum.org/EIPS/eip-2200
public Gas calculateStorageCost(
final Account account, final UInt256 key, final UInt256 newValue) {
final UInt256 currentValue = account.getStorageValue(key);
if (currentValue.equals(newValue)) {
return SLOAD_GAS;
} else {
final UInt256 originalValue = account.getOriginalStorageValue(key);
if (originalValue.equals(currentValue)) {
return originalValue.isZero() ? SSTORE_SET_GAS : SSTORE_RESET_GAS;
} else {
return SLOAD_GAS;
}
}
}
// defined in Istanbul, but re-implemented with new constants
@Override
// As per https://eips.ethereum.org/EIPS/eip-2200
public Gas calculateStorageRefundAmount(
final Account account, final UInt256 key, final UInt256 newValue) {
final UInt256 currentValue = account.getStorageValue(key);
if (currentValue.equals(newValue)) {
return Gas.ZERO;
} else {
final UInt256 originalValue = account.getOriginalStorageValue(key);
if (originalValue.equals(currentValue)) {
if (originalValue.isZero()) {
return Gas.ZERO;
} else if (newValue.isZero()) {
return SSTORE_CLEARS_SCHEDULE;
} else {
return Gas.ZERO;
}
} else {
Gas refund = Gas.ZERO;
if (!originalValue.isZero()) {
if (currentValue.isZero()) {
refund = NEGATIVE_SSTORE_CLEARS_SCHEDULE;
} else if (newValue.isZero()) {
refund = SSTORE_CLEARS_SCHEDULE;
}
}
if (originalValue.equals(newValue)) {
refund =
refund.plus(
originalValue.isZero()
? SSTORE_SET_GAS_LESS_SLOAD_GAS
: SSTORE_RESET_GAS_LESS_SLOAD_GAS);
}
return refund;
}
}
}
}

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
@ -241,7 +242,8 @@ public class FrontierGasCalculator implements GasCalculator {
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final Wei transferValue,
final Account recipient) {
final Account recipient,
final Address to) {
final Gas inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final Gas outputDataMemoryExpansionCost =
@ -446,7 +448,7 @@ public class FrontierGasCalculator implements GasCalculator {
"BEGINSUB operation not supported by " + getClass().getSimpleName());
}
private Gas copyWordsToMemoryGasCost(
protected Gas copyWordsToMemoryGasCost(
final MessageFrame frame,
final Gas baseGasCost,
final Gas wordGasCost,

@ -348,6 +348,7 @@ public abstract class MainnetProtocolSpecs {
}
return muirGlacierDefinition(
chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason)
.gasCalculator(BerlinGasCalculator::new)
.evmBuilder(
gasCalculator ->
MainnetEvmRegistries.berlin(gasCalculator, chainId.orElse(BigInteger.ZERO)))

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
@ -34,7 +35,8 @@ public class SpuriousDragonGasCalculator extends TangerineWhistleGasCalculator {
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final Wei transferValue,
final Account recipient) {
final Account recipient,
final Address to) {
final Gas inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final Gas outputDataMemoryExpansionCost =

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
@ -59,7 +60,8 @@ public class TangerineWhistleGasCalculator extends HomesteadGasCalculator {
final UInt256 outputDataOffset,
final UInt256 outputDataLength,
final Wei transferValue,
final Account recipient) {
final Account recipient,
final Address to) {
final Gas inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final Gas outputDataMemoryExpansionCost =

@ -213,6 +213,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
.returnStack(frame.getReturnStack())
.build();
frame.incrementRemainingGas(cost);
childFrame.mergeWarmedUpFields(frame);
frame.getMessageFrameStack().addFirst(childFrame);
frame.setState(MessageFrame.State.CODE_SUSPENDED);
@ -247,6 +248,7 @@ public abstract class AbstractCallOperation extends AbstractOperation {
frame.popStackItems(getStackItemsConsumed());
if (childFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
frame.mergeWarmedUpFields(childFrame);
frame.pushStackItem(UInt256.ONE.toBytes());
} else {
frame.pushStackItem(Bytes32.ZERO);

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.vm;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei;
@ -164,7 +165,8 @@ public interface GasCalculator {
* @param outputDataOffset The offset in memory to place the CALL output data
* @param outputDataLength The CALL output data length
* @param transferValue The wei being transferred
* @param recipient The CALL recipient
* @param recipient The CALL recipient (may be null if self destructed or new)
* @param contract The address of the recipient (never null)
* @return The gas cost for the CALL operation
*/
Gas callOperationGasCost(
@ -175,7 +177,8 @@ public interface GasCalculator {
UInt256 outputDataOffset,
UInt256 outputDataLength,
Wei transferValue,
Account recipient);
Account recipient,
Address contract);
Gas getAdditionalCallStipend();
@ -388,4 +391,43 @@ public interface GasCalculator {
* @return the cost for executing begin sub operation
*/
Gas getBeginSubGasCost();
/**
* Returns the cost of a SLOAD to a storage slot not previously loaded in the TX context.
*
* @return the cost of a SLOAD to a storage slot not previously loaded in the TX context.
*/
default Gas getColdSloadCost() {
return Gas.ZERO;
}
/**
* Returns the cost to access an account not previously accessed in the TX context.
*
* @return the cost to access an account not previously accessed in the TX context.
*/
default Gas getColdAccountAccessCost() {
return Gas.ZERO;
}
/**
* Returns the cost of a SLOAD to a storage slot that has previously been loaded in the TX
* context.
*
* @return the cost of a SLOAD to a storage slot that has previously been loaded in the TX
* context.
*/
default Gas getWarmStorageReadCost() {
return Gas.ZERO;
}
/**
* For the purposes of this gas calculator, is this address a precompile?
*
* @param address the address to test for being a precompile
* @return true if it is a precompile.
*/
default boolean isPrecompile(final Address address) {
return false;
}
}

@ -41,6 +41,8 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.MutableBytes;
@ -212,6 +214,8 @@ public class MessageFrame {
private Gas gasRefund;
private final Set<Address> selfDestructs;
private final Map<Address, Wei> refunds;
private final Set<Address> warmedUpAddresses;
private final Multimap<Address, Bytes32> warmedUpStorage;
// Execution Environment fields.
private final Address recipient;
@ -315,6 +319,11 @@ public class MessageFrame {
this.privateMetadataUpdater = privateMetadataUpdater;
this.transactionHash = transactionHash;
this.revertReason = revertReason;
this.warmedUpAddresses = new HashSet<>();
warmedUpAddresses.add(sender);
warmedUpAddresses.add(contract);
this.warmedUpStorage = HashMultimap.create();
}
/**
@ -828,6 +837,36 @@ public class MessageFrame {
return refunds;
}
/**
* "Warms up" the address as per EIP-2929
*
* @param address the address to warm up
* @return true if the address was already warmed up
*/
public boolean warmUpAddress(final Address address) {
return !warmedUpAddresses.add(address);
}
/**
* "Warms up" the storage slot as per EIP-2929
*
* @param address the address whose storage is being warmed up
* @param slot the slot being warmed up
* @return true if the storage slot was already warmed up
*/
public boolean warmUpStorage(final Address address, final Bytes32 slot) {
return !warmedUpStorage.put(address, slot);
}
public void mergeWarmedUpFields(final MessageFrame childFrame) {
if (childFrame == this) {
return;
}
warmedUpAddresses.addAll(childFrame.warmedUpAddresses);
warmedUpStorage.putAll(childFrame.warmedUpStorage);
}
/**
* Returns the current blockchain.
*

@ -83,14 +83,15 @@ public class StandardJsonTracer implements OperationTracer {
final ArrayNode returnStack = traceLine.putArray("returnStack");
final ReturnStack rs = messageFrame.getReturnStack();
for (int i = rs.size() - 1; i >= 0; i--) {
returnStack.add(rs.get(i));
returnStack.add("0x" + Integer.toHexString(rs.get(i) - 1));
}
Bytes returnData = messageFrame.getReturnData();
traceLine.put("returnData", returnData.size() > 0 ? returnData.toHexString() : null);
traceLine.put("depth", messageFrame.getMessageStackDepth() + 1);
traceLine.put("refund", messageFrame.getGasRefund().toLong());
final OperationResult executeResult = executeOperation.execute();
traceLine.put("refund", messageFrame.getGasRefund().toLong());
traceLine.put(
"gasCost", executeResult.getGasCost().map(gas -> shortNumber(gas.asUInt256())).orElse(""));
if (showMemory) {

@ -149,6 +149,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
.build();
frame.incrementRemainingGas(cost);
childFrame.mergeWarmedUpFields(frame);
frame.getMessageFrameStack().addFirst(childFrame);
frame.setState(MessageFrame.State.CODE_SUSPENDED);

@ -16,26 +16,52 @@ package org.hyperledger.besu.ethereum.vm.operations;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.vm.AbstractOperation;
import org.hyperledger.besu.ethereum.vm.EVM;
import org.hyperledger.besu.ethereum.vm.ExceptionalHaltReason;
import org.hyperledger.besu.ethereum.vm.FixedStack.OverflowException;
import org.hyperledger.besu.ethereum.vm.FixedStack.UnderflowException;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.Words;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
public class BalanceOperation extends AbstractFixedCostOperation {
public class BalanceOperation extends AbstractOperation {
private final Optional<Gas> warmCost;
private final Optional<Gas> coldCost;
public BalanceOperation(final GasCalculator gasCalculator) {
super(
0x31, "BALANCE", 1, 1, false, 1, gasCalculator, gasCalculator.getBalanceOperationGasCost());
super(0x31, "BALANCE", 1, 1, false, 1, gasCalculator);
final Gas baseCost = gasCalculator.getBalanceOperationGasCost();
warmCost = Optional.of(baseCost.plus(gasCalculator.getWarmStorageReadCost()));
coldCost = Optional.of(baseCost.plus(gasCalculator.getColdAccountAccessCost()));
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Address accountAddress = Words.toAddress(frame.popStackItem());
final Account account = frame.getWorldState().get(accountAddress);
frame.pushStackItem(account == null ? Bytes32.ZERO : account.getBalance().toBytes());
return successResponse;
public OperationResult execute(final MessageFrame frame, final EVM evm) {
try {
final Address address = Words.toAddress(frame.popStackItem());
final boolean accountIsWarm =
frame.warmUpAddress(address) || gasCalculator().isPrecompile(address);
final Optional<Gas> optionalCost = accountIsWarm ? warmCost : coldCost;
if (frame.getRemainingGas().compareTo(optionalCost.get()) < 0) {
return new OperationResult(
optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
} else {
final Account account = frame.getWorldState().get(address);
frame.pushStackItem(account == null ? Bytes32.ZERO : account.getBalance().toBytes());
return new OperationResult(optionalCost, Optional.empty());
}
} catch (final UnderflowException ufe) {
return new OperationResult(
warmCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS));
} catch (final OverflowException ofe) {
return new OperationResult(warmCost, Optional.of(ExceptionalHaltReason.TOO_MANY_STACK_ITEMS));
}
}
}

@ -109,6 +109,7 @@ public class CallCodeOperation extends AbstractCallOperation {
outputDataOffset,
outputDataLength,
value(frame),
recipient);
recipient,
to(frame));
}
}

@ -113,7 +113,8 @@ public class CallOperation extends AbstractCallOperation {
outputDataOffset,
outputDataLength,
value(frame),
recipient);
recipient,
to(frame));
}
@Override

@ -40,7 +40,9 @@ public class Create2Operation extends AbstractCreateOperation {
final Bytes32 salt = frame.getStackItem(3);
final Bytes initCode = frame.readMemory(offset, length);
final Hash hash = Hash.hash(Bytes.concatenate(PREFIX, sender, salt, Hash.hash(initCode)));
return Address.extract(hash);
final Address address = Address.extract(hash);
frame.warmUpAddress(address);
return address;
}
@Override

@ -35,6 +35,9 @@ public class CreateOperation extends AbstractCreateOperation {
protected Address targetContractAddress(final MessageFrame frame) {
final Account sender = frame.getWorldState().get(frame.getRecipientAddress());
// Decrement nonce by 1 to normalize the effect of transaction execution
return Address.contractAddress(frame.getRecipientAddress(), sender.getNonce() - 1L);
final Address address =
Address.contractAddress(frame.getRecipientAddress(), sender.getNonce() - 1L);
frame.warmUpAddress(address);
return address;
}
}

@ -109,6 +109,7 @@ public class DelegateCallOperation extends AbstractCallOperation {
outputDataOffset,
outputDataLength,
Wei.ZERO,
recipient);
recipient,
to(frame));
}
}

@ -42,7 +42,16 @@ public class ExtCodeCopyOperation extends AbstractOperation {
final UInt256 sourceOffset = UInt256.fromBytes(frame.popStackItem());
final UInt256 numBytes = UInt256.fromBytes(frame.popStackItem());
final Gas cost = gasCalculator().extCodeCopyOperationGasCost(frame, memOffset, numBytes);
final boolean accountIsWarm =
frame.warmUpAddress(address) || gasCalculator().isPrecompile(address);
final Gas cost =
gasCalculator()
.extCodeCopyOperationGasCost(frame, memOffset, numBytes)
.plus(
accountIsWarm
? gasCalculator().getWarmStorageReadCost()
: gasCalculator().getColdAccountAccessCost());
final Optional<Gas> optionalCost = Optional.of(cost);
if (frame.getRemainingGas().compareTo(cost) < 0) {
return new OperationResult(optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));

@ -16,37 +16,56 @@ package org.hyperledger.besu.ethereum.vm.operations;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.vm.AbstractOperation;
import org.hyperledger.besu.ethereum.vm.EVM;
import org.hyperledger.besu.ethereum.vm.ExceptionalHaltReason;
import org.hyperledger.besu.ethereum.vm.FixedStack.OverflowException;
import org.hyperledger.besu.ethereum.vm.FixedStack.UnderflowException;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.Words;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
public class ExtCodeHashOperation extends AbstractFixedCostOperation {
public class ExtCodeHashOperation extends AbstractOperation {
private final Optional<Gas> warmCost;
private final Optional<Gas> coldCost;
public ExtCodeHashOperation(final GasCalculator gasCalculator) {
super(
0x3F,
"EXTCODEHASH",
1,
1,
false,
1,
gasCalculator,
gasCalculator.extCodeHashOperationGasCost());
super(0x3F, "EXTCODEHASH", 1, 1, false, 1, gasCalculator);
final Gas baseCost = gasCalculator.extCodeHashOperationGasCost();
warmCost = Optional.of(baseCost.plus(gasCalculator.getWarmStorageReadCost()));
coldCost = Optional.of(baseCost.plus(gasCalculator.getColdAccountAccessCost()));
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Address address = Words.toAddress(frame.popStackItem());
final Account account = frame.getWorldState().get(address);
if (account == null || account.isEmpty()) {
frame.pushStackItem(Bytes32.ZERO);
} else {
frame.pushStackItem(account.getCodeHash());
public OperationResult execute(final MessageFrame frame, final EVM evm) {
try {
final Address address = Words.toAddress(frame.popStackItem());
final boolean accountIsWarm =
frame.warmUpAddress(address) || gasCalculator().isPrecompile(address);
final Optional<Gas> optionalCost = accountIsWarm ? warmCost : coldCost;
if (frame.getRemainingGas().compareTo(optionalCost.get()) < 0) {
return new OperationResult(
optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
} else {
final Account account = frame.getWorldState().get(address);
if (account == null || account.isEmpty()) {
frame.pushStackItem(Bytes32.ZERO);
} else {
frame.pushStackItem(account.getCodeHash());
}
return new OperationResult(optionalCost, Optional.empty());
}
} catch (final UnderflowException ufe) {
return new OperationResult(
warmCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS));
} catch (final OverflowException ofe) {
return new OperationResult(warmCost, Optional.of(ExceptionalHaltReason.TOO_MANY_STACK_ITEMS));
}
return successResponse;
}
}

@ -16,35 +16,54 @@ package org.hyperledger.besu.ethereum.vm.operations;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.vm.AbstractOperation;
import org.hyperledger.besu.ethereum.vm.EVM;
import org.hyperledger.besu.ethereum.vm.ExceptionalHaltReason;
import org.hyperledger.besu.ethereum.vm.FixedStack.OverflowException;
import org.hyperledger.besu.ethereum.vm.FixedStack.UnderflowException;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.Words;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
public class ExtCodeSizeOperation extends AbstractFixedCostOperation {
public class ExtCodeSizeOperation extends AbstractOperation {
private final Optional<Gas> warmCost;
private final Optional<Gas> coldCost;
public ExtCodeSizeOperation(final GasCalculator gasCalculator) {
super(
0x3B,
"EXTCODESIZE",
1,
1,
false,
1,
gasCalculator,
gasCalculator.getExtCodeSizeOperationGasCost());
super(0x3B, "EXTCODESIZE", 1, 1, false, 1, gasCalculator);
final Gas baseCost = gasCalculator.getExtCodeSizeOperationGasCost();
warmCost = Optional.of(baseCost.plus(gasCalculator.getWarmStorageReadCost()));
coldCost = Optional.of(baseCost.plus(gasCalculator.getColdAccountAccessCost()));
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Address address = Words.toAddress(frame.popStackItem());
final Account account = frame.getWorldState().get(address);
frame.pushStackItem(
account == null ? Bytes32.ZERO : UInt256.valueOf(account.getCode().size()).toBytes());
return successResponse;
public OperationResult execute(final MessageFrame frame, final EVM evm) {
try {
final Address address = Words.toAddress(frame.popStackItem());
final boolean accountIsWarm =
frame.warmUpAddress(address) || gasCalculator().isPrecompile(address);
final Optional<Gas> optionalCost = accountIsWarm ? warmCost : coldCost;
if (frame.getRemainingGas().compareTo(optionalCost.get()) < 0) {
return new OperationResult(
optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
} else {
final Account account = frame.getWorldState().get(address);
frame.pushStackItem(
account == null ? Bytes32.ZERO : UInt256.valueOf(account.getCode().size()).toBytes());
return new OperationResult(optionalCost, Optional.empty());
}
} catch (final UnderflowException ufe) {
return new OperationResult(
warmCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS));
} catch (final OverflowException ofe) {
return new OperationResult(warmCost, Optional.of(ExceptionalHaltReason.TOO_MANY_STACK_ITEMS));
}
}
}

@ -15,27 +15,60 @@
package org.hyperledger.besu.ethereum.vm.operations;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.vm.AbstractOperation;
import org.hyperledger.besu.ethereum.vm.EVM;
import org.hyperledger.besu.ethereum.vm.ExceptionalHaltReason;
import org.hyperledger.besu.ethereum.vm.FixedStack.OverflowException;
import org.hyperledger.besu.ethereum.vm.FixedStack.UnderflowException;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
public class SLoadOperation extends AbstractFixedCostOperation {
public class SLoadOperation extends AbstractOperation {
private final Optional<Gas> warmCost;
private final Optional<Gas> coldCost;
private final OperationResult warmSuccess;
private final OperationResult coldSuccess;
public SLoadOperation(final GasCalculator gasCalculator) {
super(0x54, "SLOAD", 1, 1, false, 1, gasCalculator, gasCalculator.getSloadOperationGasCost());
super(0x54, "SLOAD", 1, 1, false, 1, gasCalculator);
final Gas baseCost = gasCalculator.getSloadOperationGasCost();
warmCost = Optional.of(baseCost.plus(gasCalculator.getWarmStorageReadCost()));
coldCost = Optional.of(baseCost.plus(gasCalculator.getColdSloadCost()));
warmSuccess = new OperationResult(warmCost, Optional.empty());
coldSuccess = new OperationResult(coldCost, Optional.empty());
}
@Override
public OperationResult executeFixedCostOperation(final MessageFrame frame, final EVM evm) {
final Bytes32 key = frame.popStackItem();
final Account account = frame.getWorldState().get(frame.getRecipientAddress());
frame.pushStackItem(account.getStorageValue(UInt256.fromBytes(key)).toBytes());
public OperationResult execute(final MessageFrame frame, final EVM evm) {
try {
final Account account = frame.getWorldState().get(frame.getRecipientAddress());
final Address address = account.getAddress();
final Bytes32 key = frame.popStackItem();
final boolean slotIsWarm = frame.warmUpStorage(address, key);
final Optional<Gas> optionalCost = slotIsWarm ? warmCost : coldCost;
if (frame.getRemainingGas().compareTo(optionalCost.get()) < 0) {
return new OperationResult(
optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
} else {
frame.pushStackItem(account.getStorageValue(UInt256.fromBytes(key)).toBytes());
return successResponse;
return slotIsWarm ? warmSuccess : coldSuccess;
}
} catch (final UnderflowException ufe) {
return new OperationResult(
warmCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS));
} catch (final OverflowException ofe) {
return new OperationResult(warmCost, Optional.of(ExceptionalHaltReason.TOO_MANY_STACK_ITEMS));
}
}
}

@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.ethereum.vm.operations;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.MutableAccount;
import org.hyperledger.besu.ethereum.vm.AbstractOperation;
@ -57,7 +58,14 @@ public class SStoreOperation extends AbstractOperation {
if (account == null) {
return ILLEGAL_STATE_CHANGE;
}
final Gas cost = gasCalculator().calculateStorageCost(account, key, value);
final Address address = account.getAddress();
final boolean slotIsWarm = frame.warmUpStorage(address, key.toBytes());
final Gas cost =
gasCalculator()
.calculateStorageCost(account, key, value)
.plus(slotIsWarm ? Gas.ZERO : gasCalculator().getColdSloadCost());
final Optional<Gas> optionalCost = Optional.of(cost);
final Gas remainingGas = frame.getRemainingGas();
if (frame.isStatic()) {

@ -42,8 +42,15 @@ public class SelfDestructOperation extends AbstractOperation {
final Account recipientNullable = frame.getWorldState().get(recipientAddress);
final Wei inheritance = frame.getWorldState().get(frame.getRecipientAddress()).getBalance();
final Gas cost = gasCalculator().selfDestructOperationGasCost(recipientNullable, inheritance);
final boolean accountIsWarm =
frame.warmUpAddress(recipientAddress) || gasCalculator().isPrecompile(recipientAddress);
final Gas cost =
gasCalculator()
.selfDestructOperationGasCost(recipientNullable, inheritance)
.plus(accountIsWarm ? Gas.ZERO : gasCalculator().getColdAccountAccessCost());
final Optional<Gas> optionalCost = Optional.of(cost);
if (frame.isStatic()) {
return new OperationResult(
optionalCost, Optional.of(ExceptionalHaltReason.ILLEGAL_STATE_CHANGE));

@ -109,6 +109,7 @@ public class StaticCallOperation extends AbstractCallOperation {
outputDataOffset,
outputDataLength,
value(frame),
recipient);
recipient,
to(frame));
}
}

@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.core.WorldUpdater;
import org.hyperledger.besu.ethereum.mainnet.ConstantinopleGasCalculator;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.Code;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.Operation.OperationResult;
@ -51,7 +52,7 @@ public class Create2OperationTest {
private final String code;
private final String expectedAddress;
private final int expectedGas;
private final MessageFrame messageFrame = mock(MessageFrame.class);
private MessageFrame messageFrame;
private final WorldUpdater worldUpdater = mock(WorldUpdater.class);
private final DefaultEvmAccount account = mock(DefaultEvmAccount.class);
private final MutableAccount mutableAccount = mock(MutableAccount.class);
@ -128,31 +129,41 @@ public class Create2OperationTest {
@Before
public void setUp() {
when(messageFrame.getRecipientAddress()).thenReturn(Address.fromHexString(sender));
final Bytes32 memoryOffset = Bytes32.fromHexString("0xFF");
final Bytes codeBytes = Bytes.fromHexString(code);
final UInt256 memoryLength = UInt256.valueOf(codeBytes.size());
when(account.getMutable()).thenReturn(mutableAccount);
when(messageFrame.calculateMemoryExpansion(any(), any())).thenReturn(UInt256.valueOf(500));
when(messageFrame.getBlockHashLookup()).thenReturn(mock(BlockHashLookup.class));
when(messageFrame.getBlockHeader()).thenReturn(mock(ProcessableBlockHeader.class));
when(messageFrame.getBlockchain()).thenReturn(mock(Blockchain.class));
when(messageFrame.getBlockchain()).thenReturn(mock(Blockchain.class));
when(messageFrame.getGasPrice()).thenReturn(Wei.ZERO);
when(messageFrame.getMessageFrameStack()).thenReturn(new ArrayDeque<>());
when(messageFrame.getMiningBeneficiary()).thenReturn(Address.ZERO);
when(messageFrame.getOriginatorAddress()).thenReturn(Address.ZERO);
when(messageFrame.getRemainingGas()).thenReturn(Gas.of(100000));
when(messageFrame.getReturnStack()).thenReturn(mock(ReturnStack.class));
when(messageFrame.getStackItem(0)).thenReturn(Bytes32.ZERO);
when(messageFrame.getStackItem(1)).thenReturn(memoryOffset);
when(messageFrame.getStackItem(2)).thenReturn(memoryLength.toBytes());
when(messageFrame.getStackItem(3)).thenReturn(Bytes32.fromHexString(salt));
when(messageFrame.getWorldState()).thenReturn(worldUpdater);
when(messageFrame.memoryWordSize()).thenReturn(UInt256.valueOf(500));
when(messageFrame.readMemory(UInt256.fromBytes(memoryOffset), memoryLength))
.thenReturn(codeBytes);
when(messageFrame.stackSize()).thenReturn(4);
messageFrame =
MessageFrame.builder()
.type(MessageFrame.Type.CONTRACT_CREATION)
.contract(Address.ZERO)
.inputData(Bytes.EMPTY)
.sender(Address.fromHexString(sender))
.value(Wei.ZERO)
.apparentValue(Wei.ZERO)
.code(new Code(codeBytes))
.depth(1)
.completer(__ -> {})
.contractAccountVersion(0)
.address(Address.fromHexString(sender))
.blockHashLookup(mock(BlockHashLookup.class))
.blockHeader(mock(ProcessableBlockHeader.class))
.blockchain(mock(Blockchain.class))
.gasPrice(Wei.ZERO)
.messageFrameStack(new ArrayDeque<>())
.miningBeneficiary(Address.ZERO)
.originator(Address.ZERO)
.initialGas(Gas.of(100000))
.worldState(worldUpdater)
.build();
messageFrame.pushStackItem(Bytes32.fromHexString(salt));
messageFrame.pushStackItem(memoryLength.toBytes());
messageFrame.pushStackItem(memoryOffset);
messageFrame.pushStackItem(Bytes32.ZERO);
messageFrame.expandMemory(UInt256.ZERO, UInt256.valueOf(500));
messageFrame.writeMemory(
UInt256.fromBytes(memoryOffset), UInt256.valueOf(code.length()), codeBytes);
when(mutableAccount.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);

@ -57,6 +57,7 @@ import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.tuweni.units.bigints.UInt256;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import picocli.CommandLine.ParentCommand;
@ -69,6 +70,12 @@ public class StateTestSubCommand implements Runnable {
public static final String COMMAND_NAME = "state-test";
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"})
@Option(
names = {"--fork"},
description = "Force the state tests to run on a specific fork.")
private String fork = null;
@ParentCommand private EvmToolCommand parentCommand;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection") // picocli does it magically
@ -77,15 +84,6 @@ public class StateTestSubCommand implements Runnable {
private final ObjectMapper objectMapper = new ObjectMapper();
private static final ReferenceTestProtocolSchedules REFERENCE_TEST_PROTOCOL_SCHEDULES;
static {
Configurator.setLevel(
"org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder", Level.OFF);
REFERENCE_TEST_PROTOCOL_SCHEDULES = ReferenceTestProtocolSchedules.create();
Configurator.setLevel("org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder", null);
}
@Override
public void run() {
final ObjectMapper objectMapper = new ObjectMapper();
@ -127,6 +125,11 @@ public class StateTestSubCommand implements Runnable {
}
private void traceTestSpecs(final String test, final List<GeneralStateTestCaseEipSpec> specs) {
Configurator.setLevel(
"org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder", Level.OFF);
var referenceTestProtocolSchedules = ReferenceTestProtocolSchedules.create();
Configurator.setLevel("org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder", null);
final OperationTracer tracer = // You should have picked Mercy.
parentCommand.showJsonResults
? new StandardJsonTracer(System.out, !parentCommand.noMemory)
@ -147,7 +150,11 @@ public class StateTestSubCommand implements Runnable {
return;
}
final TransactionProcessor processor = transactionProcessor(spec.getFork());
final TransactionProcessor processor =
referenceTestProtocolSchedules
.getByName(fork == null ? spec.getFork() : fork)
.getByBlockNumber(0)
.getTransactionProcessor();
final WorldUpdater worldStateUpdater = worldState.updater();
final ReferenceTestBlockchain blockchain =
new ReferenceTestBlockchain(blockHeader.getNumber());
@ -196,11 +203,4 @@ public class StateTestSubCommand implements Runnable {
System.out.println(summaryLine);
}
}
private static TransactionProcessor transactionProcessor(final String name) {
return REFERENCE_TEST_PROTOCOL_SCHEDULES
.getByName(name)
.getByBlockNumber(0)
.getTransactionProcessor();
}
}

@ -0,0 +1,57 @@
# Case 1 - https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a#case-1
#
# This checks EXT(codehash,codesize,balance) of precompiles, which should be
# 100, and later checks the same operations twice against some non-precompiles.
# Those are cheaper second time they are accessed. Lastly, it checks the BALANCE
# of origin and this.
../../../build/install/evmtool/bin/evm \
--Xberlin-enabled=true \
--code=0x60013f5060023b506003315060f13f5060f23b5060f3315060f23f5060f33b5060f1315032315030315000 \
--sender=0x0000000000000000000000000000000000000000 \
--receiver=0x000000000000000000000000636F6E7472616374 \
--chain=YOLO_V2 \
--gas=9223372036854775807 \
--repeat=10
echo 'expect gasUser="0x21cd" (8653 dec)'
# Case 2 - https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a#case-2
#
# This checks extcodecopy( 0xff,0,0,0,0) twice, (should be expensive first
# time), and then does extcodecopy( this,0,0,0,0)
../../../build/install/evmtool/bin/evm \
--Xberlin-enabled=true \
--code=0x60006000600060ff3c60006000600060ff3c600060006000303c00 \
--sender=0x0000000000000000000000000000000000000000 \
--receiver=0x000000000000000000000000636F6E7472616374 \
--chain=YOLO_V2 \
--gas=9223372036854775807 \
--repeat=10
echo 'expect gasUser="0xb13" (2835 dec)'
# Case 3 - https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a#case-3
#
# This checks sload( 0x1) followed by sstore(loc: 0x01, val:0x11), then 'naked'
# sstore:sstore(loc: 0x02, val:0x11) twice, and sload(0x2), sload(0x1).
../../../build/install/evmtool/bin/evm \
--Xberlin-enabled=true \
--code=0x60015450601160015560116002556011600255600254600154 \
--sender=0x0000000000000000000000000000000000000000 \
--receiver=0x000000000000000000000000636F6E7472616374 \
--chain=YOLO_V2 \
--gas=9223372036854775807 \
--repeat=10
echo 'expect gasUser="0xadf1" (44529 dec)'
# Case 4 - https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a#case-4
#
# This calls the identity-precompile (cheap), then calls an account (expensive)
# and staticcalls the same account (cheap)
../../../build/install/evmtool/bin/evm \
--Xberlin-enabled=true \
--code=0x60008080808060046000f15060008080808060ff6000f15060008080808060ff6000fa50 \
--sender=0x0000000000000000000000000000000000000000 \
--receiver=0x000000000000000000000000636F6E7472616374 \
--chain=YOLO_V2 \
--gas=9223372036854775807 \
--repeat=10
echo 'expect gasUser="0xb35" (2869 dec)'

@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.Transaction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -53,7 +53,8 @@ public class GeneralStateTestCaseSpec {
final StateTestVersionedTransaction versionedTransaction) {
initialWorldState.persist();
final Map<String, List<GeneralStateTestCaseEipSpec>> res = new HashMap<>(postSections.size());
final Map<String, List<GeneralStateTestCaseEipSpec>> res =
new LinkedHashMap<>(postSections.size());
for (final Map.Entry<String, List<PostSection>> entry : postSections.entrySet()) {
final String eip = entry.getKey();
final List<PostSection> post = entry.getValue();

@ -208,7 +208,7 @@ public class RetestethContext {
genesisBlock,
new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHeaderFunctions),
new NoOpMetricsSystem(),
0);
100);
}
public ProtocolSchedule getProtocolSchedule() {

Loading…
Cancel
Save