Decrease base cost of TLOAD/TSTORE
相关视频
正文
Abstract
Decrease the base cost of TLOAD/TSTORE while introducing a superlinear pricing model. This increases the efficiency of TLOAD/TSTORE for common use cases, while providing a pricing model to prevent DoS vectors.
Motivation
EIP-1153 introduces a new storage region, termed "transient storage". It behaves like storage (word-addressed and persists between call frames), but unlike storage it is wiped at the end of each transaction. During development of EIP-1153, the pricing was set to be the same as warm storage loads and stores. This was for two reasons: conceptual simplicity of the EIP, and it also addressed concerns about two related DoS vectors: being able to allocate too much transient storage, and the cost of rolling back state in the case of reverts.
One of the most important use cases that EIP-1153 enables is cheap reentrancy protection. In fact, if transient storage is cheap enough for the first few slots, reentrancy protection can be enabled by default at the language level without too much burden to users, while simultaneously preventing the largest—and most expensive—class of smart contract vulnerabilities.
Furthermore, it seems that transient storage is fundamentally overpriced. Its pricing does not interact with refunds, it only requires a new allocation on contract load (as opposed to memory, which requires a fresh allocation on every call), and has no interaction with the physical database.
This EIP proposes a pricing model which charges additional gas per allocation, which is cheaper for common cases (fewer than ~95 slots are written per contract), while making DoS using transient storage prohibitively expensive.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
The gas cost for TLOAD
is proposed to be 5 gas. The gas cost for TSTORE
is proposed to be 8 gas + expansion_cost
, where expansion_cost
is calculated as 1 gas * len(transient storage mapping)
if the key is not yet in the transient storage mapping, and otherwise 0 gas.
In pseudo-code:
G_LOW = 5 G_MID = 8 SLOPE = 1 def gas_tload(_key): return G_LOW def gas_tstore(key, transient_mapping): cost = G_MID if key not in transient_mapping: cost += SLOPE * transient_mapping.size() return cost
Rationale
Gas
In benchmarking, TLOAD
was found to cost a similar amount of CPU time as MUL
, while TSTORE
was found to cost about 1.5x that. The values G_low
and G_mid
were therefore chosen for TLOAD
and TSTORE
, respectively.
Backwards Compatibility
No backward compatibility issues found.
Security Considerations
The maximum number of transient slots which can be allocated on a single contract given 30m gas is approximately 7,739 (solution to x(x-1)/2*1 + 8*x = 30_000_000
), which totals 248KB.
The maximum number of transient slots which can be allocated in a transaction if you use the strategy of calling new contracts (which each are designed to maximize transient storage allocation) once the cost of TSTORE
is more than the cost of calling a cold contract (2600 gas), can be solved for as follows:
solve for SLOPE * <num slots> == 2600, => num_slots == 2600
gas_used_by_contract = 2600 + SLOPE * num_slots * (num_slots - 1) / 2 + G_MID * num_slots == 3402100
block_gas_limit = 30_000_000
num_calls_per_txn = block_gas_limit // gas_used_by_contract ~= 8.8
max_transient_slots = num_calls_per_txn * num_slots == 22927
Thus, the maximum number of transient slots which can be allocated in a single transaction with this method is roughly 23,000, which totals 736KB. Compared to the current gas schedule (which allows allocating approximately 30_000_000 / 100 * 32 == 9.6MB
worth of memory), this is a net reduction in the total memory which can be allocated on a client using transient storage, so this EIP presents a stronger bound on the resources which can be used by transient storage. As a comparison point, the total amount of memory which can be allocated on a client by SSTORE
s in a given transaction is 30_000_000 / 20_000 * 32
, or 48KB.
Note that this cap scales linearly with the gas limit, which is a useful property when considering future block gas limit increases.
Copyright
Copyright and related rights waived via CC0.