diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java index 0897617c83..5d1fad698f 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java @@ -113,7 +113,13 @@ public class Address extends DelegatingBytes { "An account address must be %s bytes long, got %s", SIZE, value.size()); - return new Address(value); + if (value instanceof Address address) { + return address; + } else if (value instanceof DelegatingBytes delegatingBytes) { + return new Address(delegatingBytes.copy()); + } else { + return new Address(value); + } } /** diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java index 0e2daf96eb..f910de3197 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java @@ -59,6 +59,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.NavigableMap; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import com.google.common.base.Joiner; @@ -134,6 +135,12 @@ public class EvmToolCommand implements Runnable { description = "Receiving address for this invocation.") private final Address receiver = Address.fromHexString("0x00"); + @Option( + names = {"--coinbase"}, + paramLabel = "
", + description = "Coinbase for this invocation.") + private final Address coinbase = Address.fromHexString("0x00"); + @Option( names = {"--input"}, paramLabel = "",
@@ -317,7 +324,7 @@ public class EvmToolCommand implements Runnable {
final BlockHeader blockHeader =
BlockHeaderBuilder.create()
.parentHash(Hash.EMPTY)
- .coinbase(Address.ZERO)
+ .coinbase(coinbase)
.difficulty(Difficulty.ONE)
.number(1)
.gasLimit(5000)
@@ -399,6 +406,10 @@ public class EvmToolCommand implements Runnable {
.completer(c -> {})
.miningBeneficiary(blockHeader.getCoinbase())
.blockHashLookup(new CachingBlockHashLookup(blockHeader, component.getBlockchain()))
+ .accessListWarmAddresses(
+ EvmSpecVersion.SHANGHAI.compareTo(evm.getEvmVersion()) <= 0
+ ? Set.of(coinbase)
+ : Set.of())
.build();
Deque messageFrameStack = initialMessageFrame.getMessageFrameStack();
diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/coinbase-cold.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/coinbase-cold.json
new file mode 100644
index 0000000000..406c2684e2
--- /dev/null
+++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/coinbase-cold.json
@@ -0,0 +1,57 @@
+{
+ "cli": [
+ "--notime",
+ "--json",
+ "--code",
+ "4131ff",
+ "--coinbase",
+ "4444588443C3A91288C5002483449ABA1054192B",
+ "--fork",
+ "paris"
+ ],
+ "stdin": "",
+ "stdout": [
+ {
+ "pc": 0,
+ "op": 65,
+ "gas": "0x2540b91f8",
+ "gasCost": "0x2",
+ "memSize": 0,
+ "stack": [],
+ "depth": 1,
+ "refund": 0,
+ "opName": "COINBASE"
+ },
+ {
+ "pc": 1,
+ "op": 49,
+ "gas": "0x2540b91f6",
+ "gasCost": "0xa28",
+ "memSize": 0,
+ "stack": [
+ "0x4444588443c3a91288c5002483449aba1054192b"
+ ],
+ "depth": 1,
+ "refund": 0,
+ "opName": "BALANCE"
+ },
+ {
+ "pc": 2,
+ "op": 255,
+ "gas": "0x2540b87ce",
+ "gasCost": "0x1388",
+ "memSize": 0,
+ "stack": [
+ "0x0"
+ ],
+ "depth": 1,
+ "refund": 0,
+ "opName": "SELFDESTRUCT"
+ },
+ {
+ "gasUser": "0x1db2",
+ "gasTotal": "0x1db2",
+ "output": "0x"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/coinbase-warm.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/coinbase-warm.json
new file mode 100644
index 0000000000..9140a0268c
--- /dev/null
+++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/coinbase-warm.json
@@ -0,0 +1,57 @@
+{
+ "cli": [
+ "--notime",
+ "--json",
+ "--code",
+ "4131ff",
+ "--coinbase",
+ "4444588443C3A91288C5002483449ABA1054192B",
+ "--fork",
+ "shanghai"
+ ],
+ "stdin": "",
+ "stdout": [
+ {
+ "pc": 0,
+ "op": 65,
+ "gas": "0x2540b91f8",
+ "gasCost": "0x2",
+ "memSize": 0,
+ "stack": [],
+ "depth": 1,
+ "refund": 0,
+ "opName": "COINBASE"
+ },
+ {
+ "pc": 1,
+ "op": 49,
+ "gas": "0x2540b91f6",
+ "gasCost": "0x64",
+ "memSize": 0,
+ "stack": [
+ "0x4444588443c3a91288c5002483449aba1054192b"
+ ],
+ "depth": 1,
+ "refund": 0,
+ "opName": "BALANCE"
+ },
+ {
+ "pc": 2,
+ "op": 255,
+ "gas": "0x2540b9192",
+ "gasCost": "0x1388",
+ "memSize": 0,
+ "stack": [
+ "0x0"
+ ],
+ "depth": 1,
+ "refund": 0,
+ "opName": "SELFDESTRUCT"
+ },
+ {
+ "gasUser": "0x13ee",
+ "gasTotal": "0x13ee",
+ "output": "0x"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/EVM.java b/evm/src/main/java/org/hyperledger/besu/evm/EVM.java
index 3f5d706d41..f31cec13f0 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/EVM.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/EVM.java
@@ -31,6 +31,7 @@ import org.hyperledger.besu.evm.operation.AddModOperation;
import org.hyperledger.besu.evm.operation.AddOperation;
import org.hyperledger.besu.evm.operation.AndOperation;
import org.hyperledger.besu.evm.operation.ByteOperation;
+import org.hyperledger.besu.evm.operation.ChainIdOperation;
import org.hyperledger.besu.evm.operation.DivOperation;
import org.hyperledger.besu.evm.operation.DupOperation;
import org.hyperledger.besu.evm.operation.ExpOperation;
@@ -130,6 +131,30 @@ public class EVM {
return evmSpecVersion.maxEofVersion;
}
+ /**
+ * Returns the configured EVM spec version for this EVM
+ *
+ * @return the evm spec version
+ */
+ public EvmSpecVersion getEvmVersion() {
+ return evmSpecVersion;
+ }
+
+ /**
+ * Return the ChainId this Executor is using, or empty if the EVM version does not expose chain
+ * ID.
+ *
+ * @return the ChainId, or empty if not exposed.
+ */
+ public Optional getChainId() {
+ Operation op = operations.get(ChainIdOperation.OPCODE);
+ if (op instanceof ChainIdOperation chainIdOperation) {
+ return Optional.of(chainIdOperation.getChainId());
+ } else {
+ return Optional.empty();
+ }
+ }
+
/**
* Run to halt.
*
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java b/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java
index bd53ba11d2..88b886bb21 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java
@@ -15,6 +15,9 @@
*/
package org.hyperledger.besu.evm;
+import java.util.Comparator;
+import java.util.stream.Stream;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -24,6 +27,10 @@ public enum EvmSpecVersion {
FRONTIER(0, true, "Frontier", "Finalized"),
/** Homestead evm spec version. */
HOMESTEAD(0, true, "Homestead", "Finalized"),
+ /** Tangerine Whistle evm spec version. */
+ TANGERINE_WHISTLE(0, true, "Tangerine Whistle", "Finalized"),
+ /** Spurious Dragon evm spec version. */
+ SPURIOUS_DRAGON(0, true, "Spuruous Dragon", "Finalized"),
/** Byzantium evm spec version. */
BYZANTIUM(0, true, "Byzantium", "Finalized"),
/** Constantinople evm spec version. */
@@ -47,7 +54,7 @@ public enum EvmSpecVersion {
/** Osaka evm spec version. */
OSAKA(0, false, "Osaka", "Placeholder"),
/** Bogota evm spec version. */
- BOGOTA(0, false, "Bogata", "Placeholder"),
+ BOGOTA(0, false, "Bogota", "Placeholder"),
/** Development fork for unscheduled EIPs */
FUTURE_EIPS(1, false, "Future_EIPs", "Development, for accepted and unscheduled EIPs"),
/** Development fork for EIPs not accepted to Mainnet */
@@ -134,7 +141,7 @@ public enum EvmSpecVersion {
/**
* Calculate a spec version from a text fork name.
*
- * @param name The name of the fork, such as "shahghai" or "berlin"
+ * @param name The name of the fork, such as "shanghai" or "berlin"
* @return the EVM spec version for that fork, or null if no fork matched.
*/
public static EvmSpecVersion fromName(final String name) {
@@ -145,4 +152,17 @@ public enum EvmSpecVersion {
}
return null;
}
+
+ /**
+ * The most recent deployed evm supported by the library. This will change across versions and
+ * will be updated after mainnet activations.
+ *
+ * @return the most recently activated mainnet spec.
+ */
+ public static EvmSpecVersion mostRecent() {
+ return Stream.of(EvmSpecVersion.values())
+ .filter(v -> v.specFinalized)
+ .max(Comparator.naturalOrder())
+ .orElseThrow();
+ }
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
index 7884816ecf..0d9fa18b59 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
@@ -20,6 +20,7 @@ import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
+import org.hyperledger.besu.evm.gascalculator.HomesteadGasCalculator;
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator;
import org.hyperledger.besu.evm.gascalculator.PetersburgGasCalculator;
@@ -278,7 +279,7 @@ public class MainnetEVMs {
* @return the evm
*/
public static EVM homestead(final EvmConfiguration evmConfiguration) {
- return homestead(new FrontierGasCalculator(), evmConfiguration);
+ return homestead(new HomesteadGasCalculator(), evmConfiguration);
}
/**
@@ -328,7 +329,12 @@ public class MainnetEVMs {
* @return the evm
*/
public static EVM spuriousDragon(final EvmConfiguration evmConfiguration) {
- return homestead(new SpuriousDragonGasCalculator(), evmConfiguration);
+ GasCalculator gasCalculator = new SpuriousDragonGasCalculator();
+ return new EVM(
+ homesteadOperations(gasCalculator),
+ gasCalculator,
+ evmConfiguration,
+ EvmSpecVersion.SPURIOUS_DRAGON);
}
/**
@@ -338,7 +344,12 @@ public class MainnetEVMs {
* @return the evm
*/
public static EVM tangerineWhistle(final EvmConfiguration evmConfiguration) {
- return homestead(new TangerineWhistleGasCalculator(), evmConfiguration);
+ GasCalculator gasCalculator = new TangerineWhistleGasCalculator();
+ return new EVM(
+ homesteadOperations(gasCalculator),
+ gasCalculator,
+ evmConfiguration,
+ EvmSpecVersion.TANGERINE_WHISTLE);
}
/**
@@ -413,11 +424,16 @@ public class MainnetEVMs {
*/
public static EVM constantinople(
final GasCalculator gasCalculator, final EvmConfiguration evmConfiguration) {
+ var version = EvmSpecVersion.CONSTANTINOPLE;
+ return constantiNOPEl(gasCalculator, evmConfiguration, version);
+ }
+
+ private static EVM constantiNOPEl(
+ final GasCalculator gasCalculator,
+ final EvmConfiguration evmConfiguration,
+ final EvmSpecVersion version) {
return new EVM(
- constantinopleOperations(gasCalculator),
- gasCalculator,
- evmConfiguration,
- EvmSpecVersion.CONSTANTINOPLE);
+ constantinopleOperations(gasCalculator), gasCalculator, evmConfiguration, version);
}
/**
@@ -455,7 +471,8 @@ public class MainnetEVMs {
* @return the evm
*/
public static EVM petersburg(final EvmConfiguration evmConfiguration) {
- return constantinople(new PetersburgGasCalculator(), evmConfiguration);
+ return constantiNOPEl(
+ new PetersburgGasCalculator(), evmConfiguration, EvmSpecVersion.PETERSBURG);
}
/**
@@ -1145,7 +1162,7 @@ public class MainnetEVMs {
* @return the evm
*/
public static EVM experimentalEips(final EvmConfiguration evmConfiguration) {
- return futureEips(DEV_NET_CHAIN_ID, evmConfiguration);
+ return experimentalEips(DEV_NET_CHAIN_ID, evmConfiguration);
}
/**
@@ -1157,7 +1174,7 @@ public class MainnetEVMs {
*/
public static EVM experimentalEips(
final BigInteger chainId, final EvmConfiguration evmConfiguration) {
- return futureEips(chainId, evmConfiguration);
+ return experimentalEips(new CancunGasCalculator(), chainId, evmConfiguration);
}
/**
@@ -1176,7 +1193,7 @@ public class MainnetEVMs {
experimentalEipsOperations(gasCalculator, chainId),
gasCalculator,
evmConfiguration,
- EvmSpecVersion.FUTURE_EIPS);
+ EvmSpecVersion.EXPERIMENTAL_EIPS);
}
/**
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java
index 9921f56e64..d046c64778 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java
@@ -18,9 +18,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
+import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
+import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.code.CodeV0;
import org.hyperledger.besu.evm.contractvalidation.ContractValidationRule;
@@ -36,14 +38,19 @@ import org.hyperledger.besu.evm.processor.MessageCallProcessor;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
+import java.math.BigInteger;
import java.util.Collection;
import java.util.Deque;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
+import java.util.function.Function;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
+import com.google.errorprone.annotations.InlineMe;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
@@ -57,22 +64,27 @@ public class EVMExecutor {
private long gas = Long.MAX_VALUE;
private Address receiver = Address.ZERO;
private Address sender = Address.ZERO;
+ private Address contract = Address.ZERO;
+ private Address coinbase = Address.ZERO;
private Wei gasPriceGWei = Wei.ZERO;
private Wei blobGasPrice = Wei.ZERO;
private Bytes callData = Bytes.EMPTY;
private Wei ethValue = Wei.ZERO;
private Code code = CodeV0.EMPTY_CODE;
private BlockValues blockValues = new SimpleBlockValues();
+ private Function blockHashLookup = h -> null;
+ private Optional> versionedHashes = Optional.empty();
private OperationTracer tracer = OperationTracer.NO_TRACING;
private boolean requireDeposit = true;
private List contractValidationRules =
List.of(MaxCodeSizeRule.of(0x6000), PrefixCodeRule.of());
- private long initialNonce = 0;
+ private long initialNonce = 1;
private Collection forceCommitAddresses = List.of(Address.fromHexString("0x03"));
- private Set accessListWarmAddresses = Set.of();
+ private Set accessListWarmAddresses = new HashSet<>();
private Multimap accessListWarmStorage = HashMultimap.create();
private MessageCallProcessor messageCallProcessor = null;
private ContractCreationProcessor contractCreationProcessor = null;
+ private MessageFrame.Type messageFrameType = MessageFrame.Type.MESSAGE_CALL;
private EVMExecutor(final EVM evm) {
checkNotNull(evm, "evm must not be null");
@@ -80,7 +92,84 @@ public class EVMExecutor {
}
/**
- * Instandiate Evm executor.
+ * Create an EVM with the most current activated fork on chain ID 1.
+ *
+ * Note, this will change across versions
+ *
+ * @return executor builder
+ */
+ public static EVMExecutor evm() {
+ return evm(EvmSpecVersion.mostRecent());
+ }
+
+ /**
+ * Create an EVM at the specified version with chain ID 1.
+ *
+ * @param fork the EVM spec version to use
+ * @return executor builder
+ */
+ public static EVMExecutor evm(final EvmSpecVersion fork) {
+ return evm(fork, BigInteger.ONE);
+ }
+
+ /**
+ * Create an EVM at the specified version and chain ID
+ *
+ * @param fork the EVM spec version to use
+ * @param chainId the chain ID to use
+ * @return executor builder
+ */
+ public static EVMExecutor evm(final EvmSpecVersion fork, final BigInteger chainId) {
+ return evm(fork, chainId, EvmConfiguration.DEFAULT);
+ }
+
+ /**
+ * Create an EVM at the specified version and chain ID
+ *
+ * @param fork the EVM spec version to use
+ * @param chainId the chain ID to use
+ * @return executor builder
+ */
+ public static EVMExecutor evm(final EvmSpecVersion fork, final Bytes chainId) {
+ return evm(fork, new BigInteger(1, chainId.toArrayUnsafe()), EvmConfiguration.DEFAULT);
+ }
+
+ /**
+ * Create an EVM at the specified version and chain ID
+ *
+ * @param fork the EVM spec version to use
+ * @param chainId the chain ID to use
+ * @param evmConfiguration system configuration options.
+ * @return executor builder
+ */
+ public static EVMExecutor evm(
+ final EvmSpecVersion fork,
+ final BigInteger chainId,
+ final EvmConfiguration evmConfiguration) {
+ return switch (fork) {
+ case FRONTIER -> frontier(evmConfiguration);
+ case HOMESTEAD -> homestead(evmConfiguration);
+ case TANGERINE_WHISTLE -> tangerineWhistle(evmConfiguration);
+ case SPURIOUS_DRAGON -> spuriousDragon(evmConfiguration);
+ case BYZANTIUM -> byzantium(evmConfiguration);
+ case CONSTANTINOPLE -> constantinople(evmConfiguration);
+ case PETERSBURG -> petersburg(evmConfiguration);
+ case ISTANBUL -> istanbul(chainId, evmConfiguration);
+ case BERLIN -> berlin(chainId, evmConfiguration);
+ case LONDON -> london(chainId, evmConfiguration);
+ case PARIS -> paris(chainId, evmConfiguration);
+ case SHANGHAI -> shanghai(chainId, evmConfiguration);
+ case CANCUN -> cancun(chainId, evmConfiguration);
+ case PRAGUE -> prague(chainId, evmConfiguration);
+ case OSAKA -> osaka(chainId, evmConfiguration);
+ case BOGOTA -> bogota(chainId, evmConfiguration);
+ case FUTURE_EIPS -> futureEips(chainId, evmConfiguration);
+ case EXPERIMENTAL_EIPS -> experimentalEips(chainId, evmConfiguration);
+ };
+ }
+
+ /**
+ * Instantiate Evm executor.
*
* @param evm the evm
* @return the evm executor
@@ -102,6 +191,7 @@ public class EVMExecutor {
executor.contractValidationRules = List.of();
executor.requireDeposit = false;
executor.forceCommitAddresses = List.of();
+ executor.initialNonce = 0;
return executor;
}
@@ -117,31 +207,33 @@ public class EVMExecutor {
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of();
executor.forceCommitAddresses = List.of();
+ executor.initialNonce = 0;
return executor;
}
/**
- * Instantiate Spurious dragon evm executor.
+ * Instantiate Tangerine whistle evm executor.
*
* @param evmConfiguration the evm configuration
* @return the evm executor
*/
- public static EVMExecutor spuriousDragon(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.spuriousDragon(evmConfiguration));
+ public static EVMExecutor tangerineWhistle(final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.tangerineWhistle(evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
+ executor.initialNonce = 0;
return executor;
}
/**
- * Instantiate Tangerine whistle evm executor.
+ * Instantiate Spurious dragon evm executor.
*
* @param evmConfiguration the evm configuration
* @return the evm executor
*/
- public static EVMExecutor tangerineWhistle(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.tangerineWhistle(evmConfiguration));
+ public static EVMExecutor spuriousDragon(final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.spuriousDragon(evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@@ -195,9 +287,30 @@ public class EVMExecutor {
*
* @param evmConfiguration the evm configuration
* @return the evm executor
+ * @deprecated Migrate to use {@link EVMExecutor#evm(EvmSpecVersion)}.
*/
+ @InlineMe(
+ replacement = "EVMExecutor.evm(EvmSpecVersion.ISTANBUL, BigInteger.ONE, evmConfiguration)",
+ imports = {
+ "java.math.BigInteger",
+ "org.hyperledger.besu.evm.EvmSpecVersion",
+ "org.hyperledger.besu.evm.fluent.EVMExecutor"
+ })
+ @Deprecated(forRemoval = true)
public static EVMExecutor istanbul(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.istanbul(evmConfiguration));
+ return evm(EvmSpecVersion.ISTANBUL, BigInteger.ONE, evmConfiguration);
+ }
+
+ /**
+ * Instantiate Istanbul evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor istanbul(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.istanbul(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@@ -209,9 +322,30 @@ public class EVMExecutor {
*
* @param evmConfiguration the evm configuration
* @return the evm executor
+ * @deprecated Migrate to use {@link EVMExecutor#evm(EvmSpecVersion)}.
*/
+ @InlineMe(
+ replacement = "EVMExecutor.evm(EvmSpecVersion.BERLIN, BigInteger.ONE, evmConfiguration)",
+ imports = {
+ "java.math.BigInteger",
+ "org.hyperledger.besu.evm.EvmSpecVersion",
+ "org.hyperledger.besu.evm.fluent.EVMExecutor"
+ })
+ @Deprecated(forRemoval = true)
public static EVMExecutor berlin(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.berlin(evmConfiguration));
+ return evm(EvmSpecVersion.BERLIN, BigInteger.ONE, evmConfiguration);
+ }
+
+ /**
+ * Instantiate berlin evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor berlin(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.berlin(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
@@ -223,9 +357,30 @@ public class EVMExecutor {
*
* @param evmConfiguration the evm configuration
* @return the evm executor
+ * @deprecated Migrate to use {@link EVMExecutor#evm(EvmSpecVersion)}.
*/
+ @InlineMe(
+ replacement = "EVMExecutor.evm(EvmSpecVersion.LONDON, BigInteger.ONE, evmConfiguration)",
+ imports = {
+ "java.math.BigInteger",
+ "org.hyperledger.besu.evm.EvmSpecVersion",
+ "org.hyperledger.besu.evm.fluent.EVMExecutor"
+ })
+ @Deprecated(forRemoval = true)
public static EVMExecutor london(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.london(evmConfiguration));
+ return evm(EvmSpecVersion.LONDON, BigInteger.ONE, evmConfiguration);
+ }
+
+ /**
+ * Instantiate London evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor london(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.london(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
return executor;
@@ -236,9 +391,30 @@ public class EVMExecutor {
*
* @param evmConfiguration the evm configuration
* @return the evm executor
+ * @deprecated Migrate to use {@link EVMExecutor#evm(EvmSpecVersion)}.
*/
+ @InlineMe(
+ replacement = "EVMExecutor.evm(EvmSpecVersion.PARIS, BigInteger.ONE, evmConfiguration)",
+ imports = {
+ "java.math.BigInteger",
+ "org.hyperledger.besu.evm.EvmSpecVersion",
+ "org.hyperledger.besu.evm.fluent.EVMExecutor"
+ })
+ @Deprecated(forRemoval = true)
public static EVMExecutor paris(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.paris(evmConfiguration));
+ return evm(EvmSpecVersion.PARIS, BigInteger.ONE, evmConfiguration);
+ }
+
+ /**
+ * Instantiate Paris evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor paris(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.paris(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
return executor;
@@ -249,9 +425,30 @@ public class EVMExecutor {
*
* @param evmConfiguration the evm configuration
* @return the evm executor
+ * @deprecated Migrate to use {@link EVMExecutor#evm(EvmSpecVersion)}.
*/
+ @InlineMe(
+ replacement = "EVMExecutor.evm(EvmSpecVersion.SHANGHAI, BigInteger.ONE, evmConfiguration)",
+ imports = {
+ "java.math.BigInteger",
+ "org.hyperledger.besu.evm.EvmSpecVersion",
+ "org.hyperledger.besu.evm.fluent.EVMExecutor"
+ })
+ @Deprecated(forRemoval = true)
public static EVMExecutor shanghai(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.shanghai(evmConfiguration));
+ return evm(EvmSpecVersion.SHANGHAI, BigInteger.ONE, evmConfiguration);
+ }
+
+ /**
+ * Instantiate Shanghai evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor shanghai(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.shanghai(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
return executor;
@@ -262,22 +459,125 @@ public class EVMExecutor {
*
* @param evmConfiguration the evm configuration
* @return the evm executor
+ * @deprecated Migrate to use {@link EVMExecutor#evm(EvmSpecVersion)}.
*/
+ @InlineMe(
+ replacement = "EVMExecutor.evm(EvmSpecVersion.CANCUN, BigInteger.ONE, evmConfiguration)",
+ imports = {
+ "java.math.BigInteger",
+ "org.hyperledger.besu.evm.EvmSpecVersion",
+ "org.hyperledger.besu.evm.fluent.EVMExecutor"
+ })
+ @Deprecated(forRemoval = true)
public static EVMExecutor cancun(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.cancun(evmConfiguration));
+ return evm(EvmSpecVersion.CANCUN, BigInteger.ONE, evmConfiguration);
+ }
+
+ /**
+ * Instantiate Cancun evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor cancun(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.cancun(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.cancun(executor.evm.getGasCalculator());
return executor;
}
+ /**
+ * Instantiate Prague evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor prague(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.prague(chainId, evmConfiguration));
+ executor.precompileContractRegistry =
+ MainnetPrecompiledContracts.cancun(executor.evm.getGasCalculator());
+ return executor;
+ }
+
+ /**
+ * Instantiate Osaka evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor osaka(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.osaka(chainId, evmConfiguration));
+ executor.precompileContractRegistry =
+ MainnetPrecompiledContracts.cancun(executor.evm.getGasCalculator());
+ return executor;
+ }
+
+ /**
+ * Instantiate Bogota evm executor.
+ *
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor bogota(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.bogota(chainId, evmConfiguration));
+ executor.precompileContractRegistry =
+ MainnetPrecompiledContracts.cancun(executor.evm.getGasCalculator());
+ return executor;
+ }
+
+ /**
+ * Instantiate Future EIPs evm executor.
+ *
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ * @deprecated Migrate to use {@link EVMExecutor#evm(EvmSpecVersion)}.
+ */
+ @InlineMe(
+ replacement = "EVMExecutor.evm(EvmSpecVersion.FUTURE_EIPS, BigInteger.ONE, evmConfiguration)",
+ imports = {
+ "java.math.BigInteger",
+ "org.hyperledger.besu.evm.EvmSpecVersion",
+ "org.hyperledger.besu.evm.fluent.EVMExecutor"
+ })
+ @Deprecated(forRemoval = true)
+ public static EVMExecutor futureEips(final EvmConfiguration evmConfiguration) {
+ return evm(EvmSpecVersion.FUTURE_EIPS, BigInteger.ONE, evmConfiguration);
+ }
+
/**
* Instantiate Future EIPs evm executor.
*
+ * @param chainId the chain ID
+ * @param evmConfiguration the evm configuration
+ * @return the evm executor
+ */
+ public static EVMExecutor futureEips(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor = new EVMExecutor(MainnetEVMs.futureEips(chainId, evmConfiguration));
+ executor.precompileContractRegistry =
+ MainnetPrecompiledContracts.futureEIPs(executor.evm.getGasCalculator());
+ return executor;
+ }
+
+ /**
+ * Instantiate Experimental EIPs evm executor.
+ *
+ * @param chainId the chain ID
* @param evmConfiguration the evm configuration
* @return the evm executor
*/
- public static EVMExecutor futureEIPs(final EvmConfiguration evmConfiguration) {
- final EVMExecutor executor = new EVMExecutor(MainnetEVMs.cancun(evmConfiguration));
+ public static EVMExecutor experimentalEips(
+ final BigInteger chainId, final EvmConfiguration evmConfiguration) {
+ final EVMExecutor executor =
+ new EVMExecutor(MainnetEVMs.experimentalEips(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.futureEIPs(executor.evm.getGasCalculator());
return executor;
@@ -347,10 +647,10 @@ public class EVMExecutor {
final ContractCreationProcessor ccp = thisContractCreationProcessor();
final MessageFrame initialMessageFrame =
MessageFrame.builder()
- .type(MessageFrame.Type.MESSAGE_CALL)
+ .type(messageFrameType)
.worldUpdater(worldUpdater.updater())
.initialGas(gas)
- .contract(Address.ZERO)
+ .contract(contract)
.address(receiver)
.originator(sender)
.sender(sender)
@@ -361,11 +661,12 @@ public class EVMExecutor {
.apparentValue(ethValue)
.code(code)
.blockValues(blockValues)
- .completer(c -> {})
- .miningBeneficiary(Address.ZERO)
- .blockHashLookup(h -> null)
+ .miningBeneficiary(coinbase)
+ .blockHashLookup(blockHashLookup)
.accessListWarmAddresses(accessListWarmAddresses)
.accessListWarmStorage(accessListWarmStorage)
+ .versionedHashes(versionedHashes)
+ .completer(c -> {})
.build();
final Deque messageFrameStack = initialMessageFrame.getMessageFrameStack();
@@ -389,8 +690,7 @@ public class EVMExecutor {
* @return the evm executor
*/
public EVMExecutor commitWorldState() {
- this.commitWorldState = true;
- return this;
+ return commitWorldState(true);
}
/**
@@ -448,6 +748,32 @@ public class EVMExecutor {
return this;
}
+ /**
+ * Sets the address of the executing contract
+ *
+ * @param contract the contract
+ * @return the evm executor
+ */
+ public EVMExecutor contract(final Address contract) {
+ this.contract = contract;
+ return this;
+ }
+
+ /**
+ * Sets the address of the coinbase aka mining beneficiary
+ *
+ * @param coinbase the coinbase
+ * @return the evm executor
+ */
+ public EVMExecutor coinbase(final Address coinbase) {
+ this.coinbase = coinbase;
+ // EIP-3651
+ if (EvmSpecVersion.SHANGHAI.compareTo(evm.getEvmVersion()) <= 0) {
+ this.warmAddress(coinbase);
+ }
+ return this;
+ }
+
/**
* Sets Gas price GWei.
*
@@ -503,6 +829,16 @@ public class EVMExecutor {
return this;
}
+ /**
+ * Sets Code.
+ *
+ * @param codeBytes the code bytes
+ * @return the evm executor
+ */
+ public EVMExecutor code(final Bytes codeBytes) {
+ return code(codeBytes, Hash.hash(codeBytes));
+ }
+
/**
* Sets Code.
*
@@ -526,6 +862,131 @@ public class EVMExecutor {
return this;
}
+ /**
+ * Sets the difficulty bytes on a SimpleBlockValues object
+ *
+ * @param difficulty the difficulty
+ * @return the evm executor
+ * @throws ClassCastException if the blockValues was set with a value that is not a {@link
+ * SimpleBlockValues}
+ */
+ public EVMExecutor difficulty(final Bytes difficulty) {
+ ((SimpleBlockValues) this.blockValues).setDifficultyBytes(difficulty);
+ return this;
+ }
+
+ /**
+ * Sets the mix hash bytes on a SimpleBlockValues object
+ *
+ * @param mixHash the mix hash
+ * @return the evm executor
+ * @throws ClassCastException if the blockValues was set with a value that is not a {@link
+ * SimpleBlockValues}
+ */
+ public EVMExecutor mixHash(final Bytes32 mixHash) {
+ ((SimpleBlockValues) this.blockValues).setMixHashOrPrevRandao(mixHash);
+ return this;
+ }
+
+ /**
+ * Sets the prev randao bytes on a SimpleBlockValues object
+ *
+ * @param prevRandao the prev randao
+ * @return the evm executor
+ * @throws ClassCastException if the blockValues was set with a value that is not a {@link
+ * SimpleBlockValues}
+ */
+ public EVMExecutor prevRandao(final Bytes32 prevRandao) {
+ ((SimpleBlockValues) this.blockValues).setMixHashOrPrevRandao(prevRandao);
+ return this;
+ }
+
+ /**
+ * Sets the baseFee for the block, directly.
+ *
+ * @param baseFee the baseFee
+ * @return the evm executor
+ * @throws ClassCastException if the blockValues was set with a value that is not a {@link
+ * SimpleBlockValues}
+ */
+ public EVMExecutor baseFee(final Wei baseFee) {
+ return baseFee(Optional.ofNullable(baseFee));
+ }
+
+ /**
+ * Sets the baseFee for the block, as an Optional.
+ *
+ * @param baseFee the baseFee
+ * @return the evm executor
+ * @throws ClassCastException if the blockValues was set with a value that is not a {@link
+ * SimpleBlockValues}
+ */
+ public EVMExecutor baseFee(final Optional baseFee) {
+ ((SimpleBlockValues) this.blockValues).setBaseFee(baseFee);
+ return this;
+ }
+
+ /**
+ * Sets the block number for the block.
+ *
+ * @param number the block number
+ * @return the evm executor
+ * @throws ClassCastException if the blockValues was set with a value that is not a {@link
+ * SimpleBlockValues}
+ */
+ public EVMExecutor number(final long number) {
+ ((SimpleBlockValues) this.blockValues).setNumber(number);
+ return this;
+ }
+
+ /**
+ * Sets the timestamp for the block.
+ *
+ * @param timestamp the block timestamp
+ * @return the evm executor
+ * @throws ClassCastException if the blockValues was set with a value that is not a {@link
+ * SimpleBlockValues}
+ */
+ public EVMExecutor timestamp(final long timestamp) {
+ ((SimpleBlockValues) this.blockValues).setTimestamp(timestamp);
+ return this;
+ }
+
+ /**
+ * Sets the gas limit for the block.
+ *
+ * @param gasLimit the block gas limit
+ * @return the evm executor
+ * @throws ClassCastException if the blockValues was set with a value that is not a {@link
+ * SimpleBlockValues}
+ */
+ public EVMExecutor gasLimit(final long gasLimit) {
+ ((SimpleBlockValues) this.blockValues).setGasLimit(gasLimit);
+ return this;
+ }
+
+ /**
+ * Sets the block hash lookup function
+ *
+ * @param blockHashLookup the block hash lookup function
+ * @return the evm executor
+ */
+ public EVMExecutor blockHashLookup(final Function blockHashLookup) {
+ this.blockHashLookup = blockHashLookup;
+ return this;
+ }
+
+ /**
+ * Sets Version Hashes for blobs. The blobs themselves are not accessible.
+ *
+ * @param versionedHashes the versioned hashes
+ * @return the evm executor
+ */
+ public EVMExecutor versionedHashes(final Optional> versionedHashes) {
+ this.versionedHashes = versionedHashes;
+ return this;
+ }
+
/**
* Sets Operation Tracer.
*
@@ -664,4 +1125,33 @@ public class EVMExecutor {
this.contractCreationProcessor = contractCreationProcessor;
return this;
}
+
+ /**
+ * Sets the message frame type
+ *
+ * @param messageFrameType message frame type
+ * @return the builder
+ */
+ public EVMExecutor messageFrameType(final MessageFrame.Type messageFrameType) {
+ this.messageFrameType = messageFrameType;
+ return this;
+ }
+
+ /**
+ * Returns the EVM version this executor is using
+ *
+ * @return the current EVM version
+ */
+ public EvmSpecVersion getEVMVersion() {
+ return evm.getEvmVersion();
+ }
+
+ /**
+ * Returns the ChaindD this executor is using
+ *
+ * @return the current chain ID
+ */
+ public Optional getChainId() {
+ return evm.getChainId();
+ }
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java
index b8a4db21ea..05ad66574f 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleAccount.java
@@ -188,4 +188,21 @@ public class SimpleAccount implements MutableAccount {
public void becomeImmutable() {
mutable = false;
}
+
+ /**
+ * Push changes into the parent account, if one exists
+ *
+ * @return true if a parent account was updated, false if not (this indicates the account should
+ * be inserted into the parent contact).
+ */
+ public boolean updateParent() {
+ if (parent instanceof SimpleAccount simpleAccount) {
+ simpleAccount.balance = balance;
+ simpleAccount.nonce = nonce;
+ simpleAccount.storage.putAll(storage);
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleBlockValues.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleBlockValues.java
index f6c7c26a7d..8099e27bab 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleBlockValues.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleBlockValues.java
@@ -15,7 +15,105 @@
*/
package org.hyperledger.besu.evm.fluent;
+import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.frame.BlockValues;
+import java.util.Optional;
+
+import org.apache.tuweni.bytes.Bytes;
+import org.apache.tuweni.bytes.Bytes32;
+
/** A concrete BlockValues object that takes all the defaults */
-public class SimpleBlockValues implements BlockValues {}
+public class SimpleBlockValues implements BlockValues {
+
+ Bytes difficultyBytes = Bytes32.ZERO;
+ Bytes32 mixHashOrPrevRandao = Bytes32.ZERO;
+ Optional baseFee = Optional.empty();
+ long number = 1;
+ long timestamp = 1;
+ long gasLimit = Long.MAX_VALUE;
+
+ @Override
+ public Bytes getDifficultyBytes() {
+ return difficultyBytes;
+ }
+
+ /**
+ * Sets the difficulty of the block
+ *
+ * @param difficultyBytes the difficulty
+ */
+ public void setDifficultyBytes(final Bytes difficultyBytes) {
+ this.difficultyBytes = difficultyBytes;
+ }
+
+ @Override
+ public Bytes32 getMixHashOrPrevRandao() {
+ return mixHashOrPrevRandao;
+ }
+
+ /**
+ * sets the mix hash or prevRandao
+ *
+ * @param mixHashOrPrevRandao new mixHash or prevRandao
+ */
+ public void setMixHashOrPrevRandao(final Bytes32 mixHashOrPrevRandao) {
+ this.mixHashOrPrevRandao = mixHashOrPrevRandao;
+ }
+
+ @Override
+ public Optional getBaseFee() {
+ return baseFee;
+ }
+
+ /**
+ * Sets the base fee
+ *
+ * @param baseFee new base fee, or empty if not in a fee market fork.
+ */
+ public void setBaseFee(final Optional baseFee) {
+ this.baseFee = baseFee;
+ }
+
+ @Override
+ public long getNumber() {
+ return number;
+ }
+
+ /**
+ * Sets the block number
+ *
+ * @param number the block number
+ */
+ public void setNumber(final long number) {
+ this.number = number;
+ }
+
+ @Override
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ /**
+ * Sets the block timestamp
+ *
+ * @param timestamp the timestamp, in seconds past the unix epoch
+ */
+ public void setTimestamp(final long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ @Override
+ public long getGasLimit() {
+ return gasLimit;
+ }
+
+ /**
+ * Sets the gas limit
+ *
+ * @param gasLimit the gas limit for the block
+ */
+ public void setGasLimit(final long gasLimit) {
+ this.gasLimit = gasLimit;
+ }
+}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java
index 6bc19ca0da..a9295568a6 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java
@@ -66,6 +66,9 @@ public class SimpleWorld implements WorldUpdater {
@Override
public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) {
+ if (getAccount(address) != null) {
+ throw new IllegalStateException("Cannot create an account when one already exists");
+ }
SimpleAccount account = new SimpleAccount(address, nonce, balance);
accounts.put(address, account);
return account;
@@ -73,13 +76,23 @@ public class SimpleWorld implements WorldUpdater {
@Override
public MutableAccount getAccount(final Address address) {
- if (accounts.containsKey(address)) {
- return accounts.get(address);
- } else if (parent != null) {
- return parent.getAccount(address);
- } else {
- return null;
+ SimpleAccount account = accounts.get(address);
+ if (account != null) {
+ return account;
+ }
+ Account parentAccount = parent == null ? null : parent.getAccount(address);
+ if (parentAccount != null) {
+ account =
+ new SimpleAccount(
+ parentAccount,
+ parentAccount.getAddress(),
+ parentAccount.getNonce(),
+ parentAccount.getBalance(),
+ parentAccount.getCode());
+ accounts.put(address, account);
+ return account;
}
+ return null;
}
@Override
@@ -107,11 +120,16 @@ public class SimpleWorld implements WorldUpdater {
@Override
public void commit() {
- parent.accounts.putAll(accounts);
+ accounts.forEach(
+ (address, account) -> {
+ if (!account.updateParent()) {
+ parent.accounts.put(address, account);
+ }
+ });
}
@Override
public Optional parentUpdater() {
- return Optional.empty();
+ return Optional.ofNullable(parent);
}
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/BerlinGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/BerlinGasCalculator.java
index c15de3270f..50a035eb84 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/BerlinGasCalculator.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/BerlinGasCalculator.java
@@ -247,15 +247,26 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
BigIntegerModularExponentiationPrecompiledContract.modulusLength(input);
final long exponentOffset =
clampedAdd(BigIntegerModularExponentiationPrecompiledContract.BASE_OFFSET, baseLength);
+
+ long multiplicationComplexity = (Math.max(modulusLength, baseLength) + 7L) / 8L;
+ multiplicationComplexity =
+ Words.clampedMultiply(multiplicationComplexity, multiplicationComplexity);
+
+ if (multiplicationComplexity == 0) {
+ return 200;
+ } else if (multiplicationComplexity > 0) {
+ long maxExponentLength = Long.MAX_VALUE / multiplicationComplexity * 3 / 8;
+ if (exponentLength > maxExponentLength) {
+ return Long.MAX_VALUE;
+ }
+ }
+
final long firstExponentBytesCap =
Math.min(exponentLength, ByzantiumGasCalculator.MAX_FIRST_EXPONENT_BYTES);
final BigInteger firstExpBytes =
BigIntegerModularExponentiationPrecompiledContract.extractParameter(
input, clampedToInt(exponentOffset), clampedToInt(firstExponentBytesCap));
final long adjustedExponentLength = adjustedExponentLength(exponentLength, firstExpBytes);
- long multiplicationComplexity = (Math.max(modulusLength, baseLength) + 7L) / 8L;
- multiplicationComplexity =
- Words.clampedMultiply(multiplicationComplexity, multiplicationComplexity);
long gasRequirement =
clampedMultiply(multiplicationComplexity, Math.max(adjustedExponentLength, 1L));
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/ChainIdOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/ChainIdOperation.java
index 66918298fa..f807d74597 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/operation/ChainIdOperation.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/ChainIdOperation.java
@@ -18,11 +18,15 @@ import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
+import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
/** The Chain id operation. */
public class ChainIdOperation extends AbstractFixedCostOperation {
+ /** The CHAINID Opcode number */
+ public static final int OPCODE = 0x46;
+
private final Bytes32 chainId;
/**
@@ -32,10 +36,19 @@ public class ChainIdOperation extends AbstractFixedCostOperation {
* @param chainId the chain id
*/
public ChainIdOperation(final GasCalculator gasCalculator, final Bytes32 chainId) {
- super(0x46, "CHAINID", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
+ super(OPCODE, "CHAINID", 0, 1, gasCalculator, gasCalculator.getBaseTierGasCost());
this.chainId = chainId;
}
+ /**
+ * Returns the chain ID this operation uses
+ *
+ * @return then chainID;
+ */
+ public Bytes getChainId() {
+ return chainId;
+ }
+
@Override
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java
index 3f29fcea57..453dff9ce5 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/SelfDestructOperation.java
@@ -61,7 +61,8 @@ public class SelfDestructOperation extends AbstractOperation {
frame.warmUpAddress(beneficiaryAddress) || gasCalculator().isPrecompile(beneficiaryAddress);
final Address originatorAddress = frame.getRecipientAddress();
- final Wei originatorBalance = frame.getWorldUpdater().get(originatorAddress).getBalance();
+ final MutableAccount originatorAccount = frame.getWorldUpdater().getAccount(originatorAddress);
+ final Wei originatorBalance = originatorAccount.getBalance();
final long cost =
gasCalculator().selfDestructOperationGasCost(beneficiaryNullable, originatorBalance)
@@ -75,7 +76,6 @@ public class SelfDestructOperation extends AbstractOperation {
}
// We passed preliminary checks, get mutable accounts.
- final MutableAccount originatorAccount = frame.getWorldUpdater().getAccount(originatorAddress);
final MutableAccount beneficiaryAccount =
frame.getWorldUpdater().getOrCreate(beneficiaryAddress);
@@ -86,8 +86,8 @@ public class SelfDestructOperation extends AbstractOperation {
// If we are actually destroying the originator (pre-Cancun or same-tx-create) we need to
// explicitly zero out the account balance (destroying ether/value if the originator is the
// beneficiary) as well as tag it for later self-destruct cleanup.
- if (!eip6780Semantics || frame.wasCreatedInTransaction(originatorAddress)) {
- frame.addSelfDestruct(originatorAddress);
+ if (!eip6780Semantics || frame.wasCreatedInTransaction(originatorAccount.getAddress())) {
+ frame.addSelfDestruct(originatorAccount.getAddress());
originatorAccount.setBalance(Wei.ZERO);
}
diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java
index 0c100e3340..1963bba8a5 100644
--- a/evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java
+++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java
@@ -151,12 +151,6 @@ public class MessageCallProcessor extends AbstractMessageProcessor {
final OperationTracer operationTracer) {
final long gasRequirement = contract.gasRequirement(frame.getInputData());
if (frame.getRemainingGas() < gasRequirement) {
- LOG.trace(
- "Not enough gas available for pre-compiled contract code {}: requiring "
- + "{} but only {} gas available",
- contract,
- gasRequirement,
- frame.getRemainingGas());
frame.setExceptionalHaltReason(Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
frame.setState(MessageFrame.State.EXCEPTIONAL_HALT);
} else {
@@ -174,11 +168,6 @@ public class MessageCallProcessor extends AbstractMessageProcessor {
}
frame.setState(result.getState());
frame.setExceptionalHaltReason(result.getHaltReason());
- LOG.trace(
- "Precompiled contract {} {} (gasComsumed: {})",
- contract.getName(),
- result.getState(),
- result.isRefundGas() ? 0L : gasRequirement);
}
}
}
diff --git a/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java b/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java
index 9ba9ebf96a..9577298681 100644
--- a/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java
+++ b/evm/src/test/java/org/hyperledger/besu/evm/StandardJsonTracerTest.java
@@ -21,7 +21,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.fluent.EVMExecutor;
-import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.tracing.StandardJsonTracer;
import java.io.ByteArrayOutputStream;
@@ -37,7 +36,7 @@ class StandardJsonTracerTest {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream out = new PrintStream(baos);
- var executor = EVMExecutor.istanbul(EvmConfiguration.DEFAULT);
+ var executor = EVMExecutor.evm(EvmSpecVersion.ISTANBUL);
StandardJsonTracer tracer = new StandardJsonTracer(out, true, true, true, false);
executor.tracer(tracer);
executor.gas(10_000_000_000L);
@@ -82,7 +81,7 @@ class StandardJsonTracerTest {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream out = new PrintStream(baos);
- var executor = EVMExecutor.istanbul(EvmConfiguration.DEFAULT);
+ var executor = EVMExecutor.evm(EvmSpecVersion.ISTANBUL);
StandardJsonTracer tracer = new StandardJsonTracer(out, false, false, false, true);
executor.tracer(tracer);
executor.gas(10_000_000_000L);
diff --git a/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java
new file mode 100644
index 0000000000..176f007098
--- /dev/null
+++ b/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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 static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.hyperledger.besu.datatypes.Address;
+import org.hyperledger.besu.datatypes.Hash;
+import org.hyperledger.besu.datatypes.Wei;
+import org.hyperledger.besu.evm.EVM;
+import org.hyperledger.besu.evm.EvmSpecVersion;
+import org.hyperledger.besu.evm.code.CodeFactory;
+import org.hyperledger.besu.evm.frame.MessageFrame;
+import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator;
+import org.hyperledger.besu.evm.internal.EvmConfiguration;
+import org.hyperledger.besu.evm.operation.OperationRegistry;
+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.StandardJsonTracer;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import com.google.common.collect.MultimapBuilder;
+import org.apache.tuweni.bytes.Bytes;
+import org.apache.tuweni.bytes.Bytes32;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+class EVMExecutorTest {
+
+ @Test
+ void currentEVM() {
+ var subject = EVMExecutor.evm();
+ assertThat(subject.getEVMVersion()).isEqualTo(EvmSpecVersion.SHANGHAI);
+ }
+
+ @ParameterizedTest
+ @EnumSource(EvmSpecVersion.class)
+ void evmByRequest(final EvmSpecVersion version) {
+ var subject = EVMExecutor.evm(version);
+ assertThat(subject.getEVMVersion()).isEqualTo(version);
+ }
+
+ @ParameterizedTest
+ @EnumSource(EvmSpecVersion.class)
+ void evmWithChainIDByRequest(final EvmSpecVersion version) {
+ var subject = EVMExecutor.evm(version, BigInteger.TEN);
+ assertThat(subject.getEVMVersion()).isEqualTo(version);
+ if (EvmSpecVersion.ISTANBUL.compareTo(version) <= 0) {
+ assertThat(subject.getChainId()).map(Bytes::trimLeadingZeros).map(Bytes::toInt).contains(10);
+ } else {
+ assertThat(subject.getChainId()).isEmpty();
+ }
+ }
+
+ @ParameterizedTest
+ @EnumSource(EvmSpecVersion.class)
+ void evmWithChainIDByBytes(final EvmSpecVersion version) {
+ var subject = EVMExecutor.evm(version, Bytes.fromHexString("0xc4a1201d"));
+ assertThat(subject.getEVMVersion()).isEqualTo(version);
+ if (EvmSpecVersion.ISTANBUL.compareTo(version) <= 0) {
+ assertThat(subject.getChainId())
+ .map(Bytes::trimLeadingZeros)
+ .map(Bytes::toInt)
+ .contains(0xc4a1201d);
+ } else {
+ assertThat(subject.getChainId()).isEmpty();
+ }
+ }
+
+ @Test
+ void customEVM() {
+ var subject =
+ EVMExecutor.evm(
+ new EVM(
+ new OperationRegistry(),
+ new FrontierGasCalculator(),
+ EvmConfiguration.DEFAULT,
+ EvmSpecVersion.EXPERIMENTAL_EIPS));
+ assertThat(subject).isNotNull();
+ }
+
+ @Test
+ void nullEVM() {
+ assertThrows(NullPointerException.class, () -> EVMExecutor.evm((EVM) null));
+ }
+
+ @SuppressWarnings({"removal", "InlineMeInliner"})
+ @Test
+ void defaultChainIdAPIs() {
+ Bytes32 defaultChainId = Bytes32.leftPad(Bytes.of(1));
+
+ EVMExecutor istanbulEVM = EVMExecutor.istanbul(EvmConfiguration.DEFAULT);
+ assertThat(istanbulEVM.getChainId()).contains(defaultChainId);
+
+ EVMExecutor berlinEVM = EVMExecutor.berlin(EvmConfiguration.DEFAULT);
+ assertThat(berlinEVM.getChainId()).contains(defaultChainId);
+
+ EVMExecutor londonEVM = EVMExecutor.london(EvmConfiguration.DEFAULT);
+ assertThat(londonEVM.getChainId()).contains(defaultChainId);
+
+ EVMExecutor parisEVM = EVMExecutor.paris(EvmConfiguration.DEFAULT);
+ assertThat(parisEVM.getChainId()).contains(defaultChainId);
+
+ EVMExecutor shanghaiEVM = EVMExecutor.shanghai(EvmConfiguration.DEFAULT);
+ assertThat(shanghaiEVM.getChainId()).contains(defaultChainId);
+
+ EVMExecutor cancunEVM = EVMExecutor.cancun(EvmConfiguration.DEFAULT);
+ assertThat(cancunEVM.getChainId()).contains(defaultChainId);
+
+ EVMExecutor futureEipsVM = EVMExecutor.futureEips(EvmConfiguration.DEFAULT);
+ assertThat(futureEipsVM.getChainId()).contains(defaultChainId);
+ }
+
+ @Test
+ void executeCode() {
+ var result =
+ EVMExecutor.evm(EvmSpecVersion.SHANGHAI)
+ .worldUpdater(createSimpleWorld().updater())
+ .execute(
+ CodeFactory.createCode(Bytes.fromHexString("0x6001600255"), 1, false),
+ Bytes.EMPTY,
+ Wei.ZERO,
+ Address.ZERO);
+ assertThat(result).isNotNull();
+ }
+
+ @Test
+ void executeBytes() {
+ var result =
+ EVMExecutor.evm(EvmSpecVersion.SHANGHAI)
+ .worldUpdater(createSimpleWorld().updater())
+ .execute(Bytes.fromHexString("0x6001600255"), Bytes.EMPTY, Wei.ZERO, Address.ZERO);
+ assertThat(result).isNotNull();
+ }
+
+ @Test
+ void giantExecuteStack() {
+ SimpleWorld simpleWorld = createSimpleWorld();
+
+ var tracer = new StandardJsonTracer(System.out, false, true, true, false);
+ var result =
+ EVMExecutor.evm(EvmSpecVersion.SHANGHAI)
+ .messageFrameType(MessageFrame.Type.CONTRACT_CREATION)
+ .worldUpdater(simpleWorld.updater())
+ .tracer(tracer)
+ .contract(Address.fromHexString("0x100"))
+ .gas(15_000_000L)
+ .sender(Address.fromHexString("0x200"))
+ .receiver(Address.fromHexString("0x300"))
+ .coinbase(Address.fromHexString("0x400"))
+ .number(1)
+ .timestamp(9999)
+ .gasLimit(15_000_000)
+ .commitWorldState()
+ .gasPriceGWei(Wei.ONE)
+ .blobGasPrice(Wei.ONE)
+ .callData(Bytes.fromHexString("0x12345678"))
+ .ethValue(Wei.fromEth(1))
+ .code(CodeFactory.createCode(Bytes.fromHexString("0x6001600255"), 0, false))
+ .blockValues(new SimpleBlockValues())
+ .difficulty(Bytes.ofUnsignedLong(1L))
+ .mixHash(Bytes32.ZERO)
+ .baseFee(Wei.ONE)
+ .number(1)
+ .timestamp(100L)
+ .gasLimit(15_000_000L)
+ .blockHashLookup(number -> Hash.ZERO)
+ .versionedHashes(Optional.empty())
+ .precompileContractRegistry(new PrecompileContractRegistry())
+ .requireDeposit(false)
+ .initialNonce(42)
+ .contractValidationRules(List.of())
+ .forceCommitAddresses(List.of())
+ .warmAddress(Address.ZERO)
+ .accessListWarmStorage(
+ Address.ZERO, Bytes32.ZERO, Bytes32.leftPad(Bytes.ofUnsignedLong(2L)))
+ .messageCallProcessor(new MessageCallProcessor(null, null))
+ .contractCallProcessor(new ContractCreationProcessor(null, null, true, null, 1L))
+ .execute();
+ assertThat(result).isNotNull();
+ }
+
+ @Test
+ void anternateExecStack() {
+ SimpleWorld simpleWorld = createSimpleWorld();
+ var result =
+ EVMExecutor.evm(EvmSpecVersion.SHANGHAI)
+ .worldUpdater(simpleWorld.updater())
+ .messageFrameType(MessageFrame.Type.MESSAGE_CALL)
+ .code(Bytes.fromHexString("0x6001600255"))
+ .prevRandao(Bytes32.ZERO)
+ .accessListWarmAddresses(Set.of())
+ .accessListWarmStorage(MultimapBuilder.linkedHashKeys().arrayListValues().build())
+ .execute();
+ assertThat(result).isNotNull();
+ }
+
+ @NotNull
+ private static SimpleWorld createSimpleWorld() {
+ SimpleWorld simpleWorld = new SimpleWorld();
+
+ simpleWorld.createAccount(Address.fromHexString("0x0"), 1, Wei.fromEth(100));
+ simpleWorld.createAccount(Address.fromHexString("0x100"), 1, Wei.fromEth(100));
+ simpleWorld.createAccount(Address.fromHexString("0x200"), 1, Wei.fromEth(100));
+ simpleWorld.createAccount(Address.fromHexString("0x300"), 1, Wei.fromEth(100));
+ simpleWorld.createAccount(Address.fromHexString("0x400"), 1, Wei.fromEth(100));
+ return simpleWorld;
+ }
+}
diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java
index 6c178dda2a..913ffd92bc 100644
--- a/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java
+++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java
@@ -96,11 +96,11 @@ public class SelfDestructOperationTest {
}
when(worldUpdater.getAccount(originatorAddress)).thenReturn(accountOriginator);
- when(worldUpdater.get(originatorAddress)).thenReturn(accountOriginator);
if (!originatorAddress.equals(beneficiaryAddress)) {
when(worldUpdater.get(beneficiaryAddress)).thenReturn(accountBeneficiary);
}
when(worldUpdater.getOrCreate(beneficiaryAddress)).thenReturn(accountBeneficiary);
+ when(accountOriginator.getAddress()).thenReturn(originatorAddress);
when(accountOriginator.getBalance()).thenReturn(Wei.fromHexString(balanceHex));
final Operation.OperationResult operationResult = operation.execute(messageFrame, evm);
diff --git a/evm/src/test/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessorTest.java
index 7932741b3d..598758fb75 100644
--- a/evm/src/test/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessorTest.java
+++ b/evm/src/test/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessorTest.java
@@ -26,9 +26,9 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
+import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.fluent.EVMExecutor;
import org.hyperledger.besu.evm.frame.MessageFrame;
-import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@@ -99,7 +99,7 @@ abstract class AbstractMessageProcessorTest
@Test
void shouldTraceContextEnterExitForEip3155Test() {
- final EVMExecutor executor = EVMExecutor.shanghai(EvmConfiguration.DEFAULT);
+ final EVMExecutor executor = EVMExecutor.evm(EvmSpecVersion.SHANGHAI);
final ContextTracer contextTracer = new ContextTracer();
executor.tracer(contextTracer);