Skip to content

Commit 04be158

Browse files
committed
fix(docs): Update human docs
1 parent 914b2aa commit 04be158

2 files changed

Lines changed: 22 additions & 2 deletions

File tree

docs/writing_tests/fork_methods.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ def test_some_feature(fork):
3838

3939
```python
4040
def test_transaction_gas(fork, state_test):
41-
gas_cost = fork.gas_costs().GAS_TX_BASE
41+
# Derive the fork's intrinsic gas from the calculator rather than
42+
# summing raw `gas_costs()` constants (see the Gas Parameters warning).
43+
intrinsic_gas = fork.transaction_intrinsic_cost_calculator()()
4244

4345
# Create a transaction with the correct gas parameters for this fork
4446
tx = Transaction(
45-
gas_limit=gas_cost + 10000,
47+
gas_limit=intrinsic_gas + 10000,
4648
# ...
4749
)
4850

@@ -114,6 +116,9 @@ fork.memory_expansion_gas_calculator() # Returns a callable
114116
fork.transaction_intrinsic_cost_calculator() # Returns a callable
115117
```
116118

119+
!!! warning "Do not reconstruct expected gas from `gas_costs()` constants"
120+
`fork.gas_costs()` exposes the raw schedule for framework internals. When a test needs an *expected* gas amount, derive it from a cost construct that tracks the live schedule (`bytecode.gas_cost(fork)` / `.regular_cost(fork)` / `.state_cost(fork)` / `.refund(fork)`, opcode metadata, the intrinsic/top-frame/data-floor calculators, `fork.call_value_stipend()`) rather than hand-summing constants — hand-built expectations silently break when a fork reprices. See [Opcode Metadata and Gas Calculations](opcode_metadata.md#do-not-hand-reconstruct-gas-from-constants).
121+
117122
### Transaction Types
118123

119124
Methods for determining valid transaction types:

docs/writing_tests/opcode_metadata.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@ The execution testing package provides capabilities to calculate gas costs and r
99
- Validating gas cost calculations for specific opcode scenarios
1010
- Future-proofing tests against breaking in upcoming forks that change gas rules
1111

12+
## Do Not Hand-Reconstruct Gas From Constants
13+
14+
Never build an expected gas amount by summing `fork.gas_costs()` constants (`NEW_ACCOUNT`, `CALL_VALUE`, `COLD_STORAGE_WRITE`, `VERY_LOW`, ...). Re-deriving the schedule by hand duplicates the framework's own calculation and silently breaks when a future fork reprices or restructures a cost. Always derive the expectation from a framework construct that tracks the live schedule:
15+
16+
- **The bytecode/opcode under test:** set the relevant metadata (see below) and read `bytecode.gas_cost(fork)` (regular + state), `.regular_cost(fork)`, `.state_cost(fork)`, or `.refund(fork)`. Link the exact opcode to the behavior, e.g. `Op.SELFDESTRUCT(account_new=True).state_cost(fork)`.
17+
- **A single bare opcode/schedule cost** comes from a metadata-only opcode: `Op.BALANCE.with_metadata(address_warm=False).gas_cost(fork)` yields the cold account-access cost with no operand pushes.
18+
- **Transaction-level costs:** `fork.transaction_intrinsic_cost_calculator()`, `fork.transaction_top_frame_state_gas(contract_creation=True)` (the created account's new-account state gas — on recent forks it is charged at the top frame, *not* in the intrinsic, so never subtract it from the intrinsic), `fork.transaction_data_floor_cost_calculator()`, and `fork.call_value_stipend()`.
19+
- **Cross-fork / fork-transition comparisons:** evaluate the *same* bytecode or intrinsic at each fork (`before = fork.fork_at(timestamp=...)`, `after = ...`) and compare the resulting costs — do not compare raw schedule constants.
20+
21+
Additional rules:
22+
23+
- **Do not add "self-check" assertions** that compare a framework-computed value against a `fork.gas_costs()` decomposition of the same fork. They add no coverage over the runtime behavior the test already exercises and only break on repricing.
24+
- **If the framework cannot express a cost, extend the framework** (wire the opcode into its gas/state map, add an accessor) rather than working around it in the test.
25+
- **Exception:** a test whose *subject* is a specific schedule value — for example a regression asserting that an opcode's cost is unchanged across a fork — may compare a runtime measurement (`CodeGasMeasure`) against the fork's declared `fork.gas_costs().OPCODE_*` value. Even then, never hardcode the literal number.
26+
1227
## Opcode Metadata
1328

1429
Many opcodes accept metadata parameters that affect their gas cost calculations. Metadata represents runtime state information that influences gas consumption.

0 commit comments

Comments
 (0)