Intrinsic gas is the amount of gas paid prior to execution of a transaction. That is, the gas paid by the initiator of a transaction, which will always be an externally-owned account, before any state updates are made or any code is executed.
Gas Calculation:
gas_cost = 21000
: base cost- If
tx.to == null
(contract creation tx):gas_cost += 32000
gas_cost += 4 * bytes_zero
: gas added to base cost for every zero byte of memory datagas_cost += 16 * bytes_nonzero
: gas added to base cost for every nonzero byte of memory data
An additional gas cost is paid by any operation that expands the memory that is in use.
This memory expansion cost is dependent on the existing memory size and is 0
if the operation does not reference a memory address higher than the existing highest referenced memory address.
A reference is any read, write, or other usage of memory (such as in a CALL
).
Terms:
new_mem_size
: the highest referenced memory address after the operation in question (in bytes)new_mem_size_words = (new_mem_size + 31) // 32
: number of (32-byte) words required for memory after the operation in questionCmem(machine_state)
: the memory cost function for a given machine state
Gas Calculation:
gas_cost = Cmem(new_state) - Cmem(old_state)
gas_cost = (new_mem_size_words ^ 2 // 512) + (3 * new_mem_size_words) - Cmem(old_state)
Useful Notes:
- The following opcodes incur a memory expansion cost in addition to their otherwise static gas cost:
RETURN
,REVERT
,MLOAD
,MSTORE
,MSTORE8
. - Referencing a zero length range does not require memory to be extended to the beginning of the range.
- The memory cost function is linear up to 724 bytes of memory used, at which point additional memory costs substantially more.
As of EIP-2929, two transaction-wide access sets are maintained. These access sets keep track of which addresses and storage slots have already been touched within the current transaction.
touched_addresses : Set[Address]
- a set where every element is an address
- initialized to include
tx.origin
,tx.to
*, and all precompiles - * For a contract creation transaction,
touched_addresses
is initialized to include the address of the created contract instead oftx.to
, which is the zero address.
touched_storage_slots : Set[(Address, Bytes32)]
- a set where every element is a tuple,
(address, storage_key)
- initialized to the empty set,
{}
- a set where every element is a tuple,
The access sets above are relevant for the following operations:
ADDRESS_TOUCHING_OPCODES := { EXTCODESIZE, EXTCODECOPY, EXTCODEHASH, BALANCE, CALL, CALLCODE, DELEGATECALL, STATICCALL, SELFDESTRUCT }
STORAGE_TOUCHING_OPCODES := { SLOAD, SSTORE }
When an address is the target of one of the ADDRESS_TOUCHING_OPCODES
, the address is immediately added to the touched_addresses
set.
touched addresses = touched_addresses ∪ { target_address }
When a storage slot is the target of one of the STORAGE_TOUCHING_OPCODES
, the (address, key)
pair is immediately added to the touched_storage_slots
set.
touched_storage_slots = touched_storage_slots ∪ { (current_address, target_storage_key) }
Important Notes:
- Adding duplicate elements to these sets is a no-op. Performant implementations will use a map with more complicated addition logic.
- If an execution frame reverts, the access sets will return to the state they were in before the frame was entered.
- Additions to the
touched_addresses
set for*CALL
andCREATE*
opcodes are made immediately before the new execution frames are entered, so any failure within a call or contract creation will not remove the target address of the failing*CALL
orCREATE*
from thetouched_addresses
set. Some tricky edge cases:- For
*CALL
, if the call fails for exceeding the maximum call depth or attempting to send more value than the balance of the current address, the target address remains in thetouched_addresses
set. - For
CREATE*
, if the contract creation fails for exceeding the maximum call depth or attempting to send more value than the balance of the current address, the address of the created contract does NOT remain in thetouched_addresses
set. - If a
CREATE*
operation fails for attempting to deploy a contract to a non-empty account, the address of the created contract remains in thetouched_addresses
set.
- For
EIP-2930 introduced an optional access list that can be included as part of a transaction.
This access list allows elements to be added to the touched_addresses
and touched_storage_slots
access sets before execution of a transaction begins.
The cost for doing so is 2400
gas for each address added to touched_addresses
and 1900
gas for each (address, storage_key)
pair added to touched_storage_slots
.
This cost is charged at the same time as intrinsic gas.
Important Notes:
- No
(ADDR, storage_key)
pair can be added totouched_storage_slots
without also addingADDR
totouched_addresses
. - The access list may contain duplicates. The addition of a duplicate item to one of the access sets is a no-op, but the cost of addition is still charged.
- Providing an access list with a transaction can yield a modest discount for each unique access, but this is not always the case. See @fvictorio/gas-costs-after-berlin for a more complete discussion.
Originally intended to provide incentive for clearing unused state, the total gas_refund
is tracked throughout the execution of a transaction.
As of EIP-3529, SSTORE
is the only operation that potentially provides a gas refund.
The maximum refund for a transaction is capped at 1/5th the gas consumed for the entire transaction.
refund_amt := min(gas_refund, tx.gas_consumed // 5)
The gas consumed includes the intrinsic gas, the cost of pre-populating the access sets, and the cost of any code execution.
When a transaction is finalized, the gas used by the transaction is decreased by refund_amt
.
This effectively reimburses refund_amt * tx.gasprice
to tx.origin
, but it has the added effect of decreasing the impact of the transaction on the total gas consumed in the block (for purposes of determining the block gas limit).
Because the gas refund is not applied until the end of a transaction, a nonzero refund will not affect whether or not a transaction results in an OUT_OF_GAS
exception.
Terms:
byte_len_exponent
: the number of bytes in the exponent (exponent isb
in the stack representation)
Gas Calculation:
gas_cost = 10 + 50 * byte_len_exponent
Terms:
data_size
: size of the message to hash in bytes (len
in the stack representation)data_size_words = (data_size + 31) // 32
: number of (32-byte) words in the message to hashmem_expansion_cost
: the cost of any memory expansion required (see A0-1)
Gas Calculation:
gas_cost = 30 + 6 * data_size_words + mem_expansion_cost
The following applies for the operations CALLDATACOPY
, CODECOPY
, and RETURNDATACOPY
(not EXTCODECOPY
).
Terms:
data_size
: size of the data to copy in bytes (len
in the stack representation)data_size_words = (data_size + 31) // 32
: number of (32-byte) words in the data to copymem_expansion_cost
: the cost of any memory expansion required (see A0-1)
Gas Calculation:
gas_cost = 3 + 3 * data_size_words + mem_expansion_cost
Terms:
target_addr
: the address to copy code from (addr
in the stack representation)access_cost
: The cost of accessing a warm vs. cold account (see A0-2)access_cost = 100
iftarget_addr
intouched_addresses
(warm access)access_cost = 2600
iftarget_addr
not intouched_addresses
(cold access)
data_size
: size of the data to copy in bytes (len
in the stack representation)data_size_words = (data_size + 31) // 32
: number of (32-byte) words in the data to copymem_expansion_cost
: the cost of any memory expansion required (see A0-1)
Gas Calculation:
gas_cost = access_cost + 3 * data_size_words + mem_expansion_cost
The opcodes BALANCE
, EXTCODESIZE
, EXTCODEHASH
have the same pricing function based on making a single account access.
See A0-2 for details on EIP-2929 and touched_addresses
.
Terms:
target_addr
: the address of interest (addr
in the opcode stack representations)
Gas Calculation:
gas_cost = 100
iftarget_addr
intouched_addresses
(warm access)gas_cost = 2600
iftarget_addr
not intouched_addresses
(cold access)
See A0-2 for details on EIP-2929 and touched_storage_slots
.
Terms:
context_addr
: the address of the current execution context (i.e. whatADDRESS
would put on the stack)target_storage_key
: The 32-byte storage index to load from (key
in the stack representation)
Gas Calculation:
gas_cost = 100
if(context_addr, target_storage_key)
intouched_storage_slots
(warm access)gas_cost = 2100
if(context_addr, target_storage_key)
not intouched_storage_slots
(cold access)
This gets messy. See EIP-2200, activated in the Istanbul hardfork.
The cost of an SSTORE
operation is dependent on the existing value and the value to be stored:
- Zero vs. nonzero values - storing nonzero values is more costly than storing zero
- The current value of the slot vs. the value to store - changing the value of a slot is more costly than not changing it
- "Dirty" vs. "clean" slot - changing a slot that has not yet been changed within the current execution context is more costly than changing a slot that has already been changed
The cost is also dependent on whether or not the targeted storage slot has already been accessed within the same transaction.
See A0-2 for details on EIP-2929 and touched_storage_slots
.
Terms:
context_addr
: the address of the current execution context (i.e. whatADDRESS
would put on the stack)target_storage_key
: The 32-byte storage index to store to (key
in the stack representation)orig_val
: the value of the storage slot if the current transaction is revertedcurrent_val
: the value of the storage slot immediately before thesstore
op in questionnew_val
: the value of the storage slot immediately after thesstore
op in question
Gas Calculation:
gas_cost = 0
gas_refund = 0
- If
gas_left <= 2300
:throw OUT_OF_GAS_ERROR
(can notsstore
with < 2300 gas for backwards compatibility)
- If
(context_addr, target_storage_key)
not intouched_storage_slots
(cold access):gas_cost += 2100
- If
new_val == current_val
(no-op):gas_cost += 100
- Else
new_val != current_val
:- If
current_val == orig_val
("clean slot", not yet updated in current execution context):- If
orig_val == 0
(slot started zero, currently still zero, now being changed to nonzero):gas_cost += 20000
- Else
orig_val != 0
(slot started nonzero, currently still same nonzero value, now being changed):gas_cost += 2900
and update the refund as follows..- If
new_val == 0
(the value to store is 0):gas_refund += 4800
- If
- Else
current_val != orig_val
("dirty slot", already updated in current execution context):gas_cost += 100
and update the refund as follows..- If
orig_val != 0
(execution context started with a nonzero value in slot):- If
current_val == 0
(slot started nonzero, currently zero, now being changed to nonzero):gas_refund -= 4800
- Else if
new_val == 0
(slot started nonzero, currently still nonzero, now being changed to zero):gas_refund += 4800
- If
- If
new_val == orig_val
(slot is reset to the value it started with):- If
orig_val == 0
(slot started zero, currently nonzero, now being reset to zero):gas_refund += 19900
- Else
orig_val != 0
(slot started nonzero, currently different nonzero value, now reset to orig. nonzero value):gas_refund += 2800
- If
- If
Note that for LOG*
operations gas is paid per byte of data (not per word).
Terms:
num_topics
: the * of the LOG* op. e.g. LOG0 hasnum_topics = 0
, LOG4 hasnum_topics = 4
data_size
: size of the data to log in bytes (len
in the stack representation).mem_expansion_cost
: the cost of any memory expansion required (see A0-1)
Gas Calculation:
gas_cost = 375 + 375 * num_topics + 8 * data_size + mem_expansion_cost
Common Terms:
mem_expansion_cost
: the cost of any memory expansion required (see A0-1)code_deposit_cost
: the per-byte cost incurred for storing the deployed code (see A9-F).
Gas Calculation:
gas_cost = 32000 + mem_expansion_cost + code_deposit_cost
CREATE2
incurs an additional dynamic cost over CREATE
because of the need to hash the init code.
Terms:
data_size
: size of the init code in bytes (len
in the stack representation)data_size_words = (data_size + 31) // 32
: number of (32-byte) words in the init code
Gas Calculation:
gas_cost = 32000 + 6 * data_size_words + mem_expansion_cost + code_deposit_cost
In addition to the static and dynamic cost of the CREATE
and CREATE2
operations, a per-byte cost is charged for storing the returned runtime code.
Unlike the static and dynamic costs of the opcodes, this cost is not applied until after the execution of the initialization code halts.
Terms:
returned_code_size
: the length of the returned runtime code
Gas Calculation:
code_deposit_cost = 200 * returned_code_size
A note related to the code deposit step of contract creation:
As of EIP-3541, any code returned from a contract creation (i.e. what would become the deployed contract code), results in an exceptional abort of the entire contract creation if the code's first byte is 0xEF
.
Gas costs for CALL
, CALLCODE
, DELEGATECALL
, and STATICCALL
operations.
A big piece of the gas calculation for these operations is determining the gas to send along with the call.
There's a good chance that you are primarily interested in the base_cost
and can ignore this additional calculation, because the gas_sent_with_call
is consumed in the context of the called contract, and the unconsumed gas is returned.
If not, see the gas_sent_with_call
section.
Similar to selfdestruct, CALL
incurs an additional cost if it forces an account to be added to the state trie by sending a nonzero amount of eth to an address that was previously empty.
"Empty", in this case is defined according to EIP-161 (balance == nonce == code == 0x
).
Common Terms:
call_value
: the value sent with the call (val
in the stack representation)target_addr
: the recipient of the call (addr
in the stack representation)access_cost
: The cost of accessing a warm vs. cold account (see A0-2)access_cost = 100
iftarget_addr
intouched_addresses
(warm access)access_cost = 2600
iftarget_addr
not intouched_addresses
(cold access)
mem_expansion_cost
: the cost of any memory expansion required (see A0-1)gas_sent_with_call
: the gas ultimately sent with the call
Gas Calculation:
base_gas = access_cost + mem_expansion_cost
- If
call_value > 0
(sending value with call):base_gas += 9000
- If
is_empty(target_addr)
(forcing a new account to be created in the state trie):base_gas += 25000
Calculate the gas_sent_with_call
below.
And the final cost of the operation:
gas_cost = base_gas + gas_sent_with_call
Gas Calculation:
base_gas = access_cost + mem_expansion_cost
- If
call_value > 0
(sending value with call):base_gas += 9000
Calculate the gas_sent_with_call
below.
And the final cost of the operation:
gas_cost = base_gas + gas_sent_with_call
Gas Calculation:
base_gas = access_cost + mem_expansion_cost
Calculate the gas_sent_with_call
below.
And the final cost of the operation:
gas_cost = base_gas + gas_sent_with_call
Gas Calculation:
base_gas = access_cost + mem_expansion_cost
Calculate the gas_sent_with_call
below.
And the final cost of the operation:
gas_cost = base_gas + gas_sent_with_call
In addition to the base cost of executing the operation, CALL
, CALLCODE
, DELEGATECALL
, and STATICCALL
need to determine how much gas to send along with the call.
Much of the complexity here comes from a backward-compatible change made in EIP-150.
Here's an overview of why this calculation is used:
EIP-150 increased the base_cost
of the CALL
opcode from 40 to 700 gas, but most contracts in use at the time were sending available_gas - 40
with every call.
So, when base_cost
increased, these contracts were suddenly trying to send more gas than they had left (requested_gas > remaining_gas
).
To avoid breaking these contracts, if the requested_gas
is more than remaining_gas
, we send all_but_one_64th
of remaining_gas
instead of trying to send requested_gas
, which would result in an OUT_OF_GAS_ERROR
.
Terms:
base_gas
: the cost of the operation before taking into account the gas that should be sent along with the call. See AA for this calculation.available_gas
: the gas remaining in the current execution context immediately before the execution of the opcoderemaining_gas
: the gas remaining after deductingbase_cost
of the op but before deductinggas_sent_with_call
requested_gas
: the gas requested to be sent with the call (gas
in the stack representation)all_but_one_64th
: All but floor(1/64) of the remaining gasgas_sent_with_call
: the gas ultimately sent with the call
Gas Calculation:
remaining_gas = available_gas - base_gas
all_but_one_64th = remaining_gas - (remaining_gas // 64)
gas_sent_with_call = min(requested_gas, all_but_one_64th)
Any portion of gas_sent_with_call
that is not used by the recipient of the call is refunded to the caller after the call returns. Also, if call_value > 0
, a 2300 gas stipend is added to the amount of gas included in the call, but not to the cost of making the call.
The gas cost of a SELFDESTRUCT
operation is dependent on whether or not the operation results in a new account being added to the state trie.
If a nonzero amount of eth is sent to an address that was previously empty, an additional cost is incurred.
"Empty", in this case is defined according to EIP-161 (balance == nonce == code == 0x
).
The cost also increases if the operation requires a cold access of the recipient address.
See A0-2 for details on EIP-2929 and touched_addresses
.
Terms:
target_addr
: the recipient of the self-destructing contract's funds (addr
in the stack representation)context_addr
: the address of the current execution context (i.e. whatADDRESS
would put on the stack)
Gas Calculation:
gas_cost = 5000
: base cost- If
balance(context_addr) > 0 && is_empty(target_addr)
(sending funds to a previously empty address):gas_cost += 25000
- If
target_addr
not intouched_addresses
(cold access):gas_cost += 2600
On execution of any invalid operation, whether the designated INVALID
opcode or simply an undefined opcode, all remaining gas is consumed and the state is reverted to the point immediately prior to the beginning of the current execution context.