Gas And Karma
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
Introduction to Karma
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
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
0, abort the entire transaction.
So, where does this land us?
karmais global, any broken flows can be rescued by the
senderby supplying more
karmais 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.