-
Notifications
You must be signed in to change notification settings - Fork 35
Conversation
…nd clarify content
fa802ef
to
a92c5d7
Compare
a92c5d7
to
a9087ce
Compare
@protolambda I tried to synthesize our approaches to make the rollup node spec both more friendly to newcomers & more concise. Let me know if you have any feedback! |
algorithm from step 2. | ||
- Note: if `currentL1` does not exist, it means we are in a re-org to a shorter L1 chain. | ||
- Note: as an optimization, we can cache `currentL1` and reuse it as the next value of `nextRefL1` to avoid an | ||
extra lookup. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried simplifying this as much as possible while preserve the semantics. @protolambda could you look it over to see if it seems alright?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New version looks good!
specs/rollup-node.md
Outdated
- If the next L1 block does not exist yet, there is no re-org, and nothing new to derive, and we can abort the | ||
process. | ||
- Otherwise, if `refL2` is the L2 genesis block, we have re-orged past the genesis block, which is an error that | ||
requires a re-genesis of the L2 chain to fix (i.e. creating a new genesis configuration). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure about this, but this my best guess. What happens in practice if we re-org past genesis? Wouldn't it be better to specify that a re-org past genesis is allowed, in which case we just wait for the L2 chain inception L1 block height to restart the whole process?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the L1 reorgs past expected anchor point on L1 then we should just manually redeploy the L2 chain (new L2 genesis) and not build any blocks on top. Wiping the whole L2 chain with a reorg without intervention is pretty severe.
If we start a L2 chain we can probably pick a finalized/confirmed L1 anchor point in the past, to not risk a reorg, at the cost of just a few empty deposit-blocks at the start of the L2 chain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I'll add a footnote saying just that.
|
||
L1 Ethereum [reaches finality approximately every 12 minutes][l1-finality], so these L2 blocks can safely be considered | ||
to be final: they will never disappear from the chain's history because of a re-org. | ||
# Handling L1 Re-Orgs | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to move this to a implementation notes directory, cf. #141
Any objections?
@@ -175,58 +235,77 @@ The following scenarios are assimilated to errors: | |||
- [`engine_executePayloadV1`] returning a `status` of `"SYNCING"` or `"INVALID"` whenever passed an execution payload | |||
that was obtained by a previous call to [`engine_getPayloadV1`]. | |||
|
|||
## Handling L1 Re-Orgs | |||
### Finalization Guarantees | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added mentions to fault proofs here because this section makes little sense without it. I'm also okay to remove this this section altogether to preserve consistency (though doing so make the prescriptions on the forkchoiceState
seemingly arbitrary).
|
||
1. A contract creation deposit, which is indicated by setting the `isCreation` flag to `true`. | ||
In the event that the `to` address is non-zero, the contract will revert. | ||
2. A call from a contract account, in which case the `from` value is transformed to its L2 | ||
[alias][address-aliasing]. | ||
|
||
> **TODO** Define if/how ETH withdrawals occur. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed since it's out of scope for the deposit rollup.
|
||
> **TODO** Specify and link to deposit blocks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is defined in the rollup node, and already implicitly in this file (first tx is l1 attributes, then user-deposited), so I don't think it's necessary to add something here.
Also we link to the glossary.
In the event a deposit transaction is included which is not derived by the [execution | ||
engine][execution-engine] using the correct derivation algorithm, the resulting state transition | ||
would be invalid. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this part because it was erroneous (it's not about the execution engine but the rollup node) and also because we can't really speak to the consequences at this stage (since we don't submit roots on L1) - what does it mean to be invalid? A bad transaction being included can also not lead to any state transition (i.e. the only bad output is in the block hash, but the state root is correct). Also if you don't follow the prescribed rules, then the result is invalid, which is sort of tautological.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "valid"/"invalid" refers to following the verifier rules I think. The local rollup-node can insert any deposit into their execution-engine, but if it does not originate from the specified derivation, other nodes will regard it as invalid. You're right that while we don't have block propagation or state-root posting it's not applicable (as other nodes cannot consume the invalid data in the first place).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "valid"/"invalid" refers to following the verifier rules I think
That's correct.
|
||
<!-- TODO: Define how this account pays gas on these transactions. --> | ||
No gas is paid for L1 attributes deposited transactions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe change this to say that "gas" is paid for on L1? Should be done when we transcribe the deposit fee design in the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically it's not paid for on L1 either, it's the rollup itself as system inserting the deposit. The rate-limit is simply the L1 block production.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Not sure about the pseudocode style/language, but ok to defer to when we have more code and can inform that style/language choice better.
- Use links to the [glossary] liberally. | ||
- Include the references to all the glossary links at the top of the file, under the top-level | ||
title. | ||
- A glossary link reference should start with the `g-` prefix. This enables to see what links to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea, I was having trouble with this before
**Vocabulary note**: *deposited transaction* refers specifically to an L2 transaction, while | ||
*deposit* can refer to the transaction at various stages (for instance when it is deposited on L1). | ||
|
||
## Table of Contents |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to see the ToC update, I will automate this with doctoc in a new PR 👍
In the event a deposit transaction is included which is not derived by the [execution | ||
engine][execution-engine] using the correct derivation algorithm, the resulting state transition | ||
would be invalid. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "valid"/"invalid" refers to following the verifier rules I think. The local rollup-node can insert any deposit into their execution-engine, but if it does not originate from the specified derivation, other nodes will regard it as invalid. You're right that while we don't have block propagation or state-root posting it's not applicable (as other nodes cannot consume the invalid data in the first place).
|
||
<!-- TODO: Define how this account pays gas on these transactions. --> | ||
No gas is paid for L1 attributes deposited transactions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically it's not paid for on L1 either, it's the rollup itself as system inserting the deposit. The rate-limit is simply the L1 block production.
specs/rollup-node.md
Outdated
- If the next L1 block does not exist yet, there is no re-org, and nothing new to derive, and we can abort the | ||
process. | ||
- Otherwise, if `refL2` is the L2 genesis block, we have re-orged past the genesis block, which is an error that | ||
requires a re-genesis of the L2 chain to fix (i.e. creating a new genesis configuration). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the L1 reorgs past expected anchor point on L1 then we should just manually redeploy the L2 chain (new L2 genesis) and not build any blocks on top. Wiping the whole L2 chain with a reorg without intervention is pretty severe.
If we start a L2 chain we can probably pick a finalized/confirmed L1 anchor point in the past, to not risk a reorg, at the cost of just a few empty deposit-blocks at the start of the L2 chain.
algorithm from step 2. | ||
- Note: if `currentL1` does not exist, it means we are in a re-org to a shorter L1 chain. | ||
- Note: as an optimization, we can cache `currentL1` and reuse it as the next value of `nextRefL1` to avoid an | ||
extra lookup. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New version looks good!
|
||
Then we can apply the following pseudocode logic to update the state of both the rollup driver and execution engine: | ||
|
||
```pseudocode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine with me, but there's no syntax highlighting so it may be difficult to read. If Go is too verbose for snippets in the spec, we can try python.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with Python, it seems to be more or less the standard for pseudocode in ethereum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try using javascript
since we use JSON notation at the top, I think it should highlight well then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrote my answer before seeing maurelian's. Feel free to suggest a modification to the syntax if you feel like it's warranted. I personally don't really see the need to change anything here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few suggestions, but LGTM
processed will only derive transactions with a `from` address attested to by the logs of the [L1 | ||
As noted above, the deposited transaction type does not include a signature for validation. Rather, | ||
authorization is handled by the [L2 chain derivation][g-derivation] process, which when correctly | ||
applied will only derive transactions with a `from` address attested to by the logs of the [L1 | ||
deposit feed contract][deposit-feed-contract]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This link seems to be broken now.
In the event a deposit transaction is included which is not derived by the [execution | ||
engine][execution-engine] using the correct derivation algorithm, the resulting state transition | ||
would be invalid. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "valid"/"invalid" refers to following the verifier rules I think
That's correct.
|
||
Then we can apply the following pseudocode logic to update the state of both the rollup driver and execution engine: | ||
|
||
```pseudocode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with Python, it seems to be more or less the standard for pseudocode in ethereum
first L1 block for which an L2 block was produced). See the [Finalization Guarantees][finalization] section for more | ||
details. | ||
Once the [payload attributes] for a given L1 block `B` have been built, and if we have already derived an L2 block from | ||
`B`'s parent block, then we can use the payload attributes to derive a new L2 block. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This 'and if' really stands out to me. What if we haven't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we can't use the payload attribute to derive a new L2 block :)
Feel free to suggest a clarification if needed!
Co-authored-by: Maurelian <maurelian@protonmail.ch>
Codecov Report
@@ Coverage Diff @@
## main #144 +/- ##
==========================================
+ Coverage 34.26% 42.11% +7.84%
==========================================
Files 11 13 +2
Lines 750 900 +150
==========================================
+ Hits 257 379 +122
- Misses 468 488 +20
- Partials 25 33 +8
Continue to review full report at Codecov.
|
Okay to merge on my end unless they are further suggestions! |
This started as a pull-request to address #87 (standardize languages around deposits), but due to a small communication problem, I was faced with a pretty big merge conflict, which also lead to some interesting discussions with @protolambda about how to structure this spec.
Since I was going to introduce a huge unreadable diff anyway, I've also used to opportunity to knock off #74 (derivation pseudocode) and #106 (sync spec with implementation, though proto had pretty much taken care of that already).
The best way to review the changes to the rollup node specs is to use this links to visualize it rendered directly.
So this now closes #87 and #74