EIP-3860 Initcode Size Reference Test fixes (#4911)

* EIP-3860 Initcode Size Reference Test fixes

Fix corner cases around initcode size checking in reference tests.

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
pull/4906/head
Danno Ferrin 2 years ago committed by GitHub
parent 593e79f77c
commit 80bebf2b73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
  2. 17
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
  3. 1
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java
  4. 50
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java
  5. 9
      evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
  6. 10
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java
  7. 4
      evm/src/main/java/org/hyperledger/besu/evm/operation/Create2Operation.java
  8. 4
      evm/src/main/java/org/hyperledger/besu/evm/operation/CreateOperation.java
  9. 181
      evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java
  10. 14
      evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java

@ -36,10 +36,8 @@ import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.contractvalidation.CachedInvalidCodeRule;
import org.hyperledger.besu.evm.contractvalidation.MaxCodeSizeRule;
import org.hyperledger.besu.evm.contractvalidation.PrefixCodeRule;
import org.hyperledger.besu.evm.frame.MessageFrame;
@ -532,7 +530,8 @@ public abstract class MainnetProtocolSpecs {
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559),
quorumCompatibilityMode))
quorumCompatibilityMode,
Integer.MAX_VALUE))
.transactionProcessorBuilder(
(gasCalculator,
transactionValidator,
@ -655,9 +654,6 @@ public abstract class MainnetProtocolSpecs {
? FeeMarket.zeroBaseFee(londonForkBlockNumber)
: FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas());
// constant for max initcode size for EIP-3860 limit and meter initcode
final int contractSizeLimit = configContractSizeLimit.orElse(SHANGHAI_INIT_CODE_SIZE_LIMIT);
return parisDefinition(
chainId,
configContractSizeLimit,
@ -690,17 +686,19 @@ public abstract class MainnetProtocolSpecs {
londonFeeMarket,
CoinbaseFeePriceCalculator.eip1559()))
// Contract creation rules for EIP-3860 Limit and meter intitcode
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
new ContractCreationProcessor(
.transactionValidatorBuilder(
gasCalculator ->
new MainnetTransactionValidator(
gasCalculator,
evm,
londonFeeMarket,
true,
List.of(
MaxCodeSizeRule.of(contractSizeLimit),
CachedInvalidCodeRule.of(EvmSpecVersion.SHANGHAI)),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
chainId,
Set.of(
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559),
quorumCompatibilityMode,
SHANGHAI_INIT_CODE_SIZE_LIMIT))
.name("Shanghai");
}

@ -53,6 +53,8 @@ public class MainnetTransactionValidator {
private final Set<TransactionType> acceptedTransactionTypes;
private final boolean goQuorumCompatibilityMode;
private final int maxInitcodeSize;
public MainnetTransactionValidator(
final GasCalculator gasCalculator,
final boolean checkSignatureMalleability,
@ -78,7 +80,8 @@ public class MainnetTransactionValidator {
checkSignatureMalleability,
chainId,
acceptedTransactionTypes,
quorumCompatibilityMode);
quorumCompatibilityMode,
Integer.MAX_VALUE);
}
public MainnetTransactionValidator(
@ -87,13 +90,15 @@ public class MainnetTransactionValidator {
final boolean checkSignatureMalleability,
final Optional<BigInteger> chainId,
final Set<TransactionType> acceptedTransactionTypes,
final boolean goQuorumCompatibilityMode) {
final boolean goQuorumCompatibilityMode,
final int maxInitcodeSize) {
this.gasCalculator = gasCalculator;
this.feeMarket = feeMarket;
this.disallowSignatureMalleability = checkSignatureMalleability;
this.chainId = chainId;
this.acceptedTransactionTypes = acceptedTransactionTypes;
this.goQuorumCompatibilityMode = goQuorumCompatibilityMode;
this.maxInitcodeSize = maxInitcodeSize;
}
/**
@ -184,6 +189,14 @@ public class MainnetTransactionValidator {
intrinsicGasCost, transaction.getGasLimit()));
}
if (transaction.isContractCreation() && transaction.getPayload().size() > maxInitcodeSize) {
return ValidationResult.invalid(
TransactionInvalidReason.INITCODE_TOO_LARGE,
String.format(
"Initcode size of %d exceeds maximum size of %s",
transaction.getPayload().size(), maxInitcodeSize));
}
return ValidationResult.valid();
}

@ -37,6 +37,7 @@ public enum TransactionInvalidReason {
TRANSACTION_ALREADY_KNOWN,
TRANSACTION_REPLACEMENT_UNDERPRICED,
MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS,
INITCODE_TOO_LARGE,
// Private Transaction Invalid Reasons
PRIVATE_TRANSACTION_FAILED,
PRIVATE_NONCE_TOO_LOW,

@ -45,8 +45,8 @@ import org.hyperledger.besu.plugin.data.TransactionType;
import java.math.BigInteger;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;
import org.junit.Test;
@ -259,7 +259,8 @@ public class MainnetTransactionValidatorTest {
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.values()),
defaultGoQuorumCompatibilityMode);
defaultGoQuorumCompatibilityMode,
Integer.MAX_VALUE);
validator.setTransactionFilter(transactionFilter(true));
final Transaction transaction =
@ -342,7 +343,8 @@ public class MainnetTransactionValidatorTest {
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.FRONTIER),
defaultGoQuorumCompatibilityMode);
defaultGoQuorumCompatibilityMode,
Integer.MAX_VALUE);
final MainnetTransactionValidator eip1559Validator =
new MainnetTransactionValidator(
@ -351,7 +353,8 @@ public class MainnetTransactionValidatorTest {
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.FRONTIER, TransactionType.EIP1559),
defaultGoQuorumCompatibilityMode);
defaultGoQuorumCompatibilityMode,
Integer.MAX_VALUE);
final Transaction transaction =
new TransactionTestFixture()
@ -383,7 +386,8 @@ public class MainnetTransactionValidatorTest {
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.FRONTIER, TransactionType.EIP1559),
defaultGoQuorumCompatibilityMode);
defaultGoQuorumCompatibilityMode,
Integer.MAX_VALUE);
final Transaction transaction =
new TransactionTestFixture()
.type(TransactionType.EIP1559)
@ -406,7 +410,8 @@ public class MainnetTransactionValidatorTest {
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.FRONTIER, TransactionType.EIP1559),
defaultGoQuorumCompatibilityMode);
defaultGoQuorumCompatibilityMode,
Integer.MAX_VALUE);
final Transaction transaction =
new TransactionTestFixture()
.type(TransactionType.EIP1559)
@ -428,7 +433,8 @@ public class MainnetTransactionValidatorTest {
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.FRONTIER, TransactionType.EIP1559),
defaultGoQuorumCompatibilityMode);
defaultGoQuorumCompatibilityMode,
Integer.MAX_VALUE);
final Transaction transaction =
new TransactionTestFixture()
.maxPriorityFeePerGas(Optional.of(Wei.of(1)))
@ -452,7 +458,8 @@ public class MainnetTransactionValidatorTest {
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.FRONTIER, TransactionType.EIP1559),
defaultGoQuorumCompatibilityMode);
defaultGoQuorumCompatibilityMode,
Integer.MAX_VALUE);
final Transaction transaction =
new TransactionTestFixture()
.maxPriorityFeePerGas(Optional.of(Wei.of(1)))
@ -468,6 +475,33 @@ public class MainnetTransactionValidatorTest {
.isEqualTo(ValidationResult.valid());
}
@Test
public void shouldRejectTooLargeInitcode() {
final MainnetTransactionValidator validator =
new MainnetTransactionValidator(
gasCalculator,
FeeMarket.london(0L),
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.FRONTIER, TransactionType.EIP1559),
defaultGoQuorumCompatibilityMode,
0xc000);
var bigPayload =
new TransactionTestFixture()
.payload(Bytes.fromHexString("0x" + "00".repeat(0xc001)))
.chainId(Optional.of(BigInteger.ONE))
.createTransaction(senderKeys);
var validationResult =
validator.validate(bigPayload, Optional.empty(), transactionValidationParams);
assertThat(validationResult.isValid()).isFalse();
assertThat(validationResult.getInvalidReason())
.isEqualTo(TransactionInvalidReason.INITCODE_TOO_LARGE);
assertThat(validationResult.getErrorMessage())
.isEqualTo("Initcode size of 49153 exceeds maximum size of 49152");
}
@Test
public void goQuorumCompatibilityModeRejectNonZeroGasPrice() {
final MainnetTransactionValidator validator =

@ -123,6 +123,9 @@ public class MainnetEVMs {
public static final BigInteger DEV_NET_CHAIN_ID = BigInteger.valueOf(1337);
public static final int SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT = 0x6000;
public static final int SHANGHAI_INIT_CODE_SIZE_LIMIT = 2 * SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT;
private MainnetEVMs() {
// utility class
}
@ -209,7 +212,7 @@ public class MainnetEVMs {
registry.put(new InvalidOperation(gasCalculator));
registry.put(new StopOperation(gasCalculator));
registry.put(new SelfDestructOperation(gasCalculator));
registry.put(new CreateOperation(gasCalculator));
registry.put(new CreateOperation(gasCalculator, Integer.MAX_VALUE));
registry.put(new CallOperation(gasCalculator));
registry.put(new CallCodeOperation(gasCalculator));
@ -317,7 +320,7 @@ public class MainnetEVMs {
public static void registerConstantinopleOperations(
final OperationRegistry registry, final GasCalculator gasCalculator) {
registerByzantiumOperations(registry, gasCalculator);
registry.put(new Create2Operation(gasCalculator));
registry.put(new Create2Operation(gasCalculator, Integer.MAX_VALUE));
registry.put(new SarOperation(gasCalculator));
registry.put(new ShlOperation(gasCalculator));
registry.put(new ShrOperation(gasCalculator));
@ -461,6 +464,8 @@ public class MainnetEVMs {
final BigInteger chainID) {
registerParisOperations(registry, gasCalculator, chainID);
registry.put(new Push0Operation(gasCalculator));
registry.put(new CreateOperation(gasCalculator, SHANGHAI_INIT_CODE_SIZE_LIMIT));
registry.put(new Create2Operation(gasCalculator, SHANGHAI_INIT_CODE_SIZE_LIMIT));
}
public static EVM cancun(

@ -36,13 +36,17 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
protected static final OperationResult UNDERFLOW_RESPONSE =
new OperationResult(0L, ExceptionalHaltReason.INSUFFICIENT_STACK_ITEMS);
protected int maxInitcodeSize;
protected AbstractCreateOperation(
final int opcode,
final String name,
final int stackItemsConsumed,
final int stackItemsProduced,
final GasCalculator gasCalculator) {
final GasCalculator gasCalculator,
final int maxInitcodeSize) {
super(opcode, name, stackItemsConsumed, stackItemsProduced, gasCalculator);
this.maxInitcodeSize = maxInitcodeSize;
}
@Override
@ -74,6 +78,10 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
final long inputOffset = clampedToLong(frame.getStackItem(1));
final long inputSize = clampedToLong(frame.getStackItem(2));
if (inputSize > maxInitcodeSize) {
frame.popStackItems(getStackItemsConsumed());
return new OperationResult(cost, ExceptionalHaltReason.CODE_TOO_LARGE);
}
final Bytes inputData = frame.readMemory(inputOffset, inputSize);
Code code = evm.getCode(Hash.hash(inputData), inputData);

@ -29,8 +29,8 @@ public class Create2Operation extends AbstractCreateOperation {
private static final Bytes PREFIX = Bytes.fromHexString("0xFF");
public Create2Operation(final GasCalculator gasCalculator) {
super(0xF5, "CREATE2", 4, 1, gasCalculator);
public Create2Operation(final GasCalculator gasCalculator, final int maxInitcodeSize) {
super(0xF5, "CREATE2", 4, 1, gasCalculator, maxInitcodeSize);
}
@Override

@ -21,8 +21,8 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator;
public class CreateOperation extends AbstractCreateOperation {
public CreateOperation(final GasCalculator gasCalculator) {
super(0xF0, "CREATE", 3, 1, gasCalculator);
public CreateOperation(final GasCalculator gasCalculator, final int maxInitcodeSize) {
super(0xF0, "CREATE", 3, 1, gasCalculator, maxInitcodeSize);
}
@Override

@ -15,6 +15,8 @@
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.evm.MainnetEVMs.DEV_NET_CHAIN_ID;
import static org.hyperledger.besu.evm.frame.ExceptionalHaltReason.CODE_TOO_LARGE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -23,43 +25,65 @@ 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.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.operation.Create2Operation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.processor.ContractCreationProcessor;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.evm.worldstate.WrappedEvmAccount;
import java.util.ArrayDeque;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@RunWith(Parameterized.class)
public class Create2OperationTest {
private final String sender;
private final String salt;
private final String code;
private final String expectedAddress;
private final int expectedGas;
private MessageFrame messageFrame;
private final WorldUpdater worldUpdater = mock(WorldUpdater.class);
private final WrappedEvmAccount account = mock(WrappedEvmAccount.class);
private final MutableAccount mutableAccount = mock(MutableAccount.class);
private final EVM evm = mock(EVM.class);
private final WrappedEvmAccount newAccount = mock(WrappedEvmAccount.class);
private final MutableAccount newMutableAccount = mock(MutableAccount.class);
private final Create2Operation operation =
new Create2Operation(new ConstantinopleGasCalculator());
new Create2Operation(new ConstantinopleGasCalculator(), Integer.MAX_VALUE);
private final Create2Operation maxInitCodeOperation =
new Create2Operation(
new ConstantinopleGasCalculator(), MainnetEVMs.SHANGHAI_INIT_CODE_SIZE_LIMIT);
private static final String TOPIC =
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; // 32 FFs
private static final Bytes SIMPLE_CREATE =
Bytes.fromHexString(
"0x"
+ "7f" // push32
+ TOPIC
+ "6000" // PUSH1 0x00
+ "6000" // PUSH1 0x00
+ "A1" // LOG1
+ "6000" // PUSH1 0x00
+ "6000" // PUSH1 0x00
+ "F3" // RETURN
);
public static final String SENDER = "0xdeadc0de00000000000000000000000000000000";
private static final int SHANGHAI_CREATE_GAS = 41240 + (0xc000 / 32) * 6;
@Parameters(name = "sender: {0}, salt: {1}, code: {2}")
public static Object[][] params() {
return new Object[][] {
{
@ -114,21 +138,8 @@ public class Create2OperationTest {
};
}
public Create2OperationTest(
final String sender,
final String salt,
final String code,
final String expectedAddress,
final int expectedGas) {
this.sender = sender;
this.salt = salt;
this.code = code;
this.expectedAddress = expectedAddress;
this.expectedGas = expectedGas;
}
public void setUp(final String sender, final String salt, final String code) {
@Before
public void setUp() {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
final Bytes codeBytes = Bytes.fromHexString(code);
final UInt256 memoryLength = UInt256.valueOf(codeBytes.size());
@ -171,16 +182,124 @@ public class Create2OperationTest {
invocation.getArgument(1), invocation.getArgument(0), 0, true));
}
@Test
public void shouldCalculateAddress() {
@ParameterizedTest
@MethodSource("params")
void shouldCalculateAddress(
final String sender,
final String salt,
final String code,
final String expectedAddress,
final int ignoredExpectedGas) {
setUp(sender, salt, code);
final Address targetContractAddress = operation.targetContractAddress(messageFrame);
assertThat(targetContractAddress).isEqualTo(Address.fromHexString(expectedAddress));
}
@Test
public void shouldCalculateGasPrice() {
@ParameterizedTest
@MethodSource("params")
void shouldCalculateGasPrice(
final String sender,
final String salt,
final String code,
final String ignoredExpectedAddress,
final int expectedGas) {
setUp(sender, salt, code);
final OperationResult result = operation.execute(messageFrame, evm);
assertThat(result.getHaltReason()).isNull();
assertThat(result.getGasCost()).isEqualTo(expectedGas);
}
@Test
void shanghaiMaxInitCodeSizeCreate() {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
final UInt256 memoryLength = UInt256.fromHexString("0xc000");
final ArrayDeque<MessageFrame> messageFrameStack = new ArrayDeque<>();
final MessageFrame messageFrame =
testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack);
when(account.getMutable()).thenReturn(mutableAccount);
when(account.getNonce()).thenReturn(55L);
when(mutableAccount.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getSenderAccount(any())).thenReturn(account);
when(worldUpdater.getOrCreate(any())).thenReturn(newAccount);
when(newAccount.getMutable()).thenReturn(newMutableAccount);
when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY);
when(worldUpdater.updater()).thenReturn(worldUpdater);
final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = maxInitCodeOperation.execute(messageFrame, evm);
final MessageFrame createFrame = messageFrameStack.peek();
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
ccp.process(createFrame, OperationTracer.NO_TRACING);
final Log log = createFrame.getLogs().get(0);
final String calculatedTopic = log.getTopics().get(0).toUnprefixedHexString();
assertThat(calculatedTopic).isEqualTo(TOPIC);
assertThat(result.getGasCost()).isEqualTo(SHANGHAI_CREATE_GAS);
}
@Test
void shanghaiMaxInitCodeSizePlus1Create() {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
final UInt256 memoryLength = UInt256.fromHexString("0xc001");
final ArrayDeque<MessageFrame> messageFrameStack = new ArrayDeque<>();
final MessageFrame messageFrame =
testMemoryFrame(memoryOffset, memoryLength, UInt256.ZERO, 1, messageFrameStack);
when(account.getMutable()).thenReturn(mutableAccount);
when(account.getNonce()).thenReturn(55L);
when(mutableAccount.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getSenderAccount(any())).thenReturn(account);
when(worldUpdater.getOrCreate(any())).thenReturn(newAccount);
when(newAccount.getMutable()).thenReturn(newMutableAccount);
when(newMutableAccount.getCode()).thenReturn(Bytes.EMPTY);
when(worldUpdater.updater()).thenReturn(worldUpdater);
final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = maxInitCodeOperation.execute(messageFrame, evm);
assertThat(result.getHaltReason()).isEqualTo(CODE_TOO_LARGE);
}
@NotNull
private MessageFrame testMemoryFrame(
final UInt256 memoryOffset,
final UInt256 memoryLength,
final UInt256 value,
final int depth,
final ArrayDeque<MessageFrame> messageFrameStack) {
final MessageFrame 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(CodeFactory.createCode(SIMPLE_CREATE, Hash.hash(SIMPLE_CREATE), 0, true))
.depth(depth)
.completer(__ -> {})
.address(Address.fromHexString(SENDER))
.blockHashLookup(n -> Hash.hash(Bytes.ofUnsignedLong(n)))
.blockValues(mock(BlockValues.class))
.gasPrice(Wei.ZERO)
.messageFrameStack(messageFrameStack)
.miningBeneficiary(Address.ZERO)
.originator(Address.ZERO)
.initialGas(100000L)
.worldUpdater(worldUpdater)
.build();
messageFrame.pushStackItem(Bytes.EMPTY);
messageFrame.pushStackItem(memoryLength);
messageFrame.pushStackItem(memoryOffset);
messageFrame.pushStackItem(value);
messageFrame.expandMemory(0, 500);
messageFrame.writeMemory(
memoryOffset.trimLeadingZeros().toInt(), SIMPLE_CREATE.size(), SIMPLE_CREATE);
return messageFrame;
}
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.evm.MainnetEVMs.DEV_NET_CHAIN_ID;
import static org.hyperledger.besu.evm.frame.ExceptionalHaltReason.CODE_TOO_LARGE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -54,7 +55,11 @@ public class CreateOperationTest {
private final WrappedEvmAccount newAccount = mock(WrappedEvmAccount.class);
private final MutableAccount mutableAccount = mock(MutableAccount.class);
private final MutableAccount newMutableAccount = mock(MutableAccount.class);
private final CreateOperation operation = new CreateOperation(new ConstantinopleGasCalculator());
private final CreateOperation operation =
new CreateOperation(new ConstantinopleGasCalculator(), Integer.MAX_VALUE);
private final CreateOperation maxInitCodeOperation =
new CreateOperation(
new ConstantinopleGasCalculator(), MainnetEVMs.SHANGHAI_INIT_CODE_SIZE_LIMIT);
private static final String TOPIC =
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; // 32 FFs
@ -196,7 +201,7 @@ public class CreateOperationTest {
when(worldUpdater.updater()).thenReturn(worldUpdater);
final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = operation.execute(messageFrame, evm);
var result = maxInitCodeOperation.execute(messageFrame, evm);
final MessageFrame createFrame = messageFrameStack.peek();
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
@ -228,9 +233,8 @@ public class CreateOperationTest {
when(worldUpdater.updater()).thenReturn(worldUpdater);
final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = operation.execute(messageFrame, evm);
assertThat(messageFrame.getStackItem(0)).isEqualTo(UInt256.ZERO);
assertThat(result.getGasCost()).isEqualTo(SHANGHAI_CREATE_GAS);
var result = maxInitCodeOperation.execute(messageFrame, evm);
assertThat(result.getHaltReason()).isEqualTo(CODE_TOO_LARGE);
}
@NotNull

Loading…
Cancel
Save