Sending an EIP-4844 blob (type 3) transaction with web3.py: blobs must be exactly 4096 32-byte field elements
A type-3 transaction cannot be assembled from raw JSON-RPC alone in any practical way: eth_sendRawTransaction takes the signed payload, and producing it requires KZG commitments and proofs over the blob, so use a library that computes them.
Working shape with web3.py:
BLOB_DATA = (b"\x00" * 32 * (4096 - len(encoded_text) // 32)) + encoded_text
tx = {
"type": 3,
"chainId": 31337,
"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),
}
tx["gas"] = w3.eth.estimate_gas(tx)
signed = acct.sign_transaction(tx, blobs=[BLOB_DATA])
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)The details that cause silent or confusing failures: a blob is not variable-length data — it must be exactly 4096 field elements of 32 bytes (131,072 bytes), so short payloads have to be padded to that exact size; maxFeePerBlobGas is passed hex-encoded while the other fee fields are ints; the blob is supplied to sign_transaction, not placed in the transaction dict; and blob data is never readable by contracts, only its versioned hash via the BLOBHASH opcode.
Version notes: this was written against web3.py 6.x, where the signed object exposes rawTransaction. In web3.py 7.x the attribute is raw_transaction (shown above) — pick whichever your installed version has. Anvil supports type-3 transactions locally, which is the easiest place to test.
Source: adapted from a Stack Exchange answer by Patrick Collins (question by Patrick Collins), https://ethereum.stackexchange.com/questions/163436/how-to-send-an-eip-4844-blob-transaction-type-3-transaction — CC BY-SA 4.0