Interesting proposal. I am sure you put a lot of thought into it, probably much more than I will be able to. But, as promised, I will write down what I think about gas limit.
Currently, the discussion about gas limit usually touches on the question about what the “safe limit” is. It usually composes of 2 things:
- What is the worst-case block execution given certain gas limit. We know that bottleneck in some specially crafted worst-case blocks is state access. Depending on how it is crafted, different state layouts (like Geth snapshotter, and turbo-geth plain state) and presence/absence of bloom (or similar) filters in front of state access, make significant difference there. However, it is still possible to craft a worst-case block that would, say specifically target turbo-geth, and still result in long processing time (though other implementations are likely to suffer much more on the same blocks). Also, as I realised recently, precompile pricing calibrations are performed under assumptions of 40Mgas/sec (or even 25Mgas/sec perhaps). It is clear that with such calibrations, precompiles will become bottleneck for the worst case performance sooner or later.
- What is state growth given certain gas limit. Again, here we can easily sketch a worst case growth, which however is likely to be quite unrealistic.
So is it possible to increase the gas limit above the limitation dictated by worst case performance? It seems that the answer is “no”. But I think it is “yes”. I believe this can be done through decoupling of worst-case performance (what we are afraid may happen) and average-case performance (what actually happens most of the time). It requires some architectural changes though. Here is the idea. First, we decouple transaction pool (miner/block proposer will be located inside this transaction pool component). Sort of like shown on this diagram: https://github.com/ledgerwatch/interfaces/blob/4b95458a4f48aa11112c81e5af4c4107671dd368/turbo-geth-architecture.png?raw=true
This separation of transaction pool (it is not super hard, we should get it this year) allows a crucial improvement - the ability of running multiple instances of transaction pool per “Core”. Why is it crucial? Lets imagine that the worst-case transaction that executes really long time (but is still within the gas limit) is an “execution bomb”. Someone creates such a “bomb” and relays it over the network. Currently, because it passes simple checks like account having enough ETH to pay for gas, and no nonce gaps, it will be relayed all the way to the miners/block proposers, at which point it is likely to “explode” their “Core” engine that does the mining, delaying the composition of the block, therefore increasing probability of serious of empty blocks, and therefore reducing the capacity of Ethereum. Now lets imagine that some miner/block proposer managed to include such transaction into a block (perhaps it was intentional), and now this block propagates. It is quite likely that this block will be orphaned, because any miners/block proposers that are trying to import it to compose new blocks over it, will be delayed and lose the race to the new block. Therefore, it is not in miner/block proposer’s interest to even include such execution bombs, unless they possess clear majority and want to squeeze everyone else’s revenue.
So, my conclusion from the above is that
- There needs to be a mechanism for miners/block proposers to detect execution bombs when they come inside the block. This can be achieved by simply timing out the execution and orphaning the block if it exceeds certain reasonable time limit.
- There needs to be a mechanism for network participants who relay transactions to detect and stop relaying transactions that carry execution bombs. This can be achieved by the practice of running multiple transaction pools per “Core”, and using this to pre-execute all transactions before relaying. Here again, transaction is thrown out after exceeding a time limit. And having multiple tx pools and randomly assigning transactions to them helps prevent clogging up the pools by just one bomb. In order to make repeated bomb production more costly, transaction pools may introduce ban on the replacement of the “bomb” transactions with the transaction from the same sender and nonce, for some time (several hours?). This will make sure that whatever is in the sender’s balance will effectively be temporarily locked.
These are pretty rough ideas, but I would like to try them out on a devnet/testnet