Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Rollup Node Specification Revamp #144

Merged
merged 12 commits into from
Jan 28, 2022
Merged

Rollup Node Specification Revamp #144

merged 12 commits into from
Jan 28, 2022

Conversation

norswap
Copy link
Contributor

@norswap norswap commented Jan 21, 2022

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

@norswap norswap changed the title Standardize language around deposits Rollup Node specification make-over Jan 24, 2022
@norswap norswap changed the title Rollup Node specification make-over Rollup Node Specification Revamp Jan 24, 2022
@norswap
Copy link
Contributor Author

norswap commented Jan 24, 2022

@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.
Copy link
Contributor Author

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?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New version looks good!

- 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).
Copy link
Contributor Author

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?

Copy link
Collaborator

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.

Copy link
Contributor Author

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

Copy link
Contributor Author

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

Copy link
Contributor Author

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.
Copy link
Contributor Author

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
Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

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).

Copy link
Collaborator

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.
Copy link
Contributor Author

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.

Copy link
Collaborator

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.

Copy link
Collaborator

@protolambda protolambda left a 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
Copy link
Collaborator

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
Copy link
Collaborator

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.

Copy link
Collaborator

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.
Copy link
Collaborator

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.

- 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).
Copy link
Collaborator

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.
Copy link
Collaborator

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
Copy link
Collaborator

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.

Copy link
Collaborator

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Collaborator

@maurelian maurelian left a 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].
Copy link
Collaborator

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.

Copy link
Collaborator

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.

specs/deposits.md Outdated Show resolved Hide resolved
specs/deposits.md Outdated Show resolved Hide resolved

Then we can apply the following pseudocode logic to update the state of both the rollup driver and execution engine:

```pseudocode
Copy link
Collaborator

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.
Copy link
Collaborator

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?

Copy link
Contributor Author

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-commenter
Copy link

codecov-commenter commented Jan 28, 2022

Codecov Report

Merging #144 (04309c9) into main (6cf5e20) will increase coverage by 7.84%.
The diff coverage is n/a.

Impacted file tree graph

@@            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     
Impacted Files Coverage Δ
opnode/test/geth.go 50.00% <0.00%> (ø)
opnode/test/setup.go 96.07% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6cf5e20...04309c9. Read the comment docs.

@norswap
Copy link
Contributor Author

norswap commented Jan 28, 2022

Okay to merge on my end unless they are further suggestions!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Standardize language around deposits
4 participants