Skip to content

Instantly share code, notes, and snippets.

@holiman
Last active October 6, 2022 06:31
Show Gist options
  • Save holiman/460f952716a74eeb9ab358bb1836d821 to your computer and use it in GitHub Desktop.
Save holiman/460f952716a74eeb9ab358bb1836d821 to your computer and use it in GitHub Desktop.

Current (Istanbul) costs

With Istanbul rules, EIP-2200: https://eips.ethereum.org/EIPS/eip-2200#test-cases, the following gas usages apply for the various scenarions below:

Code Used Gas Refund Original 1st 2nd 3rd Effective gas (after refund)
0x60006000556000600055 1612 0 0 0 0 1612
0x60006000556001600055 20812 0 0 0 1 20812
0x60016000556000600055 20812 19200 0 1 0 1612
0x60016000556002600055 20812 0 0 1 2 20812
0x60016000556001600055 20812 0 0 1 1 20812
0x60006000556000600055 5812 15000 1 0 0 -9188
0x60006000556001600055 5812 4200 1 0 1 1612
0x60006000556002600055 5812 0 1 0 2 5812
0x60026000556000600055 5812 15000 1 2 0 -9188
0x60026000556003600055 5812 0 1 2 3 5812
0x60026000556001600055 5812 4200 1 2 1 1612
0x60026000556002600055 5812 0 1 2 2 5812
0x60016000556000600055 5812 15000 1 1 0 -9188
0x60016000556002600055 5812 0 1 1 2 5812
0x60016000556001600055 1612 0 1 1 1 1612
0x600160005560006000556001600055 40818 19200 0 1 0 1 21618
0x600060005560016000556000600055 10818 19200 1 0 1 0 -8382

Berlin costs

With Berlin, and EIP-2929, the gas costs changes. Note, there is a difference between 'hot' and 'cold' slots. The following table is generated based on the slot in question (0) being 'cold'.

Code Used Gas Refund Original 1st 2nd 3rd Effective gas (after refund)
0x60006000556000600055 2312 0 0 0 0 2312
0x60006000556001600055 22212 0 0 0 1 22212
0x60016000556000600055 22212 19900 0 1 0 2312
0x60016000556002600055 22212 0 0 1 2 22212
0x60016000556001600055 22212 0 0 1 1 22212
0x60006000556000600055 5112 15000 1 0 0 -9888
0x60006000556001600055 5112 2800 1 0 1 2312
0x60006000556002600055 5112 0 1 0 2 5112
0x60026000556000600055 5112 15000 1 2 0 -9888
0x60026000556003600055 5112 0 1 2 3 5112
0x60026000556001600055 5112 2800 1 2 1 2312
0x60026000556002600055 5112 0 1 2 2 5112
0x60016000556000600055 5112 15000 1 1 0 -9888
0x60016000556002600055 5112 0 1 1 2 5112
0x60016000556001600055 2312 0 1 1 1 2312
0x600160005560006000556001600055 42218 19900 0 1 0 1 22318
0x600060005560016000556000600055 8018 17800 1 0 1 0 -9782

If the slot is already 'warm', this is the corresponding table:

Code Used Gas Refund Original 1st 2nd 3rd Effective gas (after refund)
0x60006000556000600055 212 0 0 0 0 212
0x60006000556001600055 20112 0 0 0 1 20112
0x60016000556000600055 20112 19900 0 1 0 212
0x60016000556002600055 20112 0 0 1 2 20112
0x60016000556001600055 20112 0 0 1 1 20112
0x60006000556000600055 3012 15000 1 0 0 -11988
0x60006000556001600055 3012 2800 1 0 1 212
0x60006000556002600055 3012 0 1 0 2 3012
0x60026000556000600055 3012 15000 1 2 0 -11988
0x60026000556003600055 3012 0 1 2 3 3012
0x60026000556001600055 3012 2800 1 2 1 212
0x60026000556002600055 3012 0 1 2 2 3012
0x60016000556000600055 3012 15000 1 1 0 -11988
0x60016000556002600055 3012 0 1 1 2 3012
0x60016000556001600055 212 0 1 1 1 212
0x600160005560006000556001600055 40118 19900 0 1 0 1 20218
0x600060005560016000556000600055 5918 17800 1 0 1 0 -11882

Without refunds

If refunds were to be removed, this would be the comparative table

Code Original 1st 2nd 3rd Istanbul Berlin (cold) Berlin (hot) Berlin (hot)+norefund
0x60006000556000600055 0 0 0 1612 2312 212 212
0x60006000556001600055 0 0 1 20812 22212 20112 20112
0x60016000556000600055 0 1 0 1612 2312 212 20112
0x60016000556002600055 0 1 2 20812 22212 20112 20112
0x60016000556001600055 0 1 1 20812 22212 20112 20112
0x60006000556000600055 1 0 0 -9188 -9888 -11988 3012
0x60006000556001600055 1 0 1 1612 2312 212 3012
0x60006000556002600055 1 0 2 5812 5112 3012 3012
0x60026000556000600055 1 2 0 -9188 -9888 -11988 3012
0x60026000556003600055 1 2 3 5812 5112 3012 3012
0x60026000556001600055 1 2 1 1612 2312 212 3012
0x60026000556002600055 1 2 2 5812 5112 3012 3012
0x60016000556000600055 1 1 0 -9188 -9888 -11988 3012
0x60016000556002600055 1 1 2 5812 5112 3012 3012
0x60016000556001600055 1 1 1 1612 2312 212 212
0x600160005560006000556001600055 0 1 0 1 21618 22318 20218 40118
0x600060005560016000556000600055 1 0 1 0 -8382 -9782 -11882 5918

In partcular, the following cases become more expensive:

  • '0-1-0' goes from 10K to 20K,
  • '0-1-0-1' goes from 21K to 40K,

For these cases, a better scheme under the no-refund rule would be to use non-zero slots, e.g. '1-2-1' and thus wind up with 3K gas.

Note: In reality, there are never a negative gas cost, since the refund is capped at 0.5 * gasUsed. However, these tables show the negative values, since in a more real-world scenarion would likely spend the extra gas on other operations.'

@holiman
Copy link
Author

holiman commented Feb 23, 2021

Full implementation, minus some boilerplate code for actually defining the fork:

diff --git a/core/state_transition.go b/core/state_transition.go
index a8d1936c1f..7efe2ad888 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -262,7 +262,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
 		st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
 		ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
 	}
-	st.refundGas()
+	refundsEnabled := !st.evm.ChainConfig().IsRefundDisabledFork(st.evm.Context.BlockNumber)
+	st.refundGas(refundsEnabled)
 	st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
 
 	return &ExecutionResult{
@@ -272,13 +273,15 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
 	}, nil
 }
 
-func (st *StateTransition) refundGas() {
+func (st *StateTransition) refundGas(refundsEnabled bool) {
 	// Apply refund counter, capped to half of the used gas.
-	refund := st.gasUsed() / 2
-	if refund > st.state.GetRefund() {
-		refund = st.state.GetRefund()
+	if refundsEnabled {
+		refund := st.gasUsed() / 2
+		if refund > st.state.GetRefund() {
+			refund = st.state.GetRefund()
+		}
+		st.gas += refund
 	}
-	st.gas += refund
 
 	// Return ETH for remaining gas, exchanged at the original rate.
 	remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment