No Ethereum, os recursos eram até recentemente limitados e com preços, usando um único recurso chamado "gás". O gás é uma medida da quantidade de "esforço computacional" necessário para processar uma determinada transação ou bloco. O gás combina vários tipos de "esforço", principalmente:
Por exemplo, esta transaçãoque enviei custou um total de 47.085 gás. Isto é dividido entre (i) um custo base de 21000 gás, (ii) 1556 gás para os bytes nos dados de chamada incluídos na transação (iii) 16500 gás para leitura e escrita no armazenamento, (iv) gás 2149 para fazer um registo, e o restante para a execução do EVM. A taxa de transação que um utilizador deve pagar é proporcional ao gás que a transação consome. Um bloco pode conter até um máximo de 30 milhões de gás, e os preços do gás são constantemente ajustados através do @vbuterinMecanismo de segmentação EIP-1559, garantindo que, em média, os blocos contenham 15 milhões de gás.
Esta abordagem tem uma eficiência principal: porque tudo é fundido num recurso virtual único, conduz a um design de mercado muito simples. Otimizar uma transação para minimizar os custos é fácil, otimizar um bloco para recolher as taxas mais altas possíveis é relativamente fácil (não incluindoMEV) e não existem incentivos estranhos que encorajem algumas transações a agrupar-se com outras transações para poupar em taxas.
Mas essa abordagem também tem uma grande ineficiência: trata diferentes recursos como sendo mutuamente conversíveis, quando os limites reais subjacentes do que a rede pode lidar não são. Uma maneira de entender este problema é olhar para este diagrama:
O limite de gás impõe uma restrição de
𝑥1∗𝑑𝑎𝑡𝑎+𝑥2∗𝑐𝑜𝑚𝑝𝑢𝑡𝑎𝑡𝑖𝑜𝑛<𝑁
. A restrição real de segurança subjacente muitas vezes está mais próxima de
máx(x1*dados,x2*computação) . Esta discrepância leva a que o limite de gás exclua desnecessariamente blocos realmente seguros, ou aceite blocos realmente inseguros, ou alguma mistura de ambos. Se houver n recursos que têm limites de segurança distintos, então o gás unidimensional reduz plausivelmente a capacidade em até um fator de n . Por esta razão, há muito tempo que existe interesse no conceito de gás multi-dimensional e com EIP-4844na verdade, temos gás multidimensional a funcionar no Ethereum hoje. Esta publicação explora os benefícios deste abordagem e as perspetivas de aumentá-la ainda mais. No início deste ano, o bloco médio era 150 kB em tamanho. Uma grande fração desse tamanho é dados de rollup: protocolos de camada 2armazenar dados na cadeia para segurança. Estes dados eram caros: embora as transações em rollups custassem cerca de 5-10x menos do que as transações correspondentes na Ethereum L1, mesmo esse custo era demasiado elevado para muitos casos de uso. Porque não diminuir o custo do gás da calldata (atualmente 16 gás por byte não nulo e 4 gás por byte nulo), para tornar os rollups mais baratos? Nós fez isto antes, podemos fazer de novo. A resposta aqui é: o tamanho do pior caso de um bloco foi 30,000,00016=1,875,000 bytes não nulos, e a rede já mal consegue lidar com blocos desse tamanho. Reduzir os custos em mais 4x aumentaria o máximo para 7,5 MB, o que representaria um enorme risco para a segurança. Este problema acabou por ser resolvido ao introduzir um espaço separado de dados compatíveis com rollup, conhecido como "blobs", em cada bloco. Os dois recursos têm preços e limites separados: após o hard fork do Dencun, um bloco Ethereum pode conter no máximo (i) 30 milhões de gás e (ii) 6 blobs, que podem conter ~125 kB de calldata cada. Ambos os recursos têm preços separados, ajustados pormecanismos de preços semelhantes ao EIP-1559 separados, visando um uso médio de 15 milhões de gás e 3 blobs por bloco. Como resultado, os rollups tornaram-se 100 vezes mais baratos, o volume de transações nos rollups aumentou mais de 3 vezes e o tamanho máximo teórico do bloco foi apenas ligeiramente aumentado: de ~1,9 MB para ~2,6 MB. Taxas de transação em rollups, cortesia de growthepie.xyz. O fork Dencun, que introduziu blobs com preços multidimensionais, aconteceu em 13 de março de 2024. Num futuro próximo, surgirá um problema semelhante em relação às provas de armazenamento para clientes sem estado. Os clientes sem estado são um novo tipo de cliente que será capaz de verificar a cadeia sem armazenar muitos ou quaisquer dados localmente. Os clientes sem estado fazem isso ao aceitar provas das partes específicas do estado do Ethereum que as transações nesse bloco precisam alcançar. Um cliente sem estado recebe um bloco, juntamente com provas que comprovam os valores atuais nas partes específicas do estado (por exemplo, saldos de conta, código, armazenamento) que a execução do bloco toca. Isso permite que um nó verifique um bloco sem ter qualquer armazenamento próprio. Uma leitura de armazenamento custa 2100-2600 gás, dependendo do tipo de leitura, e as escritas de armazenamento custam mais. Em média, um bloco faz cerca de 1000 leituras e escritas de armazenamento (incluindo verificações de saldo de ETH, chamadas SSTORE e SLOAD, leitura de código de contrato e outras operações). O máximo teórico, no entanto, é 30,000,0002,100=14,285 lê. A carga de largura de banda de um cliente sem estado é diretamente proporcional a este número. Hoje, o plano é apoiar clientes sem estado ao mover o design da árvore de estado do Ethereum deÁrvores de Merkle PatriciaparaÁrvores VerkleNo entanto, as árvores Verkle não são resistentes a quantuns e não são ótimas para as novas ondas de sistemas de prova STARK. Como resultado, muitas pessoas estão interessadas em apoiar clientes sem estado através de árvores de Merkle binárias e STARKsem vez disso - seja pulando Verkle completamente, ou atualizando alguns anos após a transição do Verkle uma vez que os STARKs se tornem mais maduros. As provas STARK de ramos de árvore de hash binário têm muitas vantagens, mas têm a fraqueza chave de que as provas demoram muito tempo a ser geradas: enquanto Árvores Verklepode provarmais de cem mil valores por segundo, STARKs baseados em hash geralmente conseguem provar apenas alguns milhares de hashes por segundo, e provar cada valor requer um “ramo” contendo muitos hashes. Dado os números que estão sendo projetados hoje a partir de sistemas de prova hiper-otimizados como BiniusePlonky3e hashes especializados comoVisão-Mark-32, parece provável que por algum tempo estaremos num regime em que é prático provar 1.000 valores em menos de um segundo, mas não 14.285 valores. Blocos médios seriam aceitáveis, mas blocos de pior caso, potencialmente publicados por um atacante, iriam quebrar a rede. A forma “padrão” como lidamos com esse cenário é a repricing: tornar a leitura de armazenamento mais cara para reduzir o máximo por bloco para algo mais seguro. No entanto, nós temos jáfeitoistomuitosvezes, e isso tornaria demasiadas aplicações demasiado caras para fazer isto novamente. Uma abordagem melhor seria gás multidimensional: limitar e cobrar separadamente pelo acesso ao armazenamento, mantendo o uso médio em 1.000 acessos ao armazenamento por bloco, mas definindo um limite por bloco de, por exemplo, 2.000. Outro recurso que vale a pena considerar é o crescimento do tamanho do estado: operações que aumentam o tamanho do estado do Ethereum, que os nós completos precisarão manter a partir de então. A propriedade única do crescimento do tamanho do estado é que a justificativa para limitá-lo vem inteiramente do uso sustentado a longo prazo e não de picos. Portanto, pode haver valor em adicionar uma dimensão de gás separada para operações de aumento do tamanho do estado (por exemplo, SSTORE de zero para não zero, criação de contrato), mas com um objetivo diferente: poderíamos definir um preço flutuante para atingir um uso médio específico, mas não estabelecer limite por bloco. Isto mostra uma das propriedades poderosas do gás multidimensional: permite-nos perguntar separadamente qual é o uso médio ideal e qual é o uso máximo seguro por bloco, para cada recurso. Em vez de definir os preços do gás com base nos máximos por bloco e deixar que o uso médio siga, nós temos 2𝑛 graus de liberdade para definir 2𝑛 parâmetros, ajustando cada um com base no que é seguro para a rede. Situações mais complicadas, como aquelas em que dois recursos têm considerações de segurança parcialmente aditivas, poderiam ser tratadas fazendo com que um opcode ou custo de recurso consumisse uma quantidade de vários tipos de gás (por exemplo, um SSTORE de zero para não zero poderia custar 5000 gás de prova do cliente sem estado e 20000 gás de expansão de armazenamento). Deixe 𝑥1 ser o custo de gás de dados e 𝑥2 ser o custo de gás da computação, assim em um sistema de gás unidimensional podemos escrever o custo de gás de uma transação: gás=𝑥1∗𝑑𝑎𝑡𝑎+𝑥2∗c𝑜𝑚𝑝𝑢𝑡açã𝑜 Neste esquema, definimos em vez disso o custo de gás de uma transação como: gás=máx(x1*data,x2*computação) Ou seja, em vez de uma transação ser cobrada por dados mais computação, a transação é cobrada com base em qual dos dois recursos consome mais. Isso pode ser facilmente estendido para abranger mais dimensões (por exemplo, max(…,x3*storagemax) ). Deve ser fácil ver como isso melhora a taxa de transferência sem comprometer a segurança. A quantidade máxima teórica de dados em um bloco ainda é 𝐺𝐴𝑆𝐿𝐼𝑀𝐼𝑇𝑥1 , exatamente o mesmo que no esquema de gás unidimensional. Da mesma forma, a quantidade máxima teórica de computação é 𝐺𝐴𝑆𝐿𝐼𝑀𝐼𝑇𝑥2 , novamente exatamente o mesmo que no esquema de gás unidimensional. No entanto, o custo de gás de qualquer transação que consuma tanto dados quanto computação diminui. Esta é aproximadamente o esquema empregado no propostoEIP-7623, para reduzir o tamanho máximo do bloco enquanto aumenta ainda mais a contagem de blobs. O mecanismo preciso no EIP-7623 é um pouco mais complicado: mantém o preço atual dos dados de chamada de 16 gás por byte, mas adiciona um "preço mínimo" de 48 gás por byte; uma transação paga o mais elevado de (16 bytes + execution_gas) e (48 bytes). Como resultado, o EIP-7623 diminui o tamanho teórico máximo do calldata da transação em um bloco de ~1,9 MB para ~0,6 MB, mantendo os custos da maioria das aplicações inalterados. O benefício dessa abordagem é que ela representa uma alteração muito pequena em relação ao esquema de gás unidimensional atual, o que torna sua implementação muito fácil. Existem duas desvantagens: Eu argumentaria que uma regra no estilo EIP-7623, tanto para os dados da transação quanto para outros recursos, pode trazer benefícios suficientemente grandes para valer a pena, mesmo apesar dessas desvantagens. No entanto, se e quando estivermos dispostos a dedicar um esforço de desenvolvimento (significativamente maior), existe uma abordagem mais ideal. Vamos primeiro recapitular como funciona o EIP-1559 "regular". Vamos nos concentrar na versão que foi introduzida no EIP-4844 para blobs, porque é matematicamente mais elegante. Rastreamos um parâmetro, excess_blobs. Durante cada bloco, definimos: excess_blobs <— max(excess_blobs + len(block.blobs) - TARGET, 0) Onde TARGET = 3. Ou seja, se um bloco tiver mais blobs do que o alvo, excess_blobs aumenta, e se um bloco tiver menos do que o alvo, diminui. Em seguida, definimos blob_basefee = exp(excess_blobs / 25.47), onde exp é uma aproximação da função exponencial 𝑒𝑥𝑝(𝑥)=2.71828𝑥 . Ou seja, sempre que o excesso de blobs aumenta em ~25, a taxa base de blobs aumenta por um fator de ~2,7. Se os blobs ficarem muito caros, o uso médio diminui e o excesso de blobs começa a diminuir, diminuindo automaticamente o preço novamente. O preço de um blob ajusta constantemente para garantir que, em média, os blocos estejam meio cheios - ou seja, contêm em média 3 blobs cada. Se houver um pico de uso a curto prazo, então o limite entra em ação: cada bloco só pode conter um máximo de 6 blobs e, nessas circunstâncias, as transações podem competir entre si, aumentando as suas taxas de prioridade. No caso normal, no entanto, cada blob só precisa pagar a blob_basefee mais uma pequena taxa de prioridade extra como incentivo para ser incluído. Esse tipo de precificação existia no Ethereum para gás há anos: um mecanismo muito semelhante foi introduzido com @vbuterin/eip-1559-faq">O EIP-1559 está de volta em 2020. Com o EIP-4844, agora temos dois preços flutuantes separados para gás e para blobs. Taxa base de gás ao longo de uma hora em 08-05-2024, em gwei. Fonte: ultrasound.money. Em princípio, poderíamos adicionar mais taxas separadas para leitura de armazenamento e outros tipos de operações, embora com uma ressalva que irei expandir na próxima seção. Para os usuários, a experiência é notavelmente semelhante à de hoje: em vez de pagar uma taxa básica, você paga duas taxas básicas, mas sua carteira pode abstrair isso de você e apenas mostrar a taxa esperada e a taxa máxima que você pode esperar pagar. Para os construtores de blocos, na maioria das vezes a estratégia ótima é a mesma de hoje: incluir tudo o que for válido. A maioria dos blocos não está cheia - nemem gásnemem manchas. O caso desafiador é quando há gás suficiente ou blobs suficientes para exceder o limite do bloco, e o construtor precisa potencialmente resolver um problema da mochila multidimensionalpara maximizar o seu lucro. No entanto, mesmo existindo algoritmos de aproximação bastante bons, e os ganhos ao desenvolver algoritmos proprietários para otimizar lucros neste caso são muito menores do que os ganhos ao fazer o mesmo com MEV. Para os programadores, o desafio principal é a necessidade de redesenhar as funcionalidades da EVM e da sua infraestrutura envolvente, que está desenhada em torno de um preço e de um limite hoje em dia, para um design que acomode múltiplos preços e múltiplos limites. Um problema para os programadores de aplicações é que a otimização se torna ligeiramente mais difícil: em alguns casos, já não se pode dizer de forma inequívoca que A é mais eficiente do que B, porque se A utiliza mais calldata mas B utiliza mais execução, então A pode ser mais barato quando a calldata é barata e mais caro quando a calldata é cara. No entanto, os programadores ainda conseguem obter resultados razoavelmente bons ao otimizar com base nos preços médios históricos a longo prazo. Há um problema que não apareceu com blobs e não aparecerá com EIP-7623 ou mesmo com uma implementação de preços multidimensionais 'completos' para calldata, mas aparecerá se tentarmos precificar separadamente os acessos ao estado, ou qualquer outro recurso: limites de gás em sub-chamadas. Os limites de gás no EVM existem em dois lugares. Em primeiro lugar, cada transação define um limite de gás, que limita a quantidade total de gás que pode ser usada nessa transação. Em segundo lugar, quando um contrato chama outro contrato, a chamada pode definir seu próprio limite de gás. Isso permite que contratos chamem outros contratos nos quais não confiam e ainda garantam que terão gás restante para realizar outras computações após essa chamada. Um rastro de uma transação de abstração de conta, onde uma conta chama outra conta e dá ao destinatário uma quantidade limitada de gás, para garantir que a chamada externa possa continuar mesmo que o destinatário consuma todo o gás que lhe foi atribuído. O desafio é: tornar o gás multidimensional entre diferentes tipos de execução parece que exigiria subchamadas para fornecer múltiplos limites para cada tipo de gás, o que exigiria uma mudança realmente profunda no EVM e não seria compatível com as aplicações existentes. Esta é uma das razões pelas quais as propostas de gás multidimensionais frequentemente param em duas dimensões: dados e execução. Os dados (seja calldata de transação ou blobs) são apenas atribuídos fora do EVM, e assim nada dentro do EVM precisa mudar para tornar a calldata ou blobs separadamente precificados. Podemos pensar numa solução do estilo “EIP-7623” para este problema. Aqui está uma implementação simples: durante a execução, cobrar 4x mais pelas operações de armazenamento; para simplificar a análise, digamos 10000 gás por operação de armazenamento. No final da transação, reembolsar min(7500 * operações_de_armazenamento, gás_de_execução). O resultado seria que, após subtrair o reembolso, um usuário é cobrado: execution_gás + 10000 operações de armazenamento - min(7500 operações de armazenamento, gás de execução) Que equivale a: max(execution_gás + 2500 operações de armazenamento, 10000storage_operations) Este espelha a estrutura do EIP-7623. Outra maneira de o fazer é seguir as storage_operations e execution_gas em tempo real e cobrar 2500 ou 10000, dependendo de quanto max(execution_gas + 2500operações de armazenamento, 10000A quantidade de gás consumida pelas operações de armazenamento (storage_operations) aumenta no momento em que o opcode é chamado. Isso evita a necessidade de transações alocarem gás em excesso, pois a maior parte será devolvida através de reembolsos. Não obtemos permissões detalhadas para subchamadas: uma subchamada pode consumir toda a "permissão" de uma transação para operações de armazenamento baratas. Mas obtemos algo suficientemente bom, onde um contrato que faz uma subchamada pode definir um limite e garantir que, uma vez que a subchamada termine de executar, a chamada principal ainda tenha gás suficiente para fazer qualquer pós-processamento necessário. A solução de preços multidimensionais mais simples que consigo pensar é: tratamos os limites de gás de sub-chamada como sendo proporcionais. Ou seja, suponha que haja 𝑘 diferentes tipos de execução, e cada transação define um limite multidimensional 𝐿1…𝐿𝑘 Suponha que, no ponto atual da execução, o gás restante seja 𝑔1…𝑔𝑘 Suponha que um opcode de CHAMADA seja chamado, com limite de gás de sub-chamada 𝑆 . Deixa 𝑠1=𝑆 , e depois 𝑠2=𝑠1𝑔1∗𝑔2 , 𝑠3=𝑠1𝑔1∗𝑔3 , e assim por diante. Isto é, tratamos o primeiro tipo de gás (realisticamente, execução VM) como sendo uma espécie de “unidade de conta” privilegiada e, em seguida, atribuímos os outros tipos de gás para que a sub-chamada obtenha a mesma percentagem de gás disponível em cada tipo. Isto é um pouco feio, mas maximiza a compatibilidade com versões anteriores. Se quisermos tornar o esquema mais “neutro” entre diferentes tipos de gás, ao custo de sacrificar a compatibilidade com versões anteriores, poderíamos simplesmente fazer com que o parâmetro de limite de gás da sub-chamada represente uma fração (por exemplo, [1…63] / 64) do gás restante no contexto atual). Em qualquer caso, no entanto, vale a pena salientar que, uma vez que comece a introduzir gás de execução multidimensional, o nível inerente de feiura aumenta, e isso parece difícil de evitar. Portanto, a nossa tarefa é fazer um compromisso complicado: aceitamos um pouco mais de feiura ao nível do EVM, a fim de desbloquear com segurança ganhos significativos de escalabilidade L1, e, em caso afirmativo, qual proposta específica funciona melhor para a economia do protocolo e para os desenvolvedores de aplicações? Muito provavelmente, não é nenhuma das que mencionei acima, e ainda há espaço para encontrar algo mais elegante e melhor.Blobs: gás multidimensional em Dencun
Clientes sem estado e gás multidimensional
Gás multidimensional mais geralmente
Máximo por transação: a forma mais fraca, mas mais fácil de obter gás multidimensional
Multidimensional EIP-1559: a estratégia mais difícil, mas ideal
Preços multidimensionais, o EVM e sub-chamadas
Aviso legal:
Compartilhar
Conteúdo
No Ethereum, os recursos eram até recentemente limitados e com preços, usando um único recurso chamado "gás". O gás é uma medida da quantidade de "esforço computacional" necessário para processar uma determinada transação ou bloco. O gás combina vários tipos de "esforço", principalmente:
Por exemplo, esta transaçãoque enviei custou um total de 47.085 gás. Isto é dividido entre (i) um custo base de 21000 gás, (ii) 1556 gás para os bytes nos dados de chamada incluídos na transação (iii) 16500 gás para leitura e escrita no armazenamento, (iv) gás 2149 para fazer um registo, e o restante para a execução do EVM. A taxa de transação que um utilizador deve pagar é proporcional ao gás que a transação consome. Um bloco pode conter até um máximo de 30 milhões de gás, e os preços do gás são constantemente ajustados através do @vbuterinMecanismo de segmentação EIP-1559, garantindo que, em média, os blocos contenham 15 milhões de gás.
Esta abordagem tem uma eficiência principal: porque tudo é fundido num recurso virtual único, conduz a um design de mercado muito simples. Otimizar uma transação para minimizar os custos é fácil, otimizar um bloco para recolher as taxas mais altas possíveis é relativamente fácil (não incluindoMEV) e não existem incentivos estranhos que encorajem algumas transações a agrupar-se com outras transações para poupar em taxas.
Mas essa abordagem também tem uma grande ineficiência: trata diferentes recursos como sendo mutuamente conversíveis, quando os limites reais subjacentes do que a rede pode lidar não são. Uma maneira de entender este problema é olhar para este diagrama:
O limite de gás impõe uma restrição de
𝑥1∗𝑑𝑎𝑡𝑎+𝑥2∗𝑐𝑜𝑚𝑝𝑢𝑡𝑎𝑡𝑖𝑜𝑛<𝑁
. A restrição real de segurança subjacente muitas vezes está mais próxima de
máx(x1*dados,x2*computação) . Esta discrepância leva a que o limite de gás exclua desnecessariamente blocos realmente seguros, ou aceite blocos realmente inseguros, ou alguma mistura de ambos. Se houver n recursos que têm limites de segurança distintos, então o gás unidimensional reduz plausivelmente a capacidade em até um fator de n . Por esta razão, há muito tempo que existe interesse no conceito de gás multi-dimensional e com EIP-4844na verdade, temos gás multidimensional a funcionar no Ethereum hoje. Esta publicação explora os benefícios deste abordagem e as perspetivas de aumentá-la ainda mais. No início deste ano, o bloco médio era 150 kB em tamanho. Uma grande fração desse tamanho é dados de rollup: protocolos de camada 2armazenar dados na cadeia para segurança. Estes dados eram caros: embora as transações em rollups custassem cerca de 5-10x menos do que as transações correspondentes na Ethereum L1, mesmo esse custo era demasiado elevado para muitos casos de uso. Porque não diminuir o custo do gás da calldata (atualmente 16 gás por byte não nulo e 4 gás por byte nulo), para tornar os rollups mais baratos? Nós fez isto antes, podemos fazer de novo. A resposta aqui é: o tamanho do pior caso de um bloco foi 30,000,00016=1,875,000 bytes não nulos, e a rede já mal consegue lidar com blocos desse tamanho. Reduzir os custos em mais 4x aumentaria o máximo para 7,5 MB, o que representaria um enorme risco para a segurança. Este problema acabou por ser resolvido ao introduzir um espaço separado de dados compatíveis com rollup, conhecido como "blobs", em cada bloco. Os dois recursos têm preços e limites separados: após o hard fork do Dencun, um bloco Ethereum pode conter no máximo (i) 30 milhões de gás e (ii) 6 blobs, que podem conter ~125 kB de calldata cada. Ambos os recursos têm preços separados, ajustados pormecanismos de preços semelhantes ao EIP-1559 separados, visando um uso médio de 15 milhões de gás e 3 blobs por bloco. Como resultado, os rollups tornaram-se 100 vezes mais baratos, o volume de transações nos rollups aumentou mais de 3 vezes e o tamanho máximo teórico do bloco foi apenas ligeiramente aumentado: de ~1,9 MB para ~2,6 MB. Taxas de transação em rollups, cortesia de growthepie.xyz. O fork Dencun, que introduziu blobs com preços multidimensionais, aconteceu em 13 de março de 2024. Num futuro próximo, surgirá um problema semelhante em relação às provas de armazenamento para clientes sem estado. Os clientes sem estado são um novo tipo de cliente que será capaz de verificar a cadeia sem armazenar muitos ou quaisquer dados localmente. Os clientes sem estado fazem isso ao aceitar provas das partes específicas do estado do Ethereum que as transações nesse bloco precisam alcançar. Um cliente sem estado recebe um bloco, juntamente com provas que comprovam os valores atuais nas partes específicas do estado (por exemplo, saldos de conta, código, armazenamento) que a execução do bloco toca. Isso permite que um nó verifique um bloco sem ter qualquer armazenamento próprio. Uma leitura de armazenamento custa 2100-2600 gás, dependendo do tipo de leitura, e as escritas de armazenamento custam mais. Em média, um bloco faz cerca de 1000 leituras e escritas de armazenamento (incluindo verificações de saldo de ETH, chamadas SSTORE e SLOAD, leitura de código de contrato e outras operações). O máximo teórico, no entanto, é 30,000,0002,100=14,285 lê. A carga de largura de banda de um cliente sem estado é diretamente proporcional a este número. Hoje, o plano é apoiar clientes sem estado ao mover o design da árvore de estado do Ethereum deÁrvores de Merkle PatriciaparaÁrvores VerkleNo entanto, as árvores Verkle não são resistentes a quantuns e não são ótimas para as novas ondas de sistemas de prova STARK. Como resultado, muitas pessoas estão interessadas em apoiar clientes sem estado através de árvores de Merkle binárias e STARKsem vez disso - seja pulando Verkle completamente, ou atualizando alguns anos após a transição do Verkle uma vez que os STARKs se tornem mais maduros. As provas STARK de ramos de árvore de hash binário têm muitas vantagens, mas têm a fraqueza chave de que as provas demoram muito tempo a ser geradas: enquanto Árvores Verklepode provarmais de cem mil valores por segundo, STARKs baseados em hash geralmente conseguem provar apenas alguns milhares de hashes por segundo, e provar cada valor requer um “ramo” contendo muitos hashes. Dado os números que estão sendo projetados hoje a partir de sistemas de prova hiper-otimizados como BiniusePlonky3e hashes especializados comoVisão-Mark-32, parece provável que por algum tempo estaremos num regime em que é prático provar 1.000 valores em menos de um segundo, mas não 14.285 valores. Blocos médios seriam aceitáveis, mas blocos de pior caso, potencialmente publicados por um atacante, iriam quebrar a rede. A forma “padrão” como lidamos com esse cenário é a repricing: tornar a leitura de armazenamento mais cara para reduzir o máximo por bloco para algo mais seguro. No entanto, nós temos jáfeitoistomuitosvezes, e isso tornaria demasiadas aplicações demasiado caras para fazer isto novamente. Uma abordagem melhor seria gás multidimensional: limitar e cobrar separadamente pelo acesso ao armazenamento, mantendo o uso médio em 1.000 acessos ao armazenamento por bloco, mas definindo um limite por bloco de, por exemplo, 2.000. Outro recurso que vale a pena considerar é o crescimento do tamanho do estado: operações que aumentam o tamanho do estado do Ethereum, que os nós completos precisarão manter a partir de então. A propriedade única do crescimento do tamanho do estado é que a justificativa para limitá-lo vem inteiramente do uso sustentado a longo prazo e não de picos. Portanto, pode haver valor em adicionar uma dimensão de gás separada para operações de aumento do tamanho do estado (por exemplo, SSTORE de zero para não zero, criação de contrato), mas com um objetivo diferente: poderíamos definir um preço flutuante para atingir um uso médio específico, mas não estabelecer limite por bloco. Isto mostra uma das propriedades poderosas do gás multidimensional: permite-nos perguntar separadamente qual é o uso médio ideal e qual é o uso máximo seguro por bloco, para cada recurso. Em vez de definir os preços do gás com base nos máximos por bloco e deixar que o uso médio siga, nós temos 2𝑛 graus de liberdade para definir 2𝑛 parâmetros, ajustando cada um com base no que é seguro para a rede. Situações mais complicadas, como aquelas em que dois recursos têm considerações de segurança parcialmente aditivas, poderiam ser tratadas fazendo com que um opcode ou custo de recurso consumisse uma quantidade de vários tipos de gás (por exemplo, um SSTORE de zero para não zero poderia custar 5000 gás de prova do cliente sem estado e 20000 gás de expansão de armazenamento). Deixe 𝑥1 ser o custo de gás de dados e 𝑥2 ser o custo de gás da computação, assim em um sistema de gás unidimensional podemos escrever o custo de gás de uma transação: gás=𝑥1∗𝑑𝑎𝑡𝑎+𝑥2∗c𝑜𝑚𝑝𝑢𝑡açã𝑜 Neste esquema, definimos em vez disso o custo de gás de uma transação como: gás=máx(x1*data,x2*computação) Ou seja, em vez de uma transação ser cobrada por dados mais computação, a transação é cobrada com base em qual dos dois recursos consome mais. Isso pode ser facilmente estendido para abranger mais dimensões (por exemplo, max(…,x3*storagemax) ). Deve ser fácil ver como isso melhora a taxa de transferência sem comprometer a segurança. A quantidade máxima teórica de dados em um bloco ainda é 𝐺𝐴𝑆𝐿𝐼𝑀𝐼𝑇𝑥1 , exatamente o mesmo que no esquema de gás unidimensional. Da mesma forma, a quantidade máxima teórica de computação é 𝐺𝐴𝑆𝐿𝐼𝑀𝐼𝑇𝑥2 , novamente exatamente o mesmo que no esquema de gás unidimensional. No entanto, o custo de gás de qualquer transação que consuma tanto dados quanto computação diminui. Esta é aproximadamente o esquema empregado no propostoEIP-7623, para reduzir o tamanho máximo do bloco enquanto aumenta ainda mais a contagem de blobs. O mecanismo preciso no EIP-7623 é um pouco mais complicado: mantém o preço atual dos dados de chamada de 16 gás por byte, mas adiciona um "preço mínimo" de 48 gás por byte; uma transação paga o mais elevado de (16 bytes + execution_gas) e (48 bytes). Como resultado, o EIP-7623 diminui o tamanho teórico máximo do calldata da transação em um bloco de ~1,9 MB para ~0,6 MB, mantendo os custos da maioria das aplicações inalterados. O benefício dessa abordagem é que ela representa uma alteração muito pequena em relação ao esquema de gás unidimensional atual, o que torna sua implementação muito fácil. Existem duas desvantagens: Eu argumentaria que uma regra no estilo EIP-7623, tanto para os dados da transação quanto para outros recursos, pode trazer benefícios suficientemente grandes para valer a pena, mesmo apesar dessas desvantagens. No entanto, se e quando estivermos dispostos a dedicar um esforço de desenvolvimento (significativamente maior), existe uma abordagem mais ideal. Vamos primeiro recapitular como funciona o EIP-1559 "regular". Vamos nos concentrar na versão que foi introduzida no EIP-4844 para blobs, porque é matematicamente mais elegante. Rastreamos um parâmetro, excess_blobs. Durante cada bloco, definimos: excess_blobs <— max(excess_blobs + len(block.blobs) - TARGET, 0) Onde TARGET = 3. Ou seja, se um bloco tiver mais blobs do que o alvo, excess_blobs aumenta, e se um bloco tiver menos do que o alvo, diminui. Em seguida, definimos blob_basefee = exp(excess_blobs / 25.47), onde exp é uma aproximação da função exponencial 𝑒𝑥𝑝(𝑥)=2.71828𝑥 . Ou seja, sempre que o excesso de blobs aumenta em ~25, a taxa base de blobs aumenta por um fator de ~2,7. Se os blobs ficarem muito caros, o uso médio diminui e o excesso de blobs começa a diminuir, diminuindo automaticamente o preço novamente. O preço de um blob ajusta constantemente para garantir que, em média, os blocos estejam meio cheios - ou seja, contêm em média 3 blobs cada. Se houver um pico de uso a curto prazo, então o limite entra em ação: cada bloco só pode conter um máximo de 6 blobs e, nessas circunstâncias, as transações podem competir entre si, aumentando as suas taxas de prioridade. No caso normal, no entanto, cada blob só precisa pagar a blob_basefee mais uma pequena taxa de prioridade extra como incentivo para ser incluído. Esse tipo de precificação existia no Ethereum para gás há anos: um mecanismo muito semelhante foi introduzido com @vbuterin/eip-1559-faq">O EIP-1559 está de volta em 2020. Com o EIP-4844, agora temos dois preços flutuantes separados para gás e para blobs. Taxa base de gás ao longo de uma hora em 08-05-2024, em gwei. Fonte: ultrasound.money. Em princípio, poderíamos adicionar mais taxas separadas para leitura de armazenamento e outros tipos de operações, embora com uma ressalva que irei expandir na próxima seção. Para os usuários, a experiência é notavelmente semelhante à de hoje: em vez de pagar uma taxa básica, você paga duas taxas básicas, mas sua carteira pode abstrair isso de você e apenas mostrar a taxa esperada e a taxa máxima que você pode esperar pagar. Para os construtores de blocos, na maioria das vezes a estratégia ótima é a mesma de hoje: incluir tudo o que for válido. A maioria dos blocos não está cheia - nemem gásnemem manchas. O caso desafiador é quando há gás suficiente ou blobs suficientes para exceder o limite do bloco, e o construtor precisa potencialmente resolver um problema da mochila multidimensionalpara maximizar o seu lucro. No entanto, mesmo existindo algoritmos de aproximação bastante bons, e os ganhos ao desenvolver algoritmos proprietários para otimizar lucros neste caso são muito menores do que os ganhos ao fazer o mesmo com MEV. Para os programadores, o desafio principal é a necessidade de redesenhar as funcionalidades da EVM e da sua infraestrutura envolvente, que está desenhada em torno de um preço e de um limite hoje em dia, para um design que acomode múltiplos preços e múltiplos limites. Um problema para os programadores de aplicações é que a otimização se torna ligeiramente mais difícil: em alguns casos, já não se pode dizer de forma inequívoca que A é mais eficiente do que B, porque se A utiliza mais calldata mas B utiliza mais execução, então A pode ser mais barato quando a calldata é barata e mais caro quando a calldata é cara. No entanto, os programadores ainda conseguem obter resultados razoavelmente bons ao otimizar com base nos preços médios históricos a longo prazo. Há um problema que não apareceu com blobs e não aparecerá com EIP-7623 ou mesmo com uma implementação de preços multidimensionais 'completos' para calldata, mas aparecerá se tentarmos precificar separadamente os acessos ao estado, ou qualquer outro recurso: limites de gás em sub-chamadas. Os limites de gás no EVM existem em dois lugares. Em primeiro lugar, cada transação define um limite de gás, que limita a quantidade total de gás que pode ser usada nessa transação. Em segundo lugar, quando um contrato chama outro contrato, a chamada pode definir seu próprio limite de gás. Isso permite que contratos chamem outros contratos nos quais não confiam e ainda garantam que terão gás restante para realizar outras computações após essa chamada. Um rastro de uma transação de abstração de conta, onde uma conta chama outra conta e dá ao destinatário uma quantidade limitada de gás, para garantir que a chamada externa possa continuar mesmo que o destinatário consuma todo o gás que lhe foi atribuído. O desafio é: tornar o gás multidimensional entre diferentes tipos de execução parece que exigiria subchamadas para fornecer múltiplos limites para cada tipo de gás, o que exigiria uma mudança realmente profunda no EVM e não seria compatível com as aplicações existentes. Esta é uma das razões pelas quais as propostas de gás multidimensionais frequentemente param em duas dimensões: dados e execução. Os dados (seja calldata de transação ou blobs) são apenas atribuídos fora do EVM, e assim nada dentro do EVM precisa mudar para tornar a calldata ou blobs separadamente precificados. Podemos pensar numa solução do estilo “EIP-7623” para este problema. Aqui está uma implementação simples: durante a execução, cobrar 4x mais pelas operações de armazenamento; para simplificar a análise, digamos 10000 gás por operação de armazenamento. No final da transação, reembolsar min(7500 * operações_de_armazenamento, gás_de_execução). O resultado seria que, após subtrair o reembolso, um usuário é cobrado: execution_gás + 10000 operações de armazenamento - min(7500 operações de armazenamento, gás de execução) Que equivale a: max(execution_gás + 2500 operações de armazenamento, 10000storage_operations) Este espelha a estrutura do EIP-7623. Outra maneira de o fazer é seguir as storage_operations e execution_gas em tempo real e cobrar 2500 ou 10000, dependendo de quanto max(execution_gas + 2500operações de armazenamento, 10000A quantidade de gás consumida pelas operações de armazenamento (storage_operations) aumenta no momento em que o opcode é chamado. Isso evita a necessidade de transações alocarem gás em excesso, pois a maior parte será devolvida através de reembolsos. Não obtemos permissões detalhadas para subchamadas: uma subchamada pode consumir toda a "permissão" de uma transação para operações de armazenamento baratas. Mas obtemos algo suficientemente bom, onde um contrato que faz uma subchamada pode definir um limite e garantir que, uma vez que a subchamada termine de executar, a chamada principal ainda tenha gás suficiente para fazer qualquer pós-processamento necessário. A solução de preços multidimensionais mais simples que consigo pensar é: tratamos os limites de gás de sub-chamada como sendo proporcionais. Ou seja, suponha que haja 𝑘 diferentes tipos de execução, e cada transação define um limite multidimensional 𝐿1…𝐿𝑘 Suponha que, no ponto atual da execução, o gás restante seja 𝑔1…𝑔𝑘 Suponha que um opcode de CHAMADA seja chamado, com limite de gás de sub-chamada 𝑆 . Deixa 𝑠1=𝑆 , e depois 𝑠2=𝑠1𝑔1∗𝑔2 , 𝑠3=𝑠1𝑔1∗𝑔3 , e assim por diante. Isto é, tratamos o primeiro tipo de gás (realisticamente, execução VM) como sendo uma espécie de “unidade de conta” privilegiada e, em seguida, atribuímos os outros tipos de gás para que a sub-chamada obtenha a mesma percentagem de gás disponível em cada tipo. Isto é um pouco feio, mas maximiza a compatibilidade com versões anteriores. Se quisermos tornar o esquema mais “neutro” entre diferentes tipos de gás, ao custo de sacrificar a compatibilidade com versões anteriores, poderíamos simplesmente fazer com que o parâmetro de limite de gás da sub-chamada represente uma fração (por exemplo, [1…63] / 64) do gás restante no contexto atual). Em qualquer caso, no entanto, vale a pena salientar que, uma vez que comece a introduzir gás de execução multidimensional, o nível inerente de feiura aumenta, e isso parece difícil de evitar. Portanto, a nossa tarefa é fazer um compromisso complicado: aceitamos um pouco mais de feiura ao nível do EVM, a fim de desbloquear com segurança ganhos significativos de escalabilidade L1, e, em caso afirmativo, qual proposta específica funciona melhor para a economia do protocolo e para os desenvolvedores de aplicações? Muito provavelmente, não é nenhuma das que mencionei acima, e ainda há espaço para encontrar algo mais elegante e melhor.Blobs: gás multidimensional em Dencun
Clientes sem estado e gás multidimensional
Gás multidimensional mais geralmente
Máximo por transação: a forma mais fraca, mas mais fácil de obter gás multidimensional
Multidimensional EIP-1559: a estratégia mais difícil, mas ideal
Preços multidimensionais, o EVM e sub-chamadas
Aviso legal: