Gas costs before the Berlin hard fork Each opcode executed by the EVM has an associated gas cost. Most of these costs are fixed: PUSH1 always costs 3 units of gas, MUL costs 5, etc. Others vary: for example, the opcode cost of SHA3 depends on the size of its input. We will mainly discuss the opcodes SLOAD and SSTORE, as they are the most affected by the Berlin hard fork. We will later discuss address-specific opcodes, such as all EXT* and CALL*, as their gas costs also changed. Gas costs for SLOAD before BerlinBefore EIP-2929, the gas cost of SLOAD was simple: it always consumed 800 gas. So there is nothing to say (yet). Gas cost of SSTORE before BerlinSSTORE is probably the most complex opcode in terms of gas cost, as its cost depends on things like the current value of the storage slot, the new value, and whether it has been modified before. We will only analyze a few cases to get a basic understanding; if you want to learn more, read the EIP link at the end of the article.
The details of this part are not interesting, the important thing is that SSTORE is expensive, and its cost depends on several factors. Gas consumption after EIP-2929EIP-2929 affects the gas consumption of all the above opcodes. But before we dive into these changes, we need to talk about an important concept introduced by this EIP: accessed addresses and accessed storage keys. An address or a storage key is considered "accessed" if it has been "used" in a previous transaction. For example, when you CALL another contract, the address of that contract is marked as "accessed". Similarly, when you SLOAD or SSTORE some slots, the rest of the transaction is considered accessed. It doesn't matter which opcode executes it: if a SLOAD reads a slot, the following SLOAD and SSTORE will both be considered accessed. It is worth noting here that storage keys are "built into" some addresses. As this EIP explains: "While executing transactions, maintain a set of accessed_addresses: Set[Address] and accessed_storage_keys: Set[Tuple[Address, Bytes32]]" That is, when we say a storage slot is accessed, we actually say a pair (address, storageKey) is accessed. Next, let’s talk about the new gas consumption. SLOAD after BerlinBefore the Berlin hard fork, SLOAD had a fixed cost of 800 gas. Now, it depends on whether the storage slot has been accessed. If it has not been accessed, the gas cost is 2100; if it has been accessed, it is 100. Therefore, if the slot is in the list of accessed storage keys, SLOAD's gas cost will be less than 2000. SSTORE after BerlinLet’s revisit the previous SSTORE example in the context of EIP-2929: If the value of a storage slot changes from 0 to 1 (or any non-zero value), the gas cost is:
If the value of the storage slot changes from 1 to 2 (or any other non-zero value), the gas consumption is:
If the value of the storage slot changes from 1 (or any non-zero value) to 0, the gas cost is the same as the previous case, plus a refund. If the value of the storage slot has been modified in the same transaction before, the gas consumption of all subsequent SSTOREs will be 100. As you can see, if the slot that the SSTORE is modifying has been accessed before, the first SSTORE consumes less than 2100 gas. SummarizeThe following table compares the above values: Note that in the last line there is no need to talk about whether the slot has been accessed, because if it has been written to before, then it has been accessed. EIP-2930: Optional Access List TransactionsThe other EIP we mentioned at the beginning was EIP-2930. This EIP adds a new transaction type that can include an access list in the transaction. This means that you can declare in advance which addresses and slots should be considered visited before the transaction execution begins. For example, a SLOAD to an unvisited slot costs 2100 gas, but if the slot is added to the transaction access list, the same opcode only costs 100 gas. But if already accessed addresses or storage keys cost less gas, does that mean we can just add everything to the transaction access list to reduce gas costs? Great! No more gas fees! However, this is not entirely true, because you still need to pay gas fees every time you add an address or storage key. Let's look at an example. Suppose we are sending a transaction to contract A, the access list may be as follows: accessList: [{ address: "", storageKeys: [ "0x000000000000000000000000000000000000000000000000000000000000000" ] }] If we send a transaction with this access list attached, the first opcode to use slot0x0 is SLOAD, which costs 100 gas instead of 2100. That's a reduction of 2000 gas. But each time we add a storage key to the access list of a transaction, it costs 1900 gas. So we only saved 100 gas. (If the first opcode to access the slot was SSTORE instead of SLOAD, we would save 2100 gas, which means we save 200 gas in total if we consider the cost of the storage key.) Does this mean that we can save gas as long as we use transaction access lists? No, because we also need to pay for adding addresses to the access list (i.e. " " ) of gas.Visited addressesSo far, we have only discussed the opcodes SLOAD and SSTORE, but these are not the only opcodes that have changed with the Berlin upgrade. For example, the opcode CALL previously had a fixed cost of 700. But after EIP-2929, if the address is not in the access list, its cost has become 2600 gas, and if it is, it is 100 gas. Also, like accessed storage keys, no matter what opcode was accessed before (for example, if EXTCODESIZE is called for the first time, then this opcode will consume 2600 gas, and any subsequent EXTCODESIZE, CALL, or STATICCALL using the same address will only consume 100 gas). How does this affect transactions with access lists? For example, if we send a transaction to contract A, and that contract calls another contract B, we can add a list like this: accessList: [{ address: "", storageKeys: [] }] We will need to pay 2400 gas to add this access list to the transaction, but then the first opcode that uses B's address will only cost 100 gas, not 2600. So we saved 100 gas by doing this. If B uses its storage in some way, and we know which keys are used, we can also add them to the access list, saving 100-200 gas per key (depending on whether your first opcode is SLOAD or SSTORE). But why are we talking about another contract? The contract we are calling? Why not perform these operations on this contract? accessList: [ {address: "", storageKeys: []}, {address: "", storageKeys: []}, ] We can do this, but it is not cost-effective because EIP-2929 clearly stipulates that the address of the contract being called (ie tx.to) will be added to the accessed_addresses list by default. Therefore, we do not need to pay the extra 2400 gas. Let's analyze the previous example again: accessList: [{ address: "", storageKeys: [ "0x000000000000000000000000000000000000000000000000000000000000000" ] }] Unless we want to add more storage keys, this is actually wasteful. If we assume that SLOAD always uses the storage key first, then we need at least 24 storage keys to break even. As you can imagine, doing analysis and manually creating an access list isn't that much fun. Fortunately, there is a better way. eth_createAccessList RPC methodGeth (starting from version 1.10.2) has added a new eth_createAccessListRPC method that you can use to generate access lists. Its usage is similar to eth_estimateGas, but instead of returning a gas estimate, it returns a result like this: { "accessList": [ { "address": "0xb0ee076d7779a6ce152283f009f4c32b5f88756c", "storageKeys": [ "0x000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001" ] } ], "gasUsed": "0x8496" } That is, it gives you the list of addresses and storage keys that the transaction will use, plus the gas cost if the access list was included. (Like eth_estimateGas, this is an estimate, and this list may change when the transaction is actually mined.) However, this does not mean that the gas cost will be lower than sending the same transaction without the access list! I guess we'll figure out the right way to use it over time, but my guess is that the pseudo code would be something like this: let gasEstimation = estimateGas(tx) let { accessList, gasUsed } = createAccessList(tx) if (gasUsed > gasEstimation) { delete accessList[tx.to] } tx.accessList = accessList; sendTransaction(tx) Loosen the contractIt is worth mentioning that the main purpose of access lists is not to use gas. As explained in the EIP: “It mitigates the risk of contract breakage introduced by EIP-2929, because transactions can specify in advance the accounts and storage slots that the transaction plans to access and pay in advance; ultimately, in actual execution, the opcodes SLOAD and EXT* only consume 100 gas: this low gas consumption can not only prevent breakage caused by this EIP, but also "loosen" any contracts restricted by EIP-1884. ” This means that if a contract makes assumptions about the cost of performing a transaction, an increase in gas costs may cause it to stop working. For example, a contract calling another contract like this someOtherContract.someFunction{gas: 34500}() will break because it assumes that someFunction will consume exactly 34500 gas. But if you add a reasonable access list, the contract will work again. Do your own testingIf you want to test it yourself, clone the repository, which contains multiple examples that can be run with Hardhat and geth. See the README for instructions. |
<<: Chia official answer: 20 questions you need to know before participating in Chia mining
>>: AMA Review | HECO Stars' Fantastic Fantasy Night Online Roundtable Forum
Moles are very common, because everyone has them ...
Xinjiang, Inner Mongolia, Qinghai, Yunnan, Sichua...
Traditional investors are always very cautious wh...
Physiognomy says: "The palm represents wealt...
The quality of a mole can be judged from many asp...
Moles sometimes appear in places that are not eas...
Coinify, a Danish blockchain (asset) payment serv...
In our lives, I believe every girl hopes to marry...
For women, eyebrows are very important. In additi...
A broken palm is a type of palm print that appear...
In fact, due to the differences in facial feature...
"When you join Alibaba, we don't promise...
Edan Yago is the CEO of Epiphyte, a company dedic...
In palmistry, the dense lines on our palms all hav...
As one of the traditional physiognomy techniques, ...