Março de 2024 mudou a economia da layer-2 para sempre. Antes do Dencun, rollups como Arbitrum ou Optimism torravam o orçamento das equipes para empurrar calldata na mainnet. Os smart contracts do Ethereum gravavam esse array de bytes no state global para sempre, forçando cada validador a armazená-lo eternamente. Isso comia até noventa por cento dos custos dos usuários de L2.
O EIP-4844 quebrou esse padrão ao introduzir transações de terceiro tipo e blobs. Mas por trás dos números bonitos de redução de taxas em 10x a 50x, esconde-se uma pilha de nuances de engenharia que o pessoal de marketing costuma varrer parabaixo do tapete.
Como um blob funciona a nível de memória e consenso
Um blob não é apenas um arquivo enviado para a blockchain. É um array de dados isolado com exatamente 131.072 bytes (128 KB) que existe em paralelo com a execução da EVM. Os smart contracts no Ethereum não conseguem ler o conteúdo de um blob dentro de uma chamada CALL ou STATICCALL. Eles só têm acesso a um único bytecode, o opcode especial BLOBHASH, que retorna a versão e o hash de compromisso.
- Tamanho do bloco: a meta é de 3 blobs (~384 KB), com um pico máximo de 6 blobs (~768 KB).
- Tempo de vida: cerca de 4.096 épocas (aproximadamente 18 dias), após os quais os nós de consenso limpam os dados de seus discos.
- Isolamento do mempool: os blobs não rodam no execution mempool comum. Eles têm o seu próprio pool a nível de clientes de consenso (P2P blob pool), o que protege as filas de transações principais contra sobrecarga (overload).
Parâmetro | Calldata clássico | Blob pelo EIP-4844 (Type 3)
Onde os dados ficam: No EVM state permanente | No p2p-pool de consenso temporário
Tempo de retenção: Para sempre | ~18 dias
Acesso via EVM: Direto (via leitura de bytes) | Indireto (apenas via hash e KZG)
Precificação: Execution gas compartilhado | Mercado de blob gas independente (EIP-1559)
Recursos ocultos e armadilhas arquiteturais do proto-danksharding
Pouca gente presta atenção em como a precificação do blob gas realmente funciona. Diferente do gás padrão, que pula com qualquer oscilação no DeFi, o mercado de blobs é gerido por um algoritmo de correção independente. Se os rollups lotarem os slots acima dos três blobs alvo, o preço começa a subir exponencialmente. Se os slots ficarem vazios, cai para o limite mínimo. Na prática, isso cria uma situação em que enviar um blob nos horários de pouco movimento custa frações microscópicas de centavo, mas em momentos de pico e congestão da rede, o preço pode disparar centenas de vezes mais rápido do que na execution layer.
Outro ponto delicado é a verificação criptográfica via compromissos KZG (Kate-Zaverucha-Goldberg). Os validadores não precisam baixar todos os 128 KB para confirmar a validade dos dados. Basta checar um polinômio de 48 bytes. Isso reduz os requisitos de CPU dos validadores, mas joga toda a carga em cima da largura de banda da rede.
Onde despejar dados "incômodos" na prática
A natureza temporária dos blobs faz deles o container ideal para dados que não precisam de contabilidade eterna, mas exigem imutabilidade criptográfica em uma janela curta de validação:
- Dumps de oráculos e métricas brutas: arrays de dados intermediários assinados por provedores antes de serem agregados no smart contract.
- Snapshots de estado de L3 e mundos de jogos: alterações de estado delta cujos resultados só precisam ser provados como corretos para a última semana.
- Logs de auditoria de backend: pacotes de transações ou recibos que precisam ser verificáveis publicamente, mas perdem o valor operacional após um mês.
Mandar carga para um blob via scripts em Python usando web3.py exige empacotar separadamente os bytes em polinômios e gerar um hash versionado com o prefixo 0x01. Calcular errado o maxFeePerBlobGas na hora do envio garante que sua transação vai travar no mempool.
A teoria e a economia fazem sentido, mas como é trabalhar com blobs a nível de código? Usar uma chamada padrão de send_transaction vai dar erro, já que as transações de terceiro tipo exigem a preparação manual de compromissos KZG, geração de provas e o cálculo de um limite de gás separado.
Enviando uma transação Type-3 em Python
Abaixo está um padrão funcional para enviar um blob usando bibliotecas atuais para interagir com um nó (Geth ou Reth) que dê suporte ao upgrade Dencun:
import os
from eth_account import Account
from web3 import Web3
w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:8545"))
key = os.environ["OPERATOR_KEY"]
acct = Account.from_key(key)
FE_COUNT, FE_PAYLOAD = 4096, 31 # 31 bytes de dados por elemento de campo
def encode_blob(data: bytes) -> bytes:
data = len(data).to_bytes(4, "big") + data
if len(data) > FE_COUNT * FE_PAYLOAD:
raise ValueError("payload não cabe em um único blob")
data = data.ljust(FE_COUNT * FE_PAYLOAD, b"\x00")
# byte mais significativo de cada elemento = 0 para garantir que o valor < módulo BLS
return b"".join(b"\x00" + data[i:i + FE_PAYLOAD]
for i in range(0, len(data), FE_PAYLOAD))
blob = encode_blob(b"EXMON Infrastructure DA Payload: batch #98412")
# Preço atual do blob gas com margem para picos
blob_base_fee = int(w3.provider.make_request("eth_blobBaseFee", [])["result"], 16)
base_fee = w3.eth.get_block("latest")["baseFeePerGas"]
tx = {
"type": 3,
"chainId": w3.eth.chain_id,
"nonce": w3.eth.get_transaction_count(acct.address),
"gas": 21000,
"maxPriorityFeePerGas": w3.to_wei(1, "gwei"),
"maxFeePerGas": base_fee * 2 + w3.to_wei(1, "gwei"),
"maxFeePerBlobGas": max(blob_base_fee * 2, w3.to_wei(1, "gwei")),
"to": acct.address, # não é criação de contrato: `to` é obrigatório em blob-tx
"value": 0,
"data": b"",
}
# ckzg calcula o compromisso, as provas e o versioned hash; o sidecar é embutido na raw tx
signed = Account.sign_transaction(tx, key, blobs=[blob])
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f"Blob-tx enviada: {tx_hash.to_0x_hex()}")Se você não levar em conta a volatilidade do maxFeePerBlobGas, nos momentos de pico de tráfego dos rollups sua transação vai travar no mempool de consenso até o mercado dar uma esfriada.
O problema dos nós de arquivo: para onde vão os dados após 18 dias
A principal armadilha ao projetar uma arquitetura com blobs envolve a remoção deles. Os clientes de consenso armazenam os corpos dos blobs por pelo menos 4.096 épocas (cerca de 18 dias), após os quais eles os deletam. A transação em si e o compromisso KZG continuam na blockchain para sempre, mas recuperar o conteúdo do blob a partir deles é impossível. Se daqui a um mês você precisar resgatar os dados do blob, um nó padrão retornará um erro.
As equipes que constroem produtos em cima do EIP-4844 precisam contornar esse problema de uma entre três maneiras:
- Coletores de arquivo próprios: subir serviços em background que puxam os blobs da rede P2P assim que eles aparecem e jogam em armazenamento frio (buckets compatíveis com S3).
- Arquivos descentralizados: usar redes como Celestia, Avail ou The Graph para o armazenamento de longo prazo de Data Availability.
- Abert mão de histórico profundo: armazenar índices locais apenas para a janela ativa de duas semanas, descartando agregados antigos em formato compactado.
Prática EXMON: otimização de armazenamento
Na infraestrutura da EXMON, nós usamos espaços temporários de blobs para descarregar logs de transações intermediários pesados, dumps de serviço e snapshots de verificação.
Isso permite resolver duas frentes de uma só vez:
- Economia de orçamento: os custos de publicação de dados caíram em uma ordem de grandeza se comparados aos métodos antigos via calldata.
- Limpeza da blockchain: o estado global da rede não fica entupido com lixo que perde a relevância em uma semana, mantendo cem por cento de verificabilidade criptográfica no intervalo do ciclo de vida dos dados.