What is EIP-4844? Proto-Danksharding and blob transactions explained
What is the EIP-4844? Learn what proto-danksharding and blobs are, how they work, and how to send your first blob transaction using the new Ethereum improvement proposal
Introduction
Read the original What is EIP-4844? Proto-Danksharding and Blob Transactions Explained, on cyfrin.io.
EIP-4844 (Ethereum Improvement Proposal) introduces a new type of transaction to the Ethereum blockchain, allowing blockchain rollups to settle their transactions more cheaply. These new transactions accept large chunks of data known as “blobs” that delete after a short period.
In this article, we are going to explore:
- What is EIP-4844?
- What are blob transactions?
- Why were they introduced?
Before we get into what EIP-4844 is, we first need to understand that there are different kinds of transactions.
Blockchain transaction types
In a “normal” transaction, all your transaction data is stored on-chain forever. The most common type of transaction today is the type 2 transaction but there are different ones:
- Type 0 transactions: aka “legacy” transactions
- Type 1 transactions: aka “access list” transactions (introduced by EIP-2930)
- Type 2 transactions: The new “normal” (introduced by EIP-1559)
- Type 3 transactions: aka “blob” transactions (introduced by EIP-4844)
And is about the type 3 transactions, Blobs, introduced by the new EIP-4844, that we’re going to talk in this article.
What is a Blob transaction?
Blob transactions, introduced by EIP-4844 aka “Proto-danksharding” add a new data structure to Ethereum that is deleted from the chain after around 20–90 days.
This large chunk of data we eventually delete is known as a blob, a (sort of) acronym that means; “Binary Large OBject.”
Blob transactions were included in the Ethereum Dencun upgrade on 03/13/2024, and Blockchain rollups have been loving it. These came from EIP-4844, aka “Proto-danksharding” (named after the researchers who created it, not because the name sounded cool).
A lot of people have been using the “sidecar” analogy. With a blob being the sidecar of a motorcycle. The motorcycle is the transaction, and the sidecar is the blob.
To take the analogy further, we light the sidecar on fire and dump it after a month.
Placing data in a blob makes it much cheaper for rollups to settle transactions to the L1. But before we understand why/how that works, we first need to understand why and how transactions cost gas in the first place. Even if you think you already know, give this next paragraph a read.
Why do blockchain transactions even cost gas?
Before we can understand why we added blobs in the new EIP-4884, let’s first understand why we are charged a fee for sending a transaction.
Whenever we do anything on-chain, every blockchain node has to compute or store some data. We pay gas because when sending a transaction, we ask thousands of computers to do a lot of work, which costs them money.
- Computation: Costs electricity
- Storage: Has hardware costs
- Sending messages: Network traffic has costs associated with it, too
So, if we wanted to store 20 GB of the movie Shrek on-chain, we’d need to help pay for thousands of nodes to buy the hardware needed to have the space to store the movie Shrek.
So, whenever we ask a node to “do anything,” we must pay for gas. If we tell them, “You need to store 20 GB of the movie Sherk forever” (which, previously, was how Ethereum worked, where all data is stored essentially forever), then we should pay a lot more than if we asked them to store the movie Shrek for just a few months.
Keep this in mind; we’ll come back to it.
Why did we decide to add blob transactions?
So why did we give transactions this optional box to dump data?
Well, it goes back to the biggest issue with Ethereum today:
Sending $1 on Ethereum costs me 2 dollars, aka the scaling issue. Blockchains face the blockchain trilemma, where they have difficulty nailing down all three:
- Decentralization
- Security
- Scalability
Ethereum aims to be maximally decentralized and secure, so it has difficulty scaling.
As a community, we’ve decided that Optimistic and zero-knowledge proof based blockchain rollups are how we will scale ETH for the near and long-term future of Ethereum. Rollups help us scale ETH by executing transactions on their roll-up chain, bundling them up, and then “settling” them back to the L1 (Ethereum). This makes transactions cheaper while maintaining many of Ethereum’s security properties.
With many Layer-2 blockchains processing transactions, like zkSync, Arbitrum, and Optimism, you can get many more transactions for much cheaper because you’re compressing them.
When these L2s submit these batches back to Ethereum, Ethereum has to do a little work to verify the batch of transactions is valid, and herein lies the issue.
Ethereum only needs to verify the batch is good once and then never needs that data again. But before EIP-4844, Ethereum had no (good) way to delete data, so it stored that data forever.
Do you see the issue?
- We need this big batch of data for one single instant
- No one cares about the data again
- But every ETH node on the planet had to store it from then on out
It’s like if every time you passed an exam in school, you’d have to carry that exam around with you. After 20 years, you are essentially just walking around with a massive horde of papers from your PhD thesis to your spelling test when you were learning the word “cat.”
Returning to our previous Shrek example, we can see where this all ties in.
Rollups were spending a LOT of gas submitting this massive block of data they only needed for a single instant. And rollups are the key to making Ethereum scale, so we should treat them as priority citizens. Is there something we can do to make their lives easier?
“What if we, like, just delete the data after we validate our transactions?”
- The Rollups
And so, the blobs were born.
How are blobs used to validate rollup transactions?
So, how are blobs used in practice?
Instead of the batch of transactions being submitted and that data being stored forever, the process is now:
- The roll-up (like zkSync) compresses their list of transactions
- Submits the compressed list as a blob to the Ethereum L1, along with proofs
- The L1 validates the transaction batch
- The blob is eventually deleted from the L1
We are going to get a little more technical, so brace yourself.
Here is an example blob transaction on Etherscan. It’s an example of a transaction of zkSync submitting a batch of transactions to Ethereum with blobs attached. So, how are these blobs being used?
If we click that blue “2 blobs” section, we can see the blob itself, along with a little snapshot of how much cheaper this transaction is now that we are using a blob instead of calldata!
Now, if the EVM could directly access blob data, nodes would have to store the data forever. EVM/Ethereum nodes need to keep a history of all computations they do, so if they do computations directly on the blobs, we’d have to store that computation and, therefore, store the whole blob. But we don’t want to do that because we don’t want to store the blob forever. We’d be back to square one! Therefore, the EVM cannot access blob data.
The EIP-4844 creators were clever enough to add a new opcode and precompile to help:
- The
BLOBHASH
opcode: This gets the hash of any of the blobs in a transaction. - The
point evaluation
precompile: This does some math magic. See evm.codes for more information.
With these two new tools, we can use “cryptography math magic” to verify that the blob is good without actually having to store the blob data on-chain or load it into an environment where the EVM can access it.
When a zkSync validator/operator looks to submit a list of transactions back to the L1, it calls commitBatches:
function commitBatches(
StoredBatchInfo calldata,
CommitBatchInfo[] calldata _newBatchesData
And, in the _newBatchesData object, it passes some proofs that, when combined with the blob hash (retrieved by the BLOBHASH opcode), allow the smart contract to verify that the batch of transactions is valid. Later on, the function will eventually call:
/// @dev Verifies that the blobs contain the correct data by calling the point evaluation precompile. For the precompile we need:
/// versioned hash || opening point || opening value || commitment || proof
/// the _pubdataCommitments will contain the last 4 values, the versioned hash is pulled from the BLOBHASH opcode
/// pubdataCommitments is a list of: opening point (16 bytes) || claimed value (32 bytes) || commitment (48 bytes) || proof (48 bytes)) = 144 bytes
function _verifyBlobInformation(
bytes calldata _pubdataCommitments,
bytes32[] memory _blobHashes
) internal view returns (bytes32[] memory blobCommitments) {
Which will do the actual blob verification.
The BLOBHASH
opcode will grab us a hash of the blob, not the whole blob, and we can combine this with some proofs and other “math stuff” that we can then pass to the new `point evaluation` precompile (which, this function eventually does as well). The point evaluation does some “math magic” to verify the blob hash is valid. You can read more about the inputs from evm.codes.
Now, we don’t delete the blobs right away. This is because we want other nodes to have some time to make sure the BLOBHASH that is being computed is correct, so the Ethereum community lets the blobs propagate. This really only takes maybe a few blocks, but we leave a 20–90-day window to delete blobs.
And boom! We can now verify that the L2 transactions are good. This massive blob represents all the transactions, but we can verify their validity using only the hash and some clever math.
And that’s how blobs work.
How to send your blob transaction
We’ve created a minimal repo to show you how to send a transaction with a blob using the new Eip-4884 in web3.py. The setup looks similar to how EIP-1559 (normal) transactions are set up. You’ll need to set up an EIP-2718 TransactionPayload that will look something like this:
tx = {
"type": 3,
"chainId": 31337, # Anvil
"from": acct.address,
"to": "0x0000000000000000000000000000000000000000",
"value": 0,
"maxFeePerGas": 10**12,
"maxPriorityFeePerGas": 10**12,
"maxFeePerBlobGas": to_hex(10**12),
"nonce": w3.eth.get_transaction_count(acct.address),
}
# This represents the EIP-2718 TransactionPayload
And the key important part is adding the blob itself. You don’t add the blob to the payload to the EIP-2718 TransactionPayload, but instead, you send the blobs with the payload. According to the EIP, the RLP (Recursive Length Prefix: The way Ethereum encodes transaction data.) looks like this:
rlp([tx_payload_body, blobs, commitments, proofs])
On the other hand, an EIP-1559 transaction only has the tx_payload_body in the rlp. So, in Python, we can represent this by just doing the following:
# This will generate the blobs, commitments, and proofs for our blob tx
signed = acct.sign_transaction(tx, blobs=[BLOB_DATA])
Ethers and other libraries for encoding transactions also handle most proof generation and other “blobby” stuff. The full script for sending a blob transaction might look like this:
import os
from dotenv import load_dotenv
from eth_abi import abi
from eth_utils import to_hex
from web3 import HTTPProvider, Web3
load_dotenv()
def send_blob():
rpc_url = os.getenv("RPC_URL")
private_key = os.getenv("ANVIL_PRIVATE_KEY")
w3 = Web3(HTTPProvider(rpc_url))
text = "<( o.O )>"
encoded_text = abi.encode(["string"], [text])
print("Text:", encoded_text)
# Blob data must be comprised of 4096 32-byte field elements
# So yeah, blobs must be pretty big
BLOB_DATA = (b"\x00" * 32 * (4096 - len(encoded_text) // 32)) + encoded_text
acct = w3.eth.account.from_key(private_key)
tx = {
"type": 3,
"chainId": 31337, # Anvil
"from": acct.address,
"to": "0x0000000000000000000000000000000000000000",
"value": 0,
"maxFeePerGas": 10**12,
"maxPriorityFeePerGas": 10**12,
"maxFeePerBlobGas": to_hex(10**12),
"nonce": w3.eth.get_transaction_count(acct.address),
}
gas_estimate = w3.eth.estimate_gas(tx)
tx["gas"] = gas_estimate
# This will generate the blobs, commitments, and proofs for our blob tx
signed = acct.sign_transaction(tx, blobs=[BLOB_DATA])
Refer to the GitHub repository for more information.
After the EIP-4844: The future of Danksharding and Blobs
EIP-4844, aka “Proto-danksharding,” is an intermediate step to Ethereum’s future roadmap, “Danksharding,” which has a lot more cool features. These will help Ethereum scale more in a more fair, accountable manner. However, full Danksharding will take a lot more development and research, but rollups are here today with real value. So, the EVM ecosystem decided it was worth rolling this out as the rest of Danksharding is figured out.
The Ethereum docs do a great job explaining the future of Danksharding; you can read more on the Ethereum website.
Multidimensional gas pricing
Something also that has emerged is the rise of “Multidimensional gas pricing.”
Historically, any computation or storage requests to an ETH node are bundled into 1 unit: “gas.” However, with blobs, we have created a new unit to measure computation “blob gas.” There are only allowed to be so many blobs in a block, similar to how only so much data can fit into a block. Since the supply for blobs is different from the supply for transactions, the demand can also differ. Since demand for blobs can be wildly different than demand for block space, blobs have their gas market.
You can see this in the Python code above, and there was a transaction field called maxFeePerBlobGas. Blobs get their calculation of gas costs based on blob demand. In essence, this means that two calculations are done when estimating gas costs with blobs:
- Normal gas costs based on demand for block space
- Blob gas costs based on demand for blobs
This sets a precedent that the EVM ecosystem could have even more markets in the future for calculating different costs for doing different operations in the EVM ecosystem.
Summary and recap
What is EIP-4844?
EIP-4844 is an improvement proposal to the Ethereum/EVM blockchain that adds support for “blobs” to run alongside transactions, making it cheaper for rollups to validate transactions:
1. Blob transactions are a new transaction type that allows us to store data on-chain for a short period. The “short-lived data” is known as the “blob” or “binary large object”.
2. We can’t access the data itself, but a hash of the data via a new BLOBHASH opcode
3. Using blob transactions, rollups can settle transactions to the L1 much cheaper than they used to.
How do rollups validate transactions now?
1. You submit a transaction with a blob, along with some proof data
2. Your contract on-chain accesses a hash of the blob with the BLOBHASH opcode
3. It then will pass your blob-hash combined with your proof data to the new point evaluation opcode to help verify the transactions batch
A big thank you to the users who helped us understand a lot of the more nitty-gritty issues with how blobs work.
To learn smart contract security and development, visit Cyfrin Updraft
To request security support/security review for your smart contract project, visit Cyfrin.io or CodeHawks.com.
To learn more about top reported attacks in smart contracts, be sure to study up on Solodit.