ref-fvm
ref-fvm copied to clipboard
FIP: Mechanism to ensure sufficient resources
We need a mechanism to ensure that an actor is running with sufficient resources to perform an operation. Specifically, a way to assert that:
- There's at least X amount of memory remaining.
- The stack depth is at most Y.
Without this, a malicious caller M can:
- Call into some target actor T.
- T then calls into some victim V.
- V fails because it doesn't have enough memory, call stack, etc.
- T thinks there's a bug in V, ignores the failure, and continues.
Right now, there's no way for T to know that V's failure is actually M's fault.
However, this would change if T could somehow assert the current call depth and current memory usage.
We have two real options here:
- Provide some way to lookup the current call depth and memory used.
- Provide some way to assert, in a call, that some amount of memory, call stack, and gas is available.
The second option is likely more convenient as it would provide a way to assert the exact conditions under which the callee is running. Personally, I'd propose adding two send flags:
- A flag to say that there must be room for at least N (256?) recursive calls and at least M (256 or 512?) MiB of memory left.
- ~A flag to say that the the call's gas limit must not exceed the gas available (by default, the gas limit is capped at the available gas).~ (edit: we don't need this second one)
These should cover most cases and should be relatively hard to misuse.
What is the benefit of A) T doing lookup or assertion vs. B) V providing a clear error message when it runs out of memory or exceeds the call depth which T can check?
V could be lying (I probably shouldn't have called it the "victim"). Basically, T needs to know whom to blame: M or V.
- A malicious M forces V to fail.
- A malicious (or buggy) V fails on its own (intentionally or otherwise).
T now needs to know whether to:
- Abort the entire operation (e.g., because M forced V to fail).
- Ignore the failure from V.
The concrete use-case here is a "notification". On completion of some operation, we want T to be able to call into V to notify it that something has happened.
If something goes wrong (e.g., V spends too much gas, uses too much memory, or just has a bug), that's not T's problem. T shouldn't be forced to abort just because T has a bug.
However, if some malicious entity M can setup the call to T such that the call to V is guaranteed to fail, though no fault of V, we don't wan to just blame V and move on. In that case, we want to blame M and abort the call to T.
Ok, makes sense.
T shouldn't be forced to abort just because T has a bug.
"because V has a bug", right?
Er, yes.
TODO: create a FIP discussion.
FIP discussion https://github.com/filecoin-project/FIPs/discussions/646