Skip to content

Latest commit

 

History

History
137 lines (89 loc) · 5.73 KB

REP-0019.md

File metadata and controls

137 lines (89 loc) · 5.73 KB

REP-0019: Implement EIP-4844: Shard Blob Transactions on Ronin

Preamble

REP-0019
Title: Implement EIP-4844: Shard Blob Transactions on Ronin
Author: Bui Quang Minh
Type: Standard
Status: Approved
Created: 2024-07-25

Abstract

REP-0019 describes the process of porting "blob-carrying transactions" (blob transactions) from Ethereum to Ronin. The blob transaction contains large amount of data which can be pruned after the predefined time.

Rationale

Today, rollups (e.g. zkEVM) use calldata to post data to Ronin so that every one can recover the full state of rollup without depending on the rollup operator. However, calldata consumes a lot of gas and is stored permanently on Ronin. Blob transaction is introduced to tackles these issues. The transaction carries data in their blobs, these blobs are stored in a short time but still long enough for anyone who interests can fetch the data. As the data is not stored permanently in the Ronin storage, it alleviates the storage burden for network. As a result, blob transaction data is charged lower than the calldata.

Specification

This proposal follows EIP-4844: Shard Blob Transactions to introduce new blob transaction type, block header extension, blob gas, fee market and a point evaluation precompile. Please refer to EIP-4844 for the detailed specification on these topics.

Parameter

Constant Value
MIN_BLOCKS_FOR_BLOB_SIDECARS_REQUESTS 518_400

Blob storage

Since Ronin does not have consensus layer like Ethereum, execution layer is extended to stored the blobs from the mined block. Blobs are stored at least MIN_BLOCKS_FOR_BLOB_SIDECARS_REQUESTS blocks (roughly 18 days) from the time they are included in the mined block. New APIs are introduced for user to query blobs from mined blocks.

Mined blob sidecars gossip

Unlike Ethereum consensus layer which propagates the "sidecars" (sidecars contain blobs, commitments and proofs) separately from block body, in Ronin, the sidecars are embedded into the block body P2P packets.

We extend BlockBodies and NewBlock packets in P2P Ethereum Wire Protocol (eth)

BlockBodies

[request-id, [block-body-1, block-body-2, ...], [sidecar-1, sidecar-2, ...]]

NewBlock

[block, td, [sidecar-1, sidecar-2, ...]]

With new P2P packet extensions, we introduce a new eth protocol version: ETH/100. The version 100 is selected to avoid further conflicts with future protocol upgrades in Ethereum.

Block validation

We need to extend the block validity check as follows

def validate_block(block: Block, sidecars: list[BlobTxSidecar]) -> None:
    ...

    # check that the excess blob gas was updated correctly
    assert block.header.excess_blob_gas == calc_excess_blob_gas(block.parent.header)

    blob_gas_used = 0
    num_blob_txs = 0
    is_data_available = is_data_available()

    for tx in block.transactions:
        ...

        # modify the check for sufficient balance
        max_total_fee = tx.gas * tx.max_fee_per_gas
        if get_tx_type(tx) == BLOB_TX_TYPE:
            max_total_fee += get_total_blob_gas(tx) * tx.max_fee_per_blob_gas
        assert signer(tx).balance >= max_total_fee

        ...

        # add validity logic specific to blob txs
        if get_tx_type(tx) == BLOB_TX_TYPE:
            # there must be at least one blob
            assert len(tx.blob_versioned_hashes) > 0

            if is_data_available:
                assert num_blob_txs < len(sidecars)
                commitments = sidecars[num_blob_txs].commitments

                # ensure number of versioned hashes is equal to number of commitments
                assert len(tx.blob_versioned_hashes) == len(commitments)

            for i in range(len(tx.blob_versioned_hashes)):
                h = tx.blob_versioned_hashes[i]

                # all versioned blob hashes must start with VERSIONED_HASH_VERSION_KZG
                assert h[0] == VERSIONED_HASH_VERSION_KZG

                # versioned blob hashes must be equal to sidecar commitment's hash
                if is_data_available:
                    assert h == calc_blob_hash(commitments[i])

            # ensure that the user was willing to at least pay the current blob gasprice
            assert tx.max_fee_per_blob_gas >= get_blob_gasprice(block.header)

            # keep track of total blob gas spent in the block
            blob_gas_used += get_total_blob_gas(tx)
            num_blob_txs += 1

    # ensure number of blob transactions is equal to number of sidecars
    assert num_blob_txs == len(sidecars)

    # ensure the total blob gas spent is at most equal to the limit
    assert blob_gas_used <= MAX_BLOB_GAS_PER_BLOCK

    # ensure blob_gas_used matches header
    assert block.header.blob_gas_used == blob_gas_used

    # verify the sidecars
    if is_data_available:
        for sidecar in sidecars:
            assert len(sidecar.blobs) == len(sidecar.commitments)
            assert len(sidecar.blobs) == len(sidecar.proofs)

            for i in range(len(sidecar.blobs)):
                assert verify_kzg_proof(sidecar.blob[i], sidecar.commitment[i], sidecar.proof[i])

Blob transaction fee

The blob transaction fee is separated from normal transaction fee, the blob transaction fee is transfered to Ronin Treasury instead of burning like Ethereum.

Security analysis

This proposal increases the bandwidth requirements per block by a maximum of ~0.75 MB. However, the worst case bandwidth is unchanged as it is capped at 10 MB by the eth protocol max packet's size. So in the worst case, there is no change in the network bandwidth.

License

The content is licensed under CC0.