๐งโโ๏ธ Outlining a path towards gas optimization
Opened this issue ยท 3 comments
Hello, I've been looking over the codebase the last few days and I noticed you could use some help optimizing the contract so that it may be better suited for a production environment. To get us started, I thought I'd first start by listing some potential solutions:
-
SSTORE2 could potentially be implemented
-
I'm not entirely sure, but I think most of the arithmetic can be unchecked. (NOTE: where underflow/overflow is impossible or not possible in realistic conditions)
-
Storage can be optimized/packed into less slots since most of mutable state is updated together.
// single storage slot, rather than 3
uint32 private latestBlockTime; // equal to lastBlockTime % 2**32
uint112 private latestBlockHeight;
uint112 private expectedTarget;
// can these be simplified or condesed?
mapping(uint256 => bytes32) private blockHeightToHash;
mapping(uint256 => uint256) private blockHeightToTotalDifficulty;
-
SLOADs can be avoided, consider caching state variables in memory before using them several times in a function.
-
A rewrite in inline assembly or yul+ could potentially provide some benefit as well.
P.S. Feel free to send questions my way!
@0xClandestine
That should work right? exactly uint256
uint32 private latestBlockTime; // equal to lastBlockTime % 2**32
uint112 private latestBlockHeight;
uint112 private expectedTarget;
// can these be simplified or condesed?
mapping(uint256 => bytes32) private blockHeightToHash;
mapping(uint256 => uint256) private blockHeightToTotalDifficulty;
BTC hash is 256 bit long, so that is one slot gone, Difficulty could fit in a 48bit uint
struct Block { hash: byte32, difficulty: uint}
mapping(uint256 => Block) private blockHeightToBlock;
It may save a table of look up key, not sure how much overhead the struct would introduce.
@0xClandestine i just saw this. Thank you!
This looks excellent.
The biggest single cost before was the 20k gas per block to open a new storage slot.
I've optimized that using a ring buffer--by only storing the last n (eg n=1000) blocks, after the initial n
blocks to fill the array, we pay only 3k gas per block, because we're overwriting an existing storage slot.
PR #6