Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Design] L2 state derived automatic contract update transactions. #1736

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

StefanIliev545
Copy link
Contributor

Why this change is needed

Please provide a description and a link to the underlying ticket

What changes were made as part of this PR

Please provide a high level list of the changes made

PR checks pre-merging

Please indicate below by ticking the checkbox that you have read and performed the required
PR checks

  • PR checks reviewed and performed

Copy link

coderabbitai bot commented Jan 7, 2024

Walkthrough

The "Ten Auto Updater" is a proposed feature for Ethereum that aims to enable automatic updates of contracts on layer 2 without the need to publish transactions on layer 1. It introduces the concept of "L2 state derived transactions" and outlines the technical requirements and potential use cases for this functionality.

Changes

File Path Change Summary
design/scratchpad/.../Design_auto_updater.md Proposes the "Ten Auto Updater" for Ethereum, enabling automatic contract updates on layer 2 using "L2 state derived transactions," and outlines technical requirements and use cases.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 6

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between b6dada7 and a568a56.
Files selected for processing (1)
  • design/scratchpad/Design_auto_updater.md (1 hunks)
Additional comments: 3
design/scratchpad/Design_auto_updater.md (3)
  • 5-8: The introduction provides a clear rationale for the feature, explaining the limitations of Ethereum's current transaction initiation process and the benefits of "L2 state derived transactions." It's well-articulated and sets the stage for the rest of the document.

  • 28-36: The "Use cases" section is well thought out, providing concrete examples of how the feature could be utilized. It's important to ensure that these use cases have been validated with potential users of the system to confirm that there is a demand for such a feature. If not already done, gathering feedback from dApp developers could be beneficial.

  • 59-65: The "Performance considerations" section does a good job of addressing potential concerns. The comparison between L2 derived transactions and L2 user transactions is insightful. However, it would be prudent to include some performance benchmarks or projections to support the claim that there will be no noticeable performance degradation.

Comment on lines +11 to +13
### Cross Chain Synthetic Transactions Primer

The synthetic transactions we currently have are not published to the L1. They are not included in the batch albeit mutating its state. This is not an issue, because the transactions are deterministically derived from the L1 state or more specifically, the L1 block that the batch points to. This means that when a validator is recomputing the batch, the data for rebuilding the transactions, in the same order is available implicitly. If we were to publish them to the L1 it would only be redundant and increase costs.
Copy link

Choose a reason for hiding this comment

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

The primer on "Cross Chain Synthetic Transactions" is informative. However, it assumes prior knowledge of the batch process and how it relates to L1 state. For clarity, consider adding a brief explanation or a reference link for readers who may not be familiar with these concepts.

Comment on lines 16 to 21
### L2 State Derived transactions

L2 state derived transaction is a special synthetic transaction, also started by the sequencer that would call a specific contract. This contract would have to register itself as updateable and prepay L2 gas costs to the `block.coinbase`. Using this prepayed funding, the sequencer would create the implicit functions calling the entry point function with no calldata and no value. It is possible to extend to support implicit calldata sent through the prepayment, but its best to keep it simple for the initial design.

The updatable contracts would need to export a callable method that determines if an update transaction should happen. Let's say this function signature will be `shouldAutoUpdate() returns (bool)`.
Whenever a batch is produced, after all the transactions have been applied the sequencer would go through the registered contracts and `derive` the synthetic auto updates that need to happen. Then they would be applied as any other transaction would, where the gas limit and cost would be put as the prepaid amount. Anything unused will be refunded back to the contract.
Copy link

Choose a reason for hiding this comment

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

The section on "L2 State Derived transactions" introduces a new concept effectively. It's important to ensure that the term "sequencer" is well-defined elsewhere in the documentation, as it's a key actor in this process. The explanation of the contract registration and the prepayment mechanism is clear, but it might benefit from a simple diagram or flowchart to illustrate the process visually.

Comment on lines +23 to +25
#### Computation implications

The callable `shouldAutoUpdate` function would need to be subsidized by the sequencer and thus would have hard cap gas limit. This is similar to how optimism grants free gas for some special auto calls on cross chain messages. Alternatively we can use a scheduling mechanic where the contract instructs the sequencer when a transaction should happen, similar to Arbitrum's retryable transactions. When something is scheduled, it would be prepaid and the executed scheduled call should reschedule a new one to keep the automation going.
Copy link

Choose a reason for hiding this comment

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

The "Computation implications" subsection introduces the shouldAutoUpdate function and discusses its gas implications. The comparison to Optimism's gas grants is useful for context. However, the document should specify the exact gas limit for the shouldAutoUpdate calls or provide a method for determining it to avoid ambiguity.

It's important to note that most dApps aren't structured to be automated in such a way - there is no way to iterate their debt for example, as its stored in maps and people search for liquidation opportunities off chain. Regardless of this, it's reasonable to expect the feature will be utilized. Contracts currently are mostly structured around rebalancing on user inputs directly, along with exposing some public functions that can do another rebalance based on calling other contracts and so on. This is highly inefficient as most of those contracts would be far better off using an automated update system that is paid for by the users who would split the cost instead of paying all of it. While its easy to argue that L2 execution costs are so low right now that this is irrelevant, lowering the barrier even more would enable more use cases and make current ones more efficient.


And lastly, there is a very exotic use case for this feature that isn't really possible anywhere - security monitoring. A contract can register an automatic callback that checks some constraints and if something is wrong pause everything automatically.
Copy link

Choose a reason for hiding this comment

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

The mention of "security monitoring" as an exotic use case is intriguing. It would be helpful to expand on this idea with more details or a hypothetical scenario to illustrate how it might work in practice.

Comment on lines 41 to 54
### Tech Requirements

We'd need a predeployed system smart contract that allows for registering contracts:

```solidity
interface TenAutomationRegistry {
function registerCallback(bytes memory callInstructions) external payable
function uniqueCaller(address targetContract, bytes memory callInstructions) pure returns (address)
}
```

dApps will use this system contract to register callbacks. Whenever `registerCallback` is called a record will be put to call `msg.sender` with `callInstructions`.
It is payable in this design, because we might need to put some arbitrary cost to prevent DOS attacks.
The `uniqueCaller` getter would return the unique address who will be the `tx.origin` for a specific contract's callback. This will allow the dApps to limit who can call the special automatic functions if they wish to do so. Futhermore it will be a layer of security as the caller address will be isolated per contract's callback, in order to prevent potential security exploits, albeit I'm not able to come up with an example.
Copy link

Choose a reason for hiding this comment

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

The "Tech Requirements" section outlines the interface for the TenAutomationRegistry. The use of payable in the registerCallback function is appropriate given the need to prevent DOS attacks. The uniqueCaller function's purpose is well-explained, but it would be beneficial to include a note on how the unique address is generated or an example of its usage.

The `uniqueCaller` getter would return the unique address who will be the `tx.origin` for a specific contract's callback. This will allow the dApps to limit who can call the special automatic functions if they wish to do so. Futhermore it will be a layer of security as the caller address will be isolated per contract's callback, in order to prevent potential security exploits, albeit I'm not able to come up with an example.


To implement the whole feature we'd need to extend the logic in the `BatchExecutor` component and simply add another layer of transactions at the end to be executed by the `evm_facade`. Those transactions will be executed with gas priced same as normal user transactions.
Copy link

Choose a reason for hiding this comment

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

The implementation details involving the BatchExecutor component are briefly mentioned. It would be advantageous to link to existing documentation or code for the BatchExecutor and evm_facade for readers to understand the changes in context.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between a568a56 and 69b7fe6.
Files selected for processing (1)
  • design/scratchpad/Design_auto_updater.md (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • design/scratchpad/Design_auto_updater.md

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 69b7fe6 and 780694a.
Files selected for processing (1)
  • design/scratchpad/Design_auto_updater.md (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • design/scratchpad/Design_auto_updater.md

@BedrockSquirrel
Copy link
Collaborator

This feels like a cool, pretty unique feature if we could pull it off.

Having to regularly update state as an admin function seems pretty common, I think games developers would find that useful (as well as the AMMs etc. you mentioned).

My first thought was DOS attack vector, which you addressed, but I'm a bit worried that the number of these checks will grow and grow like a memory leak.

I'm not sure the one-off cost is going to cut it for that, because these auto-update contracts will live forever unless users deregister them I guess, and there's no incentive to deregister really (if the checkUpdate function is free and it's always false because their dapp is dead or whatever so they're not being charged for it actually executing).

I was wondering, would it be possible to have the developer deposit eth that will be used to pay for the auto-update check functions? This would mean that:

  • we could scrap the hard cap on the gas, more flexible for them
  • there is an ongoing cost even if the result is always false, so DOS attack more expensive
  • if the dev abandons the project their deposit will eventually run out and the auto-update contract would be frozen so that it doesn't cost our nodes CPU time forever

What do you reckon? Not sure how hard it would be to implement.

@BedrockSquirrel
Copy link
Collaborator

"I imagine this would be really great for automated arbitrage" is a cool point, acknowledging that 'good' MEV exists on the chain and needs to be mopped up.

I think publicising this feature would be really important because like you said it's non-standard so people won't expect it. But app developers that want automated housekeeping functions and people wanting to hunt MEV is a pretty big market to pitch it to imo.

I think it's important in the long term that we don't make it too cheap though, it's going to cost us to run these and this could be a way to monetise the chain to keep gas fees low, if we can indirectly claim a slice of the MEV by allowing people to register their on-chain algos.

Copy link
Collaborator

@tudor-malene tudor-malene left a comment

Choose a reason for hiding this comment

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

The design needs a bit of restructuring to make it more clear.
Start with the high level, then the use cases, then the proposed implementation.

Is there any usage for gaming that you can think of?


## Introduction

In Ethereum it is well known that transactions cannot originate from contracts. There is no way to automatically run some update. Someone has to init the transaction. If you have a contract on a layer 2 that needs rebalancing for example someone has to initiate it. This results in having to publish the transaction on the L1 and pay for it.
Copy link
Collaborator

Choose a reason for hiding this comment

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

what does rebalancing mean?

@@ -0,0 +1,80 @@
# Ten Auto Updater - Scheduled callbacks

## Introduction
Copy link
Collaborator

Choose a reason for hiding this comment

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

It is not clear what high-level problem this solves


You can imagine the scheduling approach akin to doing a recursive javascript `setTimeout`. `block.coinbase` is payed and a system function is called on a predeployed contract. Contracts can use this to conviniently have the first call to them in batch trigger a schedule, paid for by the contract. Gas costs with schedules can be problematic however if they are allowed to happen at arbitrary point in time, as contracts will be unable to predict costs and might fail the schedule (and reschedule) transaction due to being out of gas. This would effectively terminate their loop if they operate based on such. Given that excess will be refunded it shouldn't be a huge problem if contracts oversupply the schedule payment. It's the approach they seem to have with chainlink callbacks.

#### Use cases
Copy link
Collaborator

Choose a reason for hiding this comment

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

this section should be in the beginning, in the high level overview

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

Successfully merging this pull request may close these issues.

3 participants