Part of the Linea stack responsible for extracting data from the execution of an EVM client in order to construct large matrices called execution traces.
We should add a sub-registry to the defers object e.g. à la
private final Map<Integer, List<ResolveAtRollback>> toResolveAtRollback = new HashMap<>();
This map is a correspondence taking either contextNumber's or contextId's to a potentially empty list of all actions that must be undone in case of a rollback of said context. Whether self-induced or not. The deferred actions must be resolved with the TraceRollback hook (to be implemented by @daniellehrner.) To be precise when this hook is triggered one must resolve all these deferred actions recursively for all descendant contexts and clear the associated lists of ResolveAtRollback's. This mechanism allows us to not have to remember which actions were already undone and have a uniform approach to everything.
Recall that an execution context triggers a rollback whenever it either executes the REVERT opcode or triggers the Exceptional Halting condition $Z$.
Recall that the TraceRollback hook should be triggered on rollbacks at the precise point in time when Besu finishes the rollback, in particular of
the state (balances, nonces, storage ...)
the accrued state variables such as address/storage warmth ... and
the machine state in particular before any potential update to the caller/creator context's gas $\mu_\text{g}$
It should imperatively happen before any potential new opcode is acted upon in the parent context. For the root context, Besu hook should be triggered also at transaction end in case it exits with status code 0, similarly: when all rollbacks were acted upon, though before gas/value reimbursement to the sender/recipient and coinbase reward. These "transaction finalization" actions are a separate thing and this hook should appear before them.
Note. In the diagram below the actions preceded by ∴ represent "the resolution of all relevant ResolveAtRollback's". Further recall that this ought to take place during the TraceRollback hook, whence its indentation level halfway between the child context and the parent context.
────┬─ ... Either a transaction or some parent execution context spawns execution context A
└───┬─ A executes
∙ ├─ A does a CALL
∙ └───┬─ B is the callee context
∙ ∙ ├─ B executes
∙ ∙ ├─ B does a CALL
∙ ∙ └───────┬─ C is the callee context
∙ ∙ ∙ ∙ ├─ C executes
∙ ∙ ∙ ∙ ├─ C does a CREATE
∙ ∙ ∙ ∙ └───┬─ D is the createe context
∙ ∙ ∙ ∙ ∙ ├─ D executes
∙ ∙ ∙ ∙ ∙ ├─ D is successful
∙ ∙ ∙ ∙ ∙ └─ D exits with exit code 1 (success)
∙ ∙ ∙ ∙ ├─ C resumes execution
∙ ∙ ∙ ∙ ├─ C induces a rollback
∙ ∙ ∙ ∙ └─ C exits with exit code 0 (failure)
∙ ∙ ∙ ├─ ∴ we recursively resolve everything that happened in C and D
∙ ∙ ∙ └─ ∴ we recursively clear the defers sub-registry associated to C and D
∙ ∙ ├─ B resumes execution
∙ ∙ ├─ B is successful
∙ ∙ └─ B exits with exit code 1 (success)
∙ ├─ A resumes execution
∙ ├─ A does a CALL
∙ └───┬─ E executes
∙ ∙ ├─ E is successful
∙ ∙ └─ E exits with exit code 1 (success)
∙ ├─ A resumes execution
∙ ├─ A induces a rollback
∙ └─ A is responsible for undoing everything done by A, B, C, D and E
├─ ∴ we recursively resolve everything that happened in A, B, C, D and E --- NOTE: the actions in C, D were already undone!
└─ ∴ we recursively clear the defers sub-registry associated to A, B, C, D and E --- NOTE: the sub-registry entries associated to C and D were already cleared!
Note. We will impose that CallSection's and CreateSection's implement the ResolveAtRollback (or so) interface. When a CALL / CREATE is initiated we will add actions to the toResolveAtRollback sub-registry. Note that we will add items to both the caller / callee (resp. creator / createe) lists. Indeed
if the callee initiates a rollback then at that point in time we must resolve the balance transfer and "remove" the initialization code
if the caller is later on rolled back (through its own doing or by virtue of an ancestor rolling back) we must undo the warmth update of the callee
if the caller is not rolled back we are done
if the callee does not initiate a rollback then
if the caller is later on rolled back (through its own doing or by virtue of an ancestor rolling back) we must at that point in time undo the value transfer and callee warmth update
of the caller is not rolled back we are done
It's a little more intricate for CREATE's:
if the createe initiates a rollback then at that point in time we must resolve the balance transfer and "remove" the initialization code
if the creator is later on rolled back (through its own doing or by virtue of an ancestor rolling back) we must undo the warmth update of the createe as well as the nonce update of both the creator and createe
if the creator is not rolled back we are done
if the createe does not initiate a rollback then it gets (temporarily deployed and)
if the creator is later on rolled back (through its own doing or by virtue of an ancestor rolling back) we must at that point in time undo the value transfer, createe warmth update, createe deployment (code and codehash) as well as the nonce update of both the creator and createe
We should add a sub-registry to the
defers
object e.g. à laThis map is a correspondence taking either
contextNumber
's orcontextId
's to a potentially empty list of all actions that must be undone in case of a rollback of said context. Whether self-induced or not. The deferred actions must be resolved with theTraceRollback
hook (to be implemented by @daniellehrner.) To be precise when this hook is triggered one must resolve all these deferred actions recursively for all descendant contexts and clear the associated lists ofResolveAtRollback
's. This mechanism allows us to not have to remember which actions were already undone and have a uniform approach to everything.Recall that an execution context triggers a rollback whenever it either executes the REVERT opcode or triggers the Exceptional Halting condition $Z$.
Recall that the
TraceRollback
hook should be triggered on rollbacks at the precise point in time when Besu finishes the rollback, in particular ofIt should imperatively happen before any potential new opcode is acted upon in the parent context. For the root context, Besu hook should be triggered also at transaction end in case it exits with status code 0, similarly: when all rollbacks were acted upon, though before gas/value reimbursement to the sender/recipient and coinbase reward. These "transaction finalization" actions are a separate thing and this hook should appear before them.
Note. In the diagram below the actions preceded by
∴
represent "the resolution of all relevantResolveAtRollback
's". Further recall that this ought to take place during theTraceRollback
hook, whence its indentation level halfway between the child context and the parent context.Note. We will impose that
CallSection
's andCreateSection
's implement theResolveAtRollback
(or so) interface. When a CALL / CREATE is initiated we will add actions to thetoResolveAtRollback
sub-registry. Note that we will add items to both the caller / callee (resp. creator / createe) lists. IndeedIt's a little more intricate for CREATE's: