Skip to content

Commit cb7a375

Browse files
committed
added test to check that init code size check is done before state gas deduction
Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
1 parent a2319a1 commit cb7a375

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,69 @@ public long getGasLimit() {
278278

279279
assertThat(result.getHaltReason()).isEqualTo(ExceptionalHaltReason.INSUFFICIENT_GAS);
280280
}
281+
282+
@Test
283+
void oversizedInitcodeHaltsBeforeChargingStateGas() {
284+
// EIP-8037: A CREATE with initcode exceeding maxInitcodeSize must halt with CODE_TOO_LARGE
285+
// BEFORE any state gas is charged, so the state gas reservoir remains unchanged.
286+
final long blockGasLimit = 36_000_000L;
287+
final GasCalculator amsterdamCalc = new AmsterdamGasCalculator();
288+
final FakeCreateOperation amsterdamOp = new FakeCreateOperation(amsterdamCalc);
289+
290+
final EVM evm = MainnetEVMs.amsterdam(EvmConfiguration.DEFAULT);
291+
final int maxInitcodeSize = evm.getMaxInitcodeSize();
292+
// Size just over the limit
293+
final int oversizedLength = maxInitcodeSize + 1;
294+
295+
final UInt256 memoryOffset = UInt256.ZERO;
296+
final MessageFrame frame =
297+
MessageFrame.builder()
298+
.type(MessageFrame.Type.CONTRACT_CREATION)
299+
.contract(Address.ZERO)
300+
.inputData(Bytes.EMPTY)
301+
.sender(Address.fromHexString(SENDER))
302+
.value(Wei.ZERO)
303+
.apparentValue(Wei.ZERO)
304+
.code(new Code(SIMPLE_CREATE))
305+
.completer(__ -> {})
306+
.address(Address.fromHexString(SENDER))
307+
.blockHashLookup((__, ___) -> Hash.ZERO)
308+
.blockValues(
309+
new FakeBlockValues(1337) {
310+
@Override
311+
public long getGasLimit() {
312+
return blockGasLimit;
313+
}
314+
})
315+
.gasPrice(Wei.ZERO)
316+
.miningBeneficiary(Address.ZERO)
317+
.originator(Address.ZERO)
318+
.initialGas(10_000_000L)
319+
.worldUpdater(worldUpdater)
320+
.build();
321+
322+
// Push CREATE args: value=0, offset=0, size=oversizedLength
323+
frame.pushStackItem(Bytes.ofUnsignedLong(oversizedLength));
324+
frame.pushStackItem(memoryOffset);
325+
frame.pushStackItem(Bytes.EMPTY); // value = 0
326+
327+
when(account.getNonce()).thenReturn(55L);
328+
when(account.getBalance()).thenReturn(Wei.ZERO);
329+
when(worldUpdater.getAccount(any())).thenReturn(account);
330+
when(worldUpdater.get(any())).thenReturn(account);
331+
when(worldUpdater.getSenderAccount(any())).thenReturn(account);
332+
when(worldUpdater.getOrCreate(any())).thenReturn(newAccount);
333+
when(newAccount.getCode()).thenReturn(Bytes.EMPTY);
334+
when(newAccount.isStorageEmpty()).thenReturn(true);
335+
when(worldUpdater.updater()).thenReturn(worldUpdater);
336+
337+
final long stateGasBefore = frame.getStateGasReservoir();
338+
339+
final Operation.OperationResult result = amsterdamOp.execute(frame, evm);
340+
341+
assertThat(result.getHaltReason()).isEqualTo(ExceptionalHaltReason.CODE_TOO_LARGE);
342+
assertThat(frame.getStateGasReservoir())
343+
.as("State gas reservoir must be unchanged — no state gas charged for oversized initcode")
344+
.isEqualTo(stateGasBefore);
345+
}
281346
}

0 commit comments

Comments
 (0)