# EVM cost relationships ## Motivation To establish the granular steps of complex instructions on the EVM. These steps can then be applied across multiple instructions, providing a better base for repricing and discussions. The complex instructions here are those outside of computation and memory: storage, state and transaction/call frame instructions. **Question: are cost determined based on purely the specification, purely an optimised client, or some combination of both?** **Question: are cost determined based on worst-case, best-case or avg-case? If avg-case, are there some overhead charges added for worst-case?** ## Background Based on Istanbul. Current costs (from YP): ``` Zero = 0, // 0, Zero Base, // 2, Quick VeryLow, // 3, Fastest Low, // 5, Fast Mid, // 8, Mid High, // 10, Slow ``` Current costs (from Solidity's libevmasm): ``` extCodeGas: 700 balanceGas: 700 sloadGas: 800 sstoreSetGas: 20000 sstoreResetGas: 5000 sstoreRefundGas: 15000 createGas: 32000 callGas: 700 callStipendGas: 2300 callValueTransferGas: 9000 callNewAccountGas: 25000 selfdestructGas: 5000 selfdestructRefundGas: 24000 memoryGas: 3 copyGas: 3 createDataGas: 200 txGas: 21000 txCreateGas: 53000 txDataZeroGas: 4 txDataNonZeroGas: 16 keccak256Gas: 30 keccak256WordGas: 6 ``` ## Cost primitives `QUERY_TX` = 2 <small>(As currently.)</small> `QUERY_CONSTANT_FRAME` = 2 <small>(As currently.)</small> `QUERY_FRAME` = 2 <small>(As currently.)</small> `LOAD_ACCOUNT` = 700 <small>(As currently.)</small> `LOAD_CODE` = 200 <small>**(Newly introduced.)**</small> `COPY_PER_WORD` = 3 <small>(As currently.)</small> `CREATE_CALLFRAME` = 100 <small>**(Newly introduced.)**</small> `CALL_STIPEND` = 2300 <small>(As currently.)</small> `CREATE_ACCOUNT` = 25000 <small>(As currently, `callNewAccountGas` above.)</small> `CODE_STORE_PER_WORD` = 200 <small>(As currently, `createDataGas` above.)</small> `MODIFY_ACCOUNT` = 5000 <small>**(Newly introduced.)**</small> We define the following helpers: 1. `memoryExtension(offset)` -- calculates the memory extension cost 2. `copyPerWord(size)`: `ceil(len / 32) * COPY_PER_WORD` ## Instructions ### Complex #### KECCAK256 Cost: `keccak256Gas + ceil(len / 32) * keccak256WordGas` ### Transaction/blocks state #### ORIGIN Cost: `QUERY_TX` #### GASPRICE Cost: `QUERY_TX` #### BLOCKHASH TBD #### COINBASE Cost: `QUERY_TX` #### TIMESTAMP Cost: `QUERY_TX` #### NUMBER Cost: `QUERY_TX` #### DIFFICULTY Cost: `QUERY_TX` #### GASLIMIT Cost: `QUERY_TX` #### CHAINID Cost: `QUERY_TX` ### Call frame state (constants) #### CALLER Cost: `QUERY_CONSTANT_FRAME` #### CALLVALUE Cost: `QUERY_CONSTANT_FRAME` #### CALLDATALOAD Cost: `QUERY_CONSTANT_FRAME` *Currently this is set at "verylow" or 3 gas.* #### CALLDATASIZE Cost: `QUERY_CONSTANT_FRAME` #### CALLDATACOPY Cost: `QUERY_CONSTANT_FRAME (+ COPY_PER_WORD + MEM_EXTENSION)` *Currently this is set at "verylow" or 3 gas.* #### RETURNDATASIZE Cost: `QUERY_CONSTANT_FRAME` #### RETURNDATACOPY Cost: `QUERY_CONSTANT_FRAME (+ COPY_PER_WORD + MEM_EXTENSION)` *Currently this is set at "verylow" or 3 gas.* #### CODESIZE Cost: `QUERY_CONSTANT_FRAME` #### CODECOPY Cost: `QUERY_CONSTANT_FRAME (+ COPY_PER_WORD + MEM_EXTENSION)` *Currently this is set at "verylow" or 3 gas.* ### Call frame state (ephemeral) #### MSIZE Cost: `QUERY_FRAME` #### GAS Cost: `QUERY_FRAME` #### SELFBALANCE Cost: `QUERY_FRAME` *Currently this is set at "low" or 5 gas.* ### Other account state #### EXTBALANCE Cost: `LOAD_ACCOUNT` Rationale: the account contains the balance. #### EXTCODESIZE Cost: `LOAD_ACCOUNT + LOAD_CODE` Rationale: the account contains the code hash, but the code needs to be located from its own trie. #### EXTCODECOPY(address, dst, src, len) Cost: `LOAD_ACCOUNT + LOAD_CODE + copyPerWord(len) + memoryExtension(dst + len)` #### EXTCODEHASH Cost: `LOAD_ACCOUNT` Rationale: the account contains the code hash. #### CREATE Cost: `calculateAddress() + CREATE_ACCOUNT + CREATE_CALLFRAME + len(code) * CODE_STORE_PER_BYTE`, where 1. `calculateAddress` is defined as `keccak256Gas + keccak256WordGas`, since the address calculation is optimistically a single word and we ignore the overhead of RLP, 2. `CREATE_CALLFRAME` is here to account for execution of the initcode, 3. `code` refers to the code returned by executing `initcode`, where `initcode` refers to the code passed to `CREATE`. *Note: address calculation is `keccak256(rlp(sender, nonce))[:20]`* *Currently this is charge at a fixed value of `createGas`.* #### CREATE2 The same rules apply here as in `CREATE`, with the only exception that `calculateAddress` is as follows: `keccak256WordGas * (ceil(len(initcode) / 32) + 3)`. *Note: The extra 3 words are for the final round of hashing, which is not accounted for in EIP-1014. The EIP also omits `keccak256Gas`.* #### CALL Call has four different variants depending on input and account state: 1. Destination exists, no value passed: `LOAD_ACCOUNT + LOAD_CODE + CREATE_CALLFRAME` 2. Destination exists, value passed: `LOAD_ACCOUNT + LOAD_CODE + CALL_STIPEND + MODIFY_ACCOUNT + CREATE_CALLFRAME` 3. Destination does not exists, no value passed: `LOAD_ACCOUNT` (isn't this a noop ("only" a tree lookup) since the account is not presisted?) 4. Destination does not exists, value passed: `LOAD_ACCOUNT + CREATE_ACCOUNT + CALL_STIPEND + CREATE_CALLFRAME` *Currently this is set callGas + !!exists * callNewAccountGas + !!value * callValueTransferGas* *Currently in order to persist an account, need to send value, e.g. the total cost is callGas + callNewAccountGas + callValueTransferGas (34000).* #### CALLCODE Cost: `LOAD_ACCOUNT + LOAD_CODE + CREATE_CALLFRAME` TBD **Also consider value sending.** #### DELEGATECALL Cost: `LOAD_ACCOUNT + LOAD_CODE + CREATE_CALLFRAME` TBD If account does not exists, only `LOAD_ACCOUNT` is charged. #### STATICCALL Cost: `LOAD_ACCOUNT + LOAD_CODE + CREATE_CALLFRAME` TBD If account does not exists, only `LOAD_ACCOUNT` is charged. Special case: if destination is a precompile, `LOAD_CODE` doesn't need to apply. (EIP-2046) #### SELFDESTRUCT TBD ### Storage trie #### SSTORE ~~Cost: `SSTORE_COST + STATE_COST_PER_WORD`~~ See EIP-142. TBD #### SLOAD ~~Cost: `SLOAD_COST`~~ TBD ### Precompile (subset) #### SHA256 Cost: `sha256Gas + ceil(len(input)/32) * sha256WordGas`, where `sha256Gas` = 60 and `sha256WordGas` = 12. #### RIPEMD160 Cost: `ripemd160Gas + ceil(len(input)/32) * ripemd160WordGas`, where `ripemd160Gas` = 600 and `ripemd160WordGas` = 120. #### Identity Cost: `identityGas + ceil(len(input)/32) * identityWordGas`, where `identityGas` = 15 and `identityWordGas` = 3. ## Takeaways 1. `CREATE` is not accounting for the RLP and hashing. 2. `CREATE2` is not accounting for the final round of hashing. 3. `CALL` is too complex. 4. It seems that "call frame state" copying instructions have a 1 gas cost in addition to reading the state (3 gas vs 2 gas.) plus the per word cost. In comparison, the identity precompile has a base cost of 15 gas plus 3 per word. 5. Should `LOAD_ACCOUNT` charge for the avg-case or the worst-case? ## Appendix: Feedback `LOAD_CODE` has not been a significant factor due to the way the account trie and the code storage is handled. ## Appendix: Cost comparison **Numbers are not on sync with the formulas** Unfinished. (Assumes `LOAD_CODE` is 700, and `CREATE_CALLFRAME` is 200) | Opcodes | Istanbul | Proposed | |----------------------------|----------|----------| | EXTBALANCE | 700 | 700 | | CREATE (0 codesize) | 32000 | 25236 | | CREATE (max codesize) | 4947200 | 4940436 | | CREATE2 (0 codesize) | 32000 | 25248 | | CREATE2 (max codesize) | 4951838 | 4945056 | | CALL | 700 | 1500 | | CALL (new account) | 25700 | 26500 | | CALL (with value) | 9700 | 3800 | | CALL (new account + value) | 34700 | 28800 | | CALL (to self, EIP1380) | 700 | 100 | | STATICCALL (to precompile, EIP2046) | 700 | 100 | | SELFDESTRUCT | 5000 | |