Previously, I made a proposal: EIP-2583, which would add a penalty for certain operations, namely ops that caused trie misses.
The proposal would have "kind of" worked, but with some caveats:
- The maximum enforceable 'penalty' would be on the order of 800,
- There was a low (but not impossible) chance of breaking some contract flow
I'm going to first analyze these two points a bit.
There exists a roofing function for the penalty. Since the penalty is deducted from gas, that means that a malicious contract can always invoke a malicious relay to perform the trie lookup. Let's refer to this as the 'shielded relay' attack.
In the EVM, gas
is a 'local' concept. This means that even if at some specific point in the call-frame, the gas would have gone below zero, it actually only goes to zero, the execution is reverted, and control is given back to the caller, in the previous context.
Initiatives/EIPS such as EIP-1380 "reduced gas-cost for calls to self, would further limit the "enforceability" of penalties.
Any time we change the cost of an opcode, we risk breaking contracts. Unfortunately, due to the 'locality' of gas, these breakages cannot be fixed from the outside. Even if the sender
adds more gas
to his transaction when he invokes some token, it might still be the case that the token
only sends 2300
gas to the next contract in the flow. Thus: contracts acts as bottlenecks, and prevents "fixing" a broken flow by merely adding more gas
.
Some examples of contract flows that can be broken can be found in the analysis for EIP-1884, by like these found by contract-library.com and these found by Chain Security
I heard about this idea first from @ledgerwatch, he calls it 'oil'. As I'm coming from the perspective of penalizing behaviour that is unwanted, I'd prefer to all it Karma, instead of just continuing the analogy with mechanical engines.
Let's say that for every transaction, we set karma=gas
at the start of the transaction. So a 50K gas
transaction now also has 50K karma
. As opposed to gas
, karma
is a fully global concept. It is a per-transaction value.
Now, if we want to introduce the penalty
from EIP-2583, here's what we can do:
- For every trie-opcode that causes a trie-miss (defined in EIP-2583), deduct
penalty
karma
(e.g.5000
). - If
karma
goes below0
, abort the entire transaction.
So, where does this land us?
- Since
karma
is global, any broken flows can be rescued by thesender
by supplying morekarma
. - Since
karma
is global, misbehaving contracts cannot use 'call-shields' to restrict the penalty.
If we also modify the transaction format, so that karma
can be set explicitly, then users wouldn't have to raise gas
needlessly only to push through a broken contract-flow.
For stateless ethereum, the concept of a global counter for trie accesses (read: witness size counter) is highly useful. Instead of using it to penalize trie-misses, the exact same mechanism can be used to estimate withness size of a transaction, and make transaction cost relative to the witness usage.
For stateless ethereum, an example rule could be to deduct karma
for any operation that reads or writes state.