Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3
908 words
5 minutes
Geth(6) QA

Q1: What is the complete execution pipeline for a single transaction?#

The pipeline lives in three files:

state_processor.go — block-level: iterate transactions, produce receipts
state_transition.go — single-tx engine: preCheck → EVM → refund → fees
evm.go — build BlockContext and TxContext for the EVM

Block-level setup#

Before any transaction executes, Process() sets up a shared environment:

gp = new(GasPool).AddGas(block.GasLimit()) // block gas budget
evm = vm.NewEVM(blockContext, statedb, ...) // one EVM reused for all txs

GasPool is just a uint64 representing how much gas the block has left. Each transaction draws from this pool at the start and returns unused gas at the end. If the pool is exhausted, no more transactions can fit in the block.

The EVM instance is shared across the entire block — not created per transaction. Block-level context (coinbase, block number, timestamp, baseFee) stays constant; only the transaction-level context (sender, gasPrice) is swapped per transaction.

Then each transaction goes through the following stages:

Stage 1: preCheck — is this transaction eligible to execute?#

preCheck()
├─ Nonce must exactly equal the state nonce (no gaps, no replays)
├─ Sender must be an EOA (no contract code, unless EIP-7702 delegated)
├─ gasFeeCap >= baseFee (bid must meet the floor price)
└─ buyGas()

All checks happen before any gas is spent. If any check fails, the transaction is not included in the block — this is a consensus-level error.

Stage 2: buyGas — pre-pay maximum fees#

// Balance check: gasLimit × gasFeeCap + value + blobFee (worst case)
// Actual deduction: gasLimit × effectiveGasPrice (real cost)
st.state.SubBalance(sender, gasLimit × gasPrice)
st.gp.SubGas(msg.GasLimit)
st.gasRemaining = msg.GasLimit

Key distinction: validation uses gasFeeCap (the max you’re willing to pay), but the deduction uses effectiveGasPrice (the actual clearing price). Like an auction — you bid 100, clearing price is 60, the system checks you have 100 but only charges 60.

Stage 3: IntrinsicGas — baseline cost#

Before the EVM even starts, a minimum fee is deducted:

ComponentCost
Simple transfer21,000 gas
Contract creation53,000 gas
Calldata zero bytes4 gas each
Calldata non-zero bytes16 gas each
Access list addresses2,400 gas each
Access list storage keys1,900 gas each

If gasRemaining < intrinsicGas, the transaction fails immediately. Otherwise the intrinsic gas is subtracted, and the remainder enters the EVM.

Stage 4: EVM dispatch#

if msg.To == nil {
// Contract creation: Data is init code, executed to produce deployed bytecode
ret, _, st.gasRemaining, vmerr = evm.Create(sender, data, gasRemaining, value)
} else {
// Regular call: increment nonce first, then execute target contract
st.state.SetNonce(sender, nonce+1)
ret, st.gasRemaining, vmerr = evm.Call(sender, to, data, gasRemaining, value)
}

A critical point: EVM errors (vmerr) are NOT consensus errors. Even if the EVM returns OutOfGas or Revert, the transaction is still included in the block — gas is consumed, nonce is incremented, but the EVM’s internal state changes are rolled back. Only preCheck-stage errors prevent a transaction from being included.

Stage 5: calcRefund — refund calculation#

Certain operations (e.g., SSTORE clearing a slot to zero) accumulate a refund counter. But refunds are capped:

  • Pre-London: max gasUsed / 2
  • Post-London (EIP-3529): max gasUsed / 5

The tighter cap prevents “gas token” exploits — deliberately creating and destroying storage slots to farm refunds.

Stage 6: returnGas — refund ETH to sender#

state.AddBalance(sender, gasRemaining × gasPrice) // return unspent ETH
gp.AddGas(gasRemaining) // return gas to block pool

The reverse of buyGas. The sender gets back the unspent portion.

Stage 7: fee distribution#

effectiveTip = gasPrice - baseFee
state.AddBalance(coinbase, gasUsed × effectiveTip) // tip goes to block producer
// The baseFee portion? Nobody receives it. It is burned.

Stage 8: receipt creation#

receipt.Status = success / failed
receipt.GasUsed = gas consumed by this transaction
receipt.CumulativeGasUsed = cumulative gas in block up to this transaction
receipt.Logs = events emitted during EVM execution
receipt.ContractAddress = new contract address (if contract creation)

Then statedb.Finalise() is called, promoting dirty state to pending, preparing for the next transaction.


Q2: What is the complete lifecycle of gas — where does the money come from and where does it go?#

Concrete example#

Alice sends a transaction: gasLimit=100,000, gasFeeCap=30 gwei, gasTipCap=2 gwei, current baseFee=10 gwei.

Effective gas price calculation:

effectiveGasPrice = min(gasTipCap + baseFee, gasFeeCap)
= min(2 + 10, 30) = 12 gwei
effectiveTip = effectiveGasPrice - baseFee = 12 - 10 = 2 gwei

buyGas — pre-payment#

Balance check (worst case): 100,000 × 30 gwei = 3,000,000 gwei
Actual deduction: 100,000 × 12 gwei = 1,200,000 gwei
Alice balance -= 1,200,000 gwei
Block GasPool -= 100,000
gasRemaining = 100,000

IntrinsicGas — baseline deduction#

Assuming a simple transfer with no calldata:

intrinsicGas = 21,000
gasRemaining = 100,000 - 21,000 = 79,000

EVM execution — gas consumption#

Assuming the EVM consumes 29,000 gas:

gasRemaining = 79,000 - 29,000 = 50,000

calcRefund — refund#

Assuming SSTORE clears accumulated 5,000 refund. Cap check:

gasUsed = 100,000 - 50,000 = 50,000
cap = 50,000 / 5 = 10,000
actual refund = min(5,000, 10,000) = 5,000
gasRemaining = 50,000 + 5,000 = 55,000

returnGas — refund ETH#

Return to Alice: 55,000 × 12 gwei = 660,000 gwei
Alice balance += 660,000 gwei
Block GasPool += 55,000

Fee distribution#

Final gasUsed = 100,000 - 55,000 = 45,000
Coinbase receives tip: 45,000 × 2 gwei = 90,000 gwei
BaseFee burned: 45,000 × 10 gwei = 450,000 gwei (nobody receives this)

Verification#

Alice total spend = 1,200,000 - 660,000 = 540,000 gwei
Distribution = 90,000 (tip) + 450,000 (burned) = 540,000 gwei ✓

Flow diagram#

Alice prepays 1,200,000 gwei (gasLimit × effectiveGasPrice)
├─ Returned to Alice: 660,000 gwei (unused gas × effectiveGasPrice)
└─ Actually consumed: 540,000 gwei (gasUsed × effectiveGasPrice)
├─ Coinbase: 90,000 gwei (gasUsed × tip)
└─ Burned: 450,000 gwei (gasUsed × baseFee) ← EIP-1559

The baseFee burn is the core EIP-1559 design — it makes ETH deflationary. Validators only receive the tip portion and cannot profit by manipulating the baseFee.

Geth(6) QA
https://kehaozheng.vercel.app/posts/chainethgeth/06_qa/
Author
Kehao Zheng
Published at
2026-04-15
License
CC BY-NC-SA 4.0

Some information may be outdated