GasBack: Optimizing Gas Costs in Time-Sensitive Ethereum Transactions
Ask your Ethereum developer friends: What factors contribute to how much gas is paid to a miner when a smart contract executes?
Most developers tend to quote a simple formula found in guides such as the Homestead documentation:
Total cost = gasUsed * gasPrice
Some experienced Solidity developers even memorize gas costs of various operations, including how gas costs have changed throughout various incarnations of the EVM. (This handy spreadsheet lists gas costs as of EIP 150.)
Ask them if that’s all to the story. Some developers will bring up the concept of startGas or the gas limit for the transaction. This is analogous to a finite size gas tank, and prevents infinite loops from running forever within smart contracts.
OK, great. Then ask, what else contributes to total gas paid in a transaction?
Most developers I’ve asked this follow-up question to become stumped. I even asked a fair number of really sharp minds at ConsenSys. Developers seem to have a mental model that each operation has a non-negative gas cost, and that a simple addition of each of the operations within a transaction leads to a total gasUsed which is then multiplied by the gasPrice, and that’s it. And, this is a useful first approximation. However, it’s not the entire picture — which leads me to a fun little story.
Birthing CryptoKitties
Some people began birthing CryptoKitties for profit during the initial frenzy in late 2017. Essentially, there’s a reward for initiating a birthing contract at a specific point in time. Those birthing CryptoKitties compete with each other to have their transactions included in a specific upcoming block (or as soon as possible after a given block number). The order of transactions within a block can also matter, since a kitty can only be birthed once. Since miners are generally incentivized to include transactions with the highest gas prices, this led to a surge in gas prices during the initial CryptoKitties craze-phase.
The CryptoKitties birthing game has two related constraints:
- Transactions are time-sensitive, where the first to execute after a given blocknumber “wins”.
- Profits are highly influenced by gasPrice. If set too low, other transactions are run before yours. If set too high, playing the game becomes an unprofitable, money-losing proposition. Thus, profit margins become squeezed.
When these types of constraints are in place, what are some smart things a developer can do to compete?
- Bundle multiple births in the same transaction when possible. That way, you lower your per-birthing costs by paying for the contract overhead only once.
- Comb through your smart contracts and tweak all of your code to attempt to use the least amount of gas possible by using sets of operations with the lowest gas costs. Perhaps you even drop down to inline assembly within your Solidity code, to produce the tightest possible EVM bytecode.
- Collude with some powerful mining interests to share profits. (Some claim to have seen evidence of this kind of behavior during certain high-profile ICOs, when whales *really* wanted to get their early token purchases locked in.)
It turns out there’s another tactic that in early 2018 doesn’t seem to be widely known.
RTFM for Fun and Profit
RTFM has long been a useful skill. Some brave and determined souls might even seek to read and understand the entire Ethereum Yellow Paper.
Quoting section 6.1: “Finally there is Ar, the refund balance, increased through using the SSTORE instruction in order to reset contract storage to zero from some non-zero value. Though not immediately refunded, it is allowed to partially offset the total execution costs.”
Quoting section 6.2: “After the message call or contract creation is processed, the state is finalised by determining the amount to be refunded, g ∗ from the remaining gas, g 0 , plus some allowance from the refund counter, to the sender at the original rate. (70) g ∗ ≡ g 0 + min{ j Tg − g 0 2 k , Ar} The total refundable amount is the legitimately remaining gas g 0 , added to Ar, with the latter component being capped up to a maximum of half (rounded down) of the total amount used Tg − g 0 .”
In Appendix G, the Fee Schedule, the concept of the gas refund, or Rsclear, is again mentioned.
The intent of this “refund” notion is to reward the sender of the transaction for freeing up space on the Ethereum blockchain, by reducing the gas costs of the transaction by up to half. Note that this reward is essentially a disincentive for miners, who would have otherwise ended up with the refunded gas.
While not explicitly stated in the Yellow Paper, also note that the gasPrice when setting non-zero storage values might be different when subsequently setting a storage value from non-zero to zero. And that is a key insight.
What does this mean?
This means that clever developers have another tactic at their disposal. It essentially goes something like this:
- At some point in time, when you’re in no rush and can use a (very) low gasPrice, set some storage to non-zero.
- Later, during a time-critical operation when gasPrice has to be set high to compete with others to be the first to run a transaction that pays a reward, set that storage to zero and reduce your gasUsed by up to half!
Now, some might ask: Is this abusing an incentive? It might “feel” like wasting storage space only to reclaim it later could be called a misuse or abuse of the system.
From another point of view, it’s just an exceedingly clever hack.
WasteNowForHasteLater
WasteNowForHasteLater was the first name that came to me for this pattern. Maybe you can think of a better name. And maybe the name you choose depends on whether you appreciate the cleverness or are disgusted by the fact that this is even possible! Scott Bigelow suggested calling it the SSTORE Cobra Effect.
I see some similarities here with security research, such as the recent Spectre and Meltdown attacks. In both cases, inquiring minds dug into low-level details about how a system works, found some surprising functionality lurking in the depths, which could be exploited to achieve an unexpected result. Whether “used” vs. “misused” vs. “abused” is apropos is a judgment call.
Games sometimes have rules that give rise to feelings of unfairness. For example, I’ve encountered some amateur poker players who frown upon check-raising, feeling that it’s too sneaky or deceptive. Some even ban it during “friendly” home games. But, if you’re gonna go pro at a casino, or hope to compete in the big wide world, not being willing to employ all of the tactics at your disposal often leads to a competitive disadvantage.
Speaking of poker, online poker players also have a similar “edge” at their disposal — the concept of “rakeback”. If you sign-up at an online casino with a special code, you get get a percentage of the rake that the house takes on every hand back as a refund. Since you as a player have to do something special first (sign up with a code) and are later rewarded for it, when most other players aren’t, maybe another appropriate name for this technique might simply be GasBack.
Perhaps a future version of the EVM might handle gas refunds differently. Perhaps mining software, or oracles that miners can use to gain insights into smart contracts, will better predict which transactions will pay miners the most gas. This could lead to transactions with large gas refunds not being chosen for the next block by a winning miner even if their gasPrice is highest. For now, though, we have what we have for the rules in Ethereum and how its mining nodes tend to work in practice.
Now that you’ve read this far and know about this “trick”, I have a couple closing questions for you:
- Would you use it for competitive advantage if the situation called for it? (After I originally published this article, GasToken was released to the public on Mar 8, 2018 as one way to do it through a smart contract.)
- What other Ethereum coding “tricks” do you think might be left to be discovered?
Big thanks to Scott Bigelow who inspired this post, and Gonçalo Sá, Bernhard Mueller, Maurelian and persons who for now wish to remain anonymous for helpful editorial review/feedback.