Adversarial robustness and conformance tests of the execution layer against a throwaway 3-node simnet on ports 27600+. Six scenarios, each a runnable command with a design-derived pass criterion and a measured result: malformed/boundary txs, nonce games across parallel blocks, RPC fuzz, pgas exhaustion, reorgs under execution, and developer-registry abuse. 98 checks, 0 failures, 0 node panics. Two findings filed in the bench-log entry: the mempool admits txs with gas_limit above B_e (low), and an over-pgas-budget tx is executed natively in full before being skipped for no fee (medium, griefing). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
46 lines
1.8 KiB
Solidity
46 lines
1.8 KiB
Solidity
// SPDX-License-Identifier: ISC
|
|
pragma solidity ^0.8.20;
|
|
|
|
// A contract that is cheap in execution gas but heavy in proving gas (pgas): it hammers the modexp precompile
|
|
// (0x05) and the KECCAK256 opcode in a loop. Under Igneum's pgas table (igneum/exec/src/pgas.rs) modexp is
|
|
// ~1000 + 10*input_len pgas for ~200 execution gas, so each call carries a large pgas/gas ratio and a loop can
|
|
// drive a transaction's pgas toward the per-block proving budget B_p with only a few million execution gas.
|
|
contract PgasBomb {
|
|
event Done(uint256 iterations, uint256 acc);
|
|
|
|
// Call the 1024-bit modexp precompile `n` times. Each call: baseLen=1, expLen=1, modLen=128 (input_len 226).
|
|
function modexpLoop(uint256 n) external returns (uint256 acc) {
|
|
bytes memory input = new bytes(96 + 1 + 1 + 128);
|
|
// baseLen = 1
|
|
input[31] = 0x01;
|
|
// expLen = 1
|
|
input[63] = 0x01;
|
|
// modLen = 128
|
|
input[95] = 0x80;
|
|
// base byte = 2
|
|
input[96] = 0x02;
|
|
// exp byte = 1
|
|
input[97] = 0x01;
|
|
// modulus: all 0xff (a large odd number)
|
|
for (uint256 i = 0; i < 128; i++) input[98 + i] = 0xff;
|
|
|
|
bytes memory out = new bytes(128);
|
|
for (uint256 i = 0; i < n; i++) {
|
|
bool ok;
|
|
assembly {
|
|
ok := staticcall(gas(), 0x05, add(input, 32), mload(input), add(out, 32), 128)
|
|
}
|
|
require(ok, "modexp failed");
|
|
acc += uint8(out[127]);
|
|
}
|
|
emit Done(n, acc);
|
|
}
|
|
|
|
// Hash a 32-byte word `n` times, chaining the result. Pure KECCAK256 opcode load.
|
|
function keccakLoop(uint256 n) external returns (bytes32 h) {
|
|
h = keccak256(abi.encodePacked(block.number));
|
|
for (uint256 i = 0; i < n; i++) {
|
|
h = keccak256(abi.encodePacked(h));
|
|
}
|
|
}
|
|
}
|