Francesco
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
3
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# Delayed execution Goal: we want to go further than just [delaying the state-root computation](https://github.com/ethereum/EIPs/pull/9241), which still requires immediately executing the block to check that it is valid. We want to allow attesting to a block without executing it, taking execution fully out of the critical path. It would only need to complete before the following slot (though in practice there are other constraints as well, e.g. sync speed). ## Approach 1: statically verify payload with upfront builder payment This is an EL-based approach, for which an [EELS spec](https://github.com/ethereum/execution-specs/compare/master...fradamt:execution-specs:delayed-execution-simple) is available. ### Static verification We want to be able to statically verify the block, meaning do some checks that do not involve tx execution, and which are sufficient to guarantee block validity. The key problem in doing this is that a tx's sender might not be sufficiently funded when its tx should be executed, e.g. because the sender is a 7702 delegated EOA and a previous tx sent out its balance. Moreover, we are reluctant to simply skip such a tx, because even the tx's inclusion without execution consumes resources that should be paid for. In particular, we are concerned about builders always having an incentive to fill any unused blockspace with invalid txs full of calldata (the free DA problem). To get around this problem and enable static verification, we *charge the builder upfront for all inclusion costs*, i.e., all costs that don't depend on whether the tx is executed or not: - the 21000 fixed fee, which accounts for signature verification and any other small validity check, and for all bytes other than calldata (e.g. signature, nonce etc...) - calldata - blob data Meaning, for each tx the builder (`fee_recipient`/`coinbase`) pays this amount upfront: ```python TX_BASE_COST = 21000 TOTAL_COST_FLOOR_PER_TOKEN = 10 tokens_in_calldata = ( zero_bytes_in_calldata + nonzero_bytes_in_calldata * 4 ) inclusion_gas = ( TX_BASE_COST + TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata ) inclusion_cost = ( inclusion_gas * base_fee_per_gas + blob_gas * blob_basefee ) ``` Now, if at execution time a tx fails to be sufficiently funded, we can safely skip it without doing any execution, because the protocol is still made whole for the inclusion costs fronted by the builder. Skipped txs might still be used as a weird DA layer, for example by paying the builder out-of-band, but from the protocol's perspective what's important is that its resources are paid for. ### Execution Once we actually execute the block, and are preparing to execute a given transaction `tx`, we check that `sender_balance >= tx.value + max_gas_fee`, as we also currently do. Here, `max_gas_fee` is just the worst case fee declared by the tx: ```python if isinstance(tx, (FeeMarketTransaction, BlobTransaction)): max_gas_fee = tx.gas * tx.max_fee_per_gas else: max_gas_fee = tx.gas * tx.gas_price ``` In other words, we are checking that the sender is sufficiently funded to execute this tx. This check cannot be done statically, without executing, and as just mentioned it's precisely why we are forced to require an upfront payment from the builder. If check fails at execution time, it's too late to invalidate the block, but we can just skip the tx (treat it like a no-op), because its inclusion costs have already been covered. Since the builder could have prevented this by not including the tx in the first place, and since the transaction sender doesn't get any benefit from the tx being included but skipped, *we do not refund the builder at all for the intrinsic costs*. From a tx sender's perspective, this essentially preserves the guarantee that they don't pay for invalid txs. If instead the check above succeeds, the tx is executed *exactly as usual*, including fee collection: basefee and blob base fee are burnt, while priority fees go to the builder. *Separately*, the builder is refunded ("by the protocol" rather than from the sender, i.e., by just increasing its balance) exactly what they have paid upfront for this tx, the `inclusion_cost`. In other words, when a tx is skipped the builder ends up paying exactly the `inclusion_cost`, whereas when a transaction executes the behavior is exactly the same as today, except for `inclusion_cost` being temporarily reserved from the builder's balance. ### Variant: builder pays for all protocol fees Separately from delayed execution, another feature ([EELS spec here](https://github.com/ethereum/execution-specs/compare/master...fradamt:execution-specs:delayed-execution)) involving a different way to deal with the sale of protocol resources is [block-level base fees](https://ethresear.ch/t/block-level-fee-markets-four-easy-pieces/21448#p-52192-piece-3-block-level-base-fee-6), the idea of requiring base fee payment not on a tx by tx basis, but at the level of the block. In other words, we want to loosen two constraints which the protocol currently requires from each tx, namely to be: 1. *Basefee paying*: `tx.max_fee >= base_fee_per_gas` and `tx.max_fee_per_blob_gas >= blob_gas_price` 2. *Funded upfront*: `sender_balance >= tx.value + max_gas_fee`, where `max_gas_fee = tx.gas * tx.max_fee_per_gas + blob_gas * blob_gas_price` Block level base fees would instead require budget balance to hold only at the level of the block, potentially allowing *underpriced* txs, which are not willing to pay the current basefee, as well as *underfunded* txs, where the sender balance is too low to fund the worst case execution upfront. The classic use case here are sponsored txs, or txs where the sender starts without any eth but gets eth over the course of the execution, e.g. by swapping a token for it. In the delayed execution paradigm, we are slightly restricted in how we can go about allowing such use cases, because we always have to make sure that txs are sufficiently funded upfront. In particular, static verifiability of validity is incompatible with the approach of optimistically executing the block and invalidating it if by the end the protocol has not been made whole for all gas usage. What we can do instead is to still require upfront payment, but *collect it from the builder whenever the sender does not want to or cannot pay*. In other words, there are three possibilities at tx execution time: - *Charge the sender upfront*: if the transaction prices are higher than the basefees and the sender is funded (1. and 2. hold), we execute as usual, charging the sender upfront, refunding them the unused gas and sending priority fees to the builder. The builder is also refunded the inclusion costs that were reserved at the beginning of the block's execution. - *Charge the builder upfront*: if not, but the builder is funded upfront, meaning `coinbase_balance >= (tx.gas - inclusion_gas) * base_fee_per_gas`, and the sender has at least `tx.value` to send out, then the builder pays upfront, and at the end collects gas refunds and *all* fees from the sender (which might still be insufficient to recoup the costs) - *Skip txs*: if all else fails, the tx is skipped and the builder is not refunded the inclusion costs ## Approach 2: optimistic attesting This is a CL-based approach. We simply drop the requirement to validate `beacon_block.execution_payload` when attesting to a `BeaconBlock` *in its proposal slot*. In other words, the CL does not need to wait for the EL to finish executing and respond that the payload is valid: once the CL has done all validations on its side, it can attest. This is only the case until the end of the slot however: whenever `beacon_block.slot < current_slot`, attesting to `beacon_block` requires `beacon_block.execution_payload` to be valid. If the payload turns out to be invalid, we mark it as such and never output it as part of the canonical chain, never attest to it or to descendants of it etc... In practice, the easiest way to do so would be completely remove it from our fork-choice store, in particular from `store.blocks`, which is essentially our block tree. However, there's an issue: the initial attestations to this block would end up being wasted, because they point to a block that is not in the block tree anymore. This is ok when it comes to the block itself, but it's problematic when it comes to the block's ancestors, which might themselves be perfectly valid. To drive the point home, consider the following scenario: 1. At slot N, invalid block B is proposed on top of valid block A 2. Everyone attests to B, since they do not yet execute the payload. Both A and B gain one committee's worth of attestation weight 3. After slot N, everyone has completed the execution of B and finds it invalid. B is discarded, and so are all attestations to B. Block A loses one committee's worth of attestation weight When we look at the same scenario without optimistic attesting, what would happen is instead: 1. At slot N, invalid block B is proposed on top of valid block A 2. No one attests to B, since they find it invalid. Everyone attests to A instead. A gains one committee's worth of attestation weight (and doesn't later lose it) Essentially, we break a monotonicity property of the fork-choice: while a block is winning in the fork-choice, i.e., while its subtree has more weight than the competing subtrees and thus it is in the canonical chain, its weight advantage only grows with each slot, because all honest validators attest to it (and assuming honest majority). Another way to look at it is that honest attesting weight can be wasted by the adversary, while adversarial weight from the same slot can in the meantime accumulate on a competing block. In theory, there's a straightforward solution. When we find out that B is invalid, we don't completely throw it out of our fork-choice. Instead, we keep track of B's existence and of its place in the block tree, for example by storing a header, and of the fact that it is invalid. Then, `latest_messages` pointing to B can be counted for B's parent, while B itself can always be excluded from the canonical chain. #### Block propagation Note that block propagation already does not involve fully validating the block. In fact, it does not require even fully validating everything other than the execution payload. Mainly, DoS resistance relies on checking the proposer's signature, and whether the proposer is the expected one based on the current shuffle. Nothing about this changes in the slightest with optimistic attesting. #### Syncing/requesting When someone sees an attestation that points to a block they don't have, they request that block. If the block is invalid but still relevant to the fork-choice because of what I mentioned above (which won't be the case after a later block has been finalized), peers should respond with the header, and signal that the block is invalid. With the header, the requesting node can now correctly utilize all attestations to it. If a peer were to instead respond with the full block, it would be downscored or disconnected once the block fails to be validated. #### Fully optimistic validation We could go further than not requiring the execution payload to be valid, by not requiring the beacon block to be valid at all. Essentially, we'd delay the entire beacon block state transition function, rather than only the EL component of it. As for block propagation, validation for the initial attestation would be mainly centered on the proposer's signature, rather than on the content. It would essentially just be a way of saying "by the attestation deadline, I have seen a correctly signed message from the expected proposer, commiting to a block", without saying anything about whether or not this block is valid.

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully