No artigo The Three Transitions, Vitalik Buterin, o fundador da Ethereum, elaborou claramente a "rede principal (doravante denominada L1) + camada 2 cross-chain (doravante denominada cross-L2) support"" "Segurança da carteira" e "privacidade" são valores importantes como as funções necessárias da pilha do ecossistema. Eles não devem ser apenas alguns componentes adicionais, e uma carteira separada fornece funções relacionadas.
E este artigo, apontou Vitalik Buterin, se concentrará em uma questão técnica fundamental: como ler mais facilmente dados L1 de L2; ou ler dados L2 de L1; ou como ler mais facilmente dados L2 de um L2 Ler dados de outro L2 . **
Vitalik Buterin apontou que a chave para resolver os problemas acima está em como realizar a separação de ativos e keystores. Essa tecnologia também tem casos de uso muito valiosos em outras áreas além do dimensionamento, como a mobilidade de ativos entre L1 e L2.
** Qual é o objetivo de fazer isso? **
Assim que o L2 se tornar popular, os usuários poderão possuir ativos em vários L2s e possivelmente também no L1.
Uma vez que as carteiras de contratos inteligentes se tornem populares, as "chaves" agora comuns não serão mais usadas.
Uma vez que essas duas coisas aconteçam ao mesmo tempo, os usuários precisarão de um método que não exija um grande número de transações para alterar as chaves de contas diferentes.
Em particular, precisamos de uma maneira de lidar com endereços "contrafactuais" (também conhecidos como "endereços hipotéticos"): endereços que ainda não estão "registrados" na cadeia de forma alguma, mas ainda precisam receber e manter ativos com segurança .
Na verdade, todos nós contamos com essa "configuração contrafactual" de endereços: quando um usuário usa Ethereum pela primeira vez, o usuário pode gerar um endereço ETH e outros podem pagar para essa conta sem precisar se registrar no blockchain. Cadastre-se" o endereço (mas você precisará pagar taxas de transação, então você precisa manter algum ETH).
Para contas externas (EOA), de fato, todos os endereços começam no endereço do "cenário contrafactual".
Endereços "definidos contrafactualmente" ainda são possíveis com carteiras de contratos inteligentes, em grande parte graças ao CREATE2, que permite que você tenha um endereço ETH que só pode ser criado por código de contrato inteligente que corresponda a um preenchimento de hash específico.
△ Algoritmo de cálculo de endereço EIP-1014 (CREATE2).
No entanto, a introdução de carteiras de contrato inteligentes também traz novos desafios: **As chaves de acesso podem mudar. **Essa alteração é que o endereço é o valor hash do initcode, que pode conter apenas a chave de verificação inicial da carteira, e a chave de verificação atual será armazenada no armazenamento da carteira, mas o registro do armazenamento não será automaticamente transferido para outro L2.
Se um usuário tiver endereços em muitos L2s, apenas a Separação de ativos e arquitetura de armazenamento de chaves poderá ajudar os usuários a alterar suas chaves.
A estrutura dessa arquitetura dividida é que cada usuário tem (i) um "contrato de armazenamento de chaves" (no L1 ou em uma cadeia L2 específica) que armazena chaves de verificação para todas as carteiras e regras para alteração de chaves e (ii) "contratos de carteira " em L1 e em muitas cadeias L2, que obtêm chaves de verificação por meio de leituras cruzadas.
Há duas maneiras de implementar a arquitetura de separação de armazenamento de chaves e ativos:
Versão leve (ou seja, verifica apenas as chaves atualizadas): Cada carteira armazena a chave de verificação localmente e contém uma função que pode ser chamada para verificar a prova de cadeia cruzada do estado atual do armazenamento de chaves e atualizar o armazenamento local A autenticação chave a combinar. Chamar esta função para obter a chave de autenticação atual do keystore é necessário ao usar a carteira pela primeira vez em um L2.
**Vantagens: **O uso de provas cross-chain é mais prudente, e não haverá custos de operação de rede muito caros. Todos os ativos só podem ser usados com a chave atual, então a segurança ainda é garantida.
**Desvantagens: **Necessidade de alteração da chave de verificação, a alteração da chave on-chain deve ser realizada no keystore e em cada carteira que foi inicializada, podendo consumir muito Gas Fee.
Versão completa (ou seja, todas as transações são verificadas): Cada transação requer uma prova de cadeia cruzada mostrando a chave atual no armazenamento de chaves.
Vantagens: A complexidade do sistema é baixa e o keystore é atualizado rapidamente.
**Desvantagens: **A taxa de operação de rede de uma única transação é alta e não é fácil ser compatível com ERC-4337. Atualmente, o ERC-4337 não oferece suporte à leitura de objetos mutáveis entre contratos durante a verificação.
**O que é prova de cadeia cruzada? **
Para demonstrar a complexidade das provas de cadeia cruzada, selecionamos um dos cenários de aplicação mais complexos para demonstrar e explicar este princípio técnico. Este cenário de aplicação complexo é o seguinte: a chave é armazenada em um L2 e a carteira está em outro L2. Se o keystore na carteira estiver em L1, apenas metade desse design será necessário.
Suponha que o keystore esteja no Linea e a carteira esteja no Kakarot. O processo completo de certificação da chave da carteira precisa incluir:
Prova da raiz atual do estado Linea, dada a raiz atual do estado Ethereum conhecida por Kakarot.
Prova da chave atual no keystore, dada a raiz atual do estado Linea.
Existem duas questões principais de implementação espinhosas aqui: "Que tipo de prova precisa ser usada? (É uma prova de Merkle? Ou outra coisa?)" e "Como L2 aprende a raiz do estado L1 mais próxima?" Ou, "L1 Como aprender a raiz do estado de L2?"
Então, em ambos os casos, quanto tempo demora entre quando um evento ocorre de um lado e quando a outra parte é capaz de fornecer provas?
**Quais esquemas de prova estão disponíveis para nós? **
Existem cinco métodos principais para escolher:
Prova Merkle
General ZK-SNARKs
Certificado para fins especiais (por exemplo, usando KZG)
Verkle proof, entre KZG e ZK-SNARKs, considerando tanto esforço quanto custo de infraestrutura
sem prova, depende da leitura direta do estado
Em termos de trabalho de infraestrutura necessário e custos do usuário, eles podem ser classificados da seguinte forma:
"Agregação" refere-se à agregação de todas as provas fornecidas pelos usuários em cada bloco em uma grande metaprova, mesclando-as. Isso funciona para SNARKs e KZG, mas não para garfos Merkle.
Na verdade, a "agregação" só tem valor quando a solução possui um grande número de usuários.
**Como funcionam as provas Merkle? **
Este problema é muito simples e pode ser seguido diretamente pelo diagrama da seção anterior. Cada "prova" (assumindo que um L2 é provado ser outro L2, que é o cenário de aplicação mais difícil) incluirá:
Um fork Merkle que atesta a raiz do estado do keystore L2, a última raiz do estado do Ethereum conhecida por L2. As raízes de estado que contêm o keystore L2 são armazenadas em slots de armazenamento conhecidos em endereços conhecidos (contratos L1 representando L2), para que os caminhos possam ser codificados permanentemente.
Uma ramificação Merkle atestando a chave de verificação atual, de acordo com a raiz do estado que contém o keystore L2. Além disso, as chaves de autenticação são armazenadas em slots conhecidos em endereços conhecidos, portanto, os caminhos podem ser codificados permanentemente.
No entanto, as provas de estado no Ethereum são complicadas, mas existem bibliotecas que podem ser usadas para verificá-las e, se usar essas bibliotecas, o mecanismo não é muito complicado.
No entanto, o maior desafio é o custo. ** Merkle provou ser muito longo, e a árvore Patricia era 3,9 vezes mais longa do que o necessário - muito mais alto do que o preço base atual de 21.000 Gas Fee por transação.
Porém, se a prova for verificada em L2, a discrepância se agrava. A computação dentro de L2 é barata porque a computação é feita fora da cadeia e em um ecossistema com menos nós que L1.
Podemos calcular o que isso significa observando a comparação entre o custo da taxa de gás L1 e o custo da taxa de gás L2:
Atualmente, se for uma operação de envio relativamente simples, o custo na rede L1 é cerca de 15 a 25 vezes maior que o de L2, e o custo de troca de Token é cerca de 20 a 50 vezes maior que o de L2.
A operação de envio simples tem uma grande quantidade de dados; e a operação de troca requer maior poder de computação, portanto, a operação de troca é uma referência melhor para aproximar o custo do cálculo L1 e cálculo L2.
Juntando o que foi dito acima, se assumirmos uma relação de custo de 30x entre o custo computacional L1 e o custo computacional L2, isso parece implicar que o custo de colocar provas de Merkle em L2 pode ser equivalente a cerca de cinquenta transações regulares.
Claro, usar uma árvore Merkle binária reduziria o custo por um fator de cerca de 4, mas mesmo assim o custo ainda seria proibitivo na maioria dos casos, e se estivéssemos dispostos a desistir da compatibilidade com a árvore de estado hexa atual do Ethereum, isso poderia Irá procurar melhores opções.
**Como funciona a prova ZK-SNARK? **
O uso de ZK-SNARKs também é conceitualmente fácil de entender: basta substituir as provas de Merkle no diagrama acima por ZK-SNARKs provando a existência dessas provas de Merkle. O valor de cálculo de um ZK-SNARK é de cerca de 400.000 Gas Fee, cerca de 400 bytes; uma transação básica requer 21.000 Gas Fee e 100 bytes.
Portanto, do ponto de vista do cálculo, o custo do ZK-SNARK é 19 vezes o custo da transação básica atual; do ponto de vista dos dados, o custo do ZK-SNARK é 4 vezes o custo da transação básica atual e 16 vezes o futuro custo de transação básico.
Esses números representam uma grande melhoria em relação às provas de Merkle, mas ainda são bastante caros. Existem duas maneiras de melhorar esta situação: (i) provas KZG para fins especiais, ou (ii) agregação, semelhante à agregação ERC-4337.
**Como funciona a prova KZG para fins especiais? **
Primeiro, uma recapitulação de como as promessas KZG funcionam:
*[D_1 ...D_n] representa um conjunto de dados através do qual a prova polinomial KZG é derivada. *
*Especificamente, o polinômio P, onde P(w) = D_1, P(w²) = D_2 ... P(wⁿ) = D_n. onde é a "raiz uniforme", para algum Campo de avaliação tamanho N, valor wN = 1 (tudo isso é feito em campos finitos). *
Para "comprometer" com P, criamos um ponto de curva elíptica com(P) = P₀ * G + P₁ * S₁ + ... + Pk * Sk. aqui:*
G é o ponto gerador da curva
Pi é o coeficiente i do polinômio P
Si é o ponto i no cenário confiável
*E para provar que P(z) = a, criamos um quociente polinomial Q = (P - a) / (X - z) e criamos um compromisso com(Q). Só é possível criar tal polinômio se P(z) for realmente igual a a. *
Para verificar a prova, verificamos a equação Q * (X - z) = P - a realizando uma verificação de curva elíptica na prova com(Q) e o compromisso polinomial com(P): verificamos e(com( Q), com (X - z)) ? = e(com(P) - com(a), com(1))*
Algumas propriedades importantes que você também deve conhecer incluem:
A prova é apenas o valor com(Q), que é de 48 bytes
com(P₁) + com(P₂) = com(P₁ + P₂)
*Isso também significa que você pode "editar" o valor em um contrato existente. *
Suponha que sabemos que D_i é atualmente a, queremos defini-lo como b e o compromisso existente para D é com(P). promessa "P, mas P(wⁱ) = b, e nenhuma outra mudança de avaliação", então definimos com(new_P) = com(P) + (ba)*com(Li), onde Li é "lag Langeriano polinomial", igual a 1 em wⁱ e 0 em outros pontos wj. *
Para executar essas atualizações com eficiência, cada cliente pode pré-computar e armazenar todos os compromissos N para o polinômio lagrangeano (com(Li)). Em um contrato on-chain, pode ser muito armazenar todos os compromissos N, então você pode fazer compromissos KZG para o conjunto de valores com(L_i), então sempre que alguém precisar atualizar a árvore on-chain, eles podem simplesmente enviar para Proper com(L_i) fornece prova de sua correção. *
Então, tenha uma estrutura que vá acrescentando valores ao final da lista crescente, mas com um certo limite de tamanho. Em seguida, use essa estrutura como uma estrutura de dados para (i) compromissos com a lista de chaves em cada L2, armazenados naquele L2 e espelhados em L1 e (ii) compromissos com a lista de compromissos com chaves L2, armazenados no Ethereum em L1 e espelhado para cada L2.
Manter os compromissos atualizados pode fazer parte da lógica L2 principal ou ser implementado por meio de uma ponte de depósito e retirada sem alterar o protocolo principal L2.
Uma prova completa requer o seguinte:
Armazene o com (lista de chaves) mais recente do armazenamento de chaves em L2.
Prova KZG com com(keylist) como o valor em com(mirror list), que é a lista de todos os compromissos da lista de chaves.
Faça o certificado KZG da chave do usuário em com (lista de chaves).
Na verdade, as duas provas KZG acima podem ser combinadas em uma com um tamanho total de apenas 100 bytes.
Observe um detalhe: como uma lista de chaves é uma lista, não um mapa de chave/valor como o estado é, as posições da lista de chaves devem ser atribuídas em ordem. O contrato de promessa de chave conterá seu próprio registro interno, mapeando cada keystore para um ID e, para cada chave, ele armazenará o hash (chave, o endereço do keystore) em vez de apenas a chave, para informar explicitamente outros L2s sobre qual keystore a que uma entrada específica se refere.
A vantagem dessa técnica é que ela funciona muito bem em L2. Cerca de 4 vezes mais curto que ZK-SNARK, muito mais curto que Merkle proof. O custo de cálculo é de cerca de 119.000 taxa de gás.
No L1, o poder de computação é mais importante do que os dados, então o KZG é um pouco mais caro do que a prova Merkle.
**Como funcionam as árvores Verkle? **
As árvores Verkle envolvem essencialmente o empilhamento de compromissos KZG juntos: para armazenar 2⁴⁸ valores, um compromisso KZG pode ser feito para uma lista de 2²⁴ valores, cada um dos quais é um compromisso KZG para 2²⁴ valores.
As árvores Verkle são consideradas para as árvores de estado Ethereum porque as árvores Verkle podem ser usadas para armazenar mapas de chave-valor.
As provas nas árvores Verkle são mais longas que as provas KZG, elas podem ter centenas de bytes de comprimento.
Na verdade, as árvores Verkle devem ser consideradas como as árvores Merkle, mas são mais viáveis sem o SNARKing, mas o SNARKing demonstrou ter um custo de prova menor.
A grande vantagem das árvores Verkle é que elas podem coordenar estruturas de dados: portanto, podem ser usadas diretamente para L1 ou L2, não há estrutura de superposição e o mesmo mecanismo é usado para L1 e L2.
Uma vez que os computadores quânticos se tornam um problema, ou uma vez que os ramos Merkle provam ser eficientes o suficiente, as árvores Verkle têm mais usos.
polimerização
Se N usuários fizerem N transações e precisarem provar N reivindicações de cadeia cruzada, podemos economizar muito Gas Fee agregando essas provas, o que pode significar:
Uma prova ZK-SNARK de ramos N Merkle
Um certificado múltiplo KZG
Uma prova múltipla Verkle (ou uma prova múltipla ZK-SNARK)
Em todos os três casos, cada prova custa apenas algumas centenas de milhares de Gas Fee.
Os desenvolvedores precisam fazer uma dessas provas em cada L2 para os usuários dessa L2; assim, para que essa prova seja útil, todo o esquema precisa ter uso suficiente para que muitas vezes haja pelo menos algumas transações.
Se ZK-SNARKs forem usados, cada usuário pode precisar gastar milhares de taxas de gás L2. Se KZG multi-prova for usado, o verificador precisa adicionar 48 Gas Fees ao L2 de cada keystore usado no bloco.
Ainda assim, esses custos são muito mais baixos do que sem agregação, o que inevitavelmente envolve mais de 10.000 taxas de gás L1 e centenas de milhares de taxas de gás L2 por usuário.
Para a árvore Verkle, os usuários podem usar diretamente a prova múltipla Verkle, cada usuário adiciona cerca de 100 ~ 200 bytes, ou você pode fazer uma prova múltipla ZK-SNARK Verkle, seu custo é semelhante ao ZK-SNARK do ramo Merkle, mas a prova parece obviamente barata.
Do ponto de vista da implementação, pode ser melhor permitir que os empacotadores agreguem provas de cadeia cruzada por meio do padrão de abstração de conta ERC-4337. O ERC-4337 já possui um mecanismo para os construtores agregarem partes das operações do usuário de maneira personalizada. Existe até uma implementação para agregação de assinatura BLS, que pode reduzir a taxa de gás L2 de 1,5x a 3x.
** Leia o status diretamente **
Uma possibilidade final, e que só se aplica a L2 lendo L1 (em vez de L1 lendo L2), é modificar L2 para que eles façam chamadas estáticas diretamente para os contratos de L1.
Isso pode ser feito com um opcode ou pré-compilação que permite chamadas para o L1 onde você fornece o endereço de destino, gás e calldata e retorna a saída, embora, como essas chamadas são estáticas, elas não podem realmente alterar nenhum estado do L1. O L2 tem que saber o que está acontecendo com o L1 para processar os depósitos, então não há nada de fundamental que impeça que isso seja possível, é principalmente um desafio técnico de implementação.
Observe que, se o keystore estiver em L1 e L2 incorporar a funcionalidade de chamada estática de L1, nenhum atestado será necessário.
No entanto, se L2 não incorporar chamadas estáticas L1, ou se o keystore estiver em L2, a prova será necessária.
**Como o L2 aprende a raiz do estado Ethereum mais recente? **
Todos os esquemas acima exigem que o L2 acesse a raiz do estado L1 mais próximo ou todo o estado L1 mais próximo.
De fato, se L2 tiver uma função de depósito, você poderá usar esse L2 como está para mover a raiz do estado L1 para um contrato em L2: basta fazer com que o contrato em L1 chame o opcode BLOCKHASH e deposite-o como um ativo A mensagem é passada para L2. O cabeçalho de bloco completo pode ser recebido no lado L2 e sua raiz de estado extraída.
No entanto, cada L2 preferencialmente tem uma maneira explícita de acessar diretamente o último estado L1 completo ou a raiz do estado L1 mais próxima.
O principal desafio em otimizar a maneira como o L2 recebe a raiz do estado L1 mais recente é obter segurança e baixa latência ao mesmo tempo:
Se L2 for lento para implementar a funcionalidade L1 de leitura direta, apenas lendo a raiz do estado L1 final, então o atraso é normalmente de 15 minutos, mas em alguns casos extremos o atraso pode ser de semanas.
L2 definitivamente pode ser projetado para ler raízes de estado L1 atualizadas, mas como L1 pode se recuperar (o que acontece durante vazamentos inativos mesmo com finalidade de soquete único), L2 também precisa ser capaz de se recuperar. Do ponto de vista da engenharia de software, isso é tecnicamente desafiador.
Se uma ponte é usada para trazer as raízes do estado L1 para L2, as atualizações de ativos demoram muito e, na melhor das hipóteses, há usuários constantemente pagando por atualizações e mantendo o sistema atualizado para todos os outros.
Oracles não são uma solução aceitável aqui: o gerenciamento de chaves de carteira é uma função de baixo nível muito crítica para a segurança, portanto, deve depender, no máximo, de uma infraestrutura de baixo nível muito simples e criptograficamente confiável.
Além disso, na direção oposta (L1 lê L2):
No Optimistic Rollup, a raiz do estado leva uma semana para atingir o L1 devido a atrasos à prova de fraude. Em ZK rollups, agora leva horas devido a uma combinação de tempo de verificação e restrições econômicas, embora a tecnologia futura reduza isso.
A pré-confirmação (do sequenciador, certificador, etc.) não é uma solução aceitável para L1 lê L2. O gerenciamento de carteira é uma função de baixo nível muito crítica para a segurança, portanto, o nível de segurança de comunicação L2 a L1 deve ser absolutamente alto. A única raiz de estado em que L1 deve confiar é aquela que foi aceita como a raiz de estado final pelo contrato de manutenção da raiz de estado de L2 em L1.
Alguns deles são inaceitavelmente lentos para operações de cadeia cruzada sem confiança para muitos casos de uso de DeFi. No entanto, para o caso de uso de atualização de chaves de carteira, atrasos mais longos são mais aceitáveis - porque, em vez de atrasar as transações, está atrasando as alterações de chave.
Os usuários só precisam manter a chave antiga por um longo período de tempo. Se o usuário alterar a chave porque ela foi roubada, então realmente há um longo período de vulnerabilidade, mas pode ser mitigado, por exemplo. Por meio de uma carteira com funcionalidade de congelamento.
Em última análise, a melhor solução para minimizar a latência é fazer com que o L2 implemente leituras diretas otimizadas da raiz do estado L1, onde cada bloco L2 (ou log de computação da raiz do estado) contém um ponteiro para o bloco L1 mais recente, portanto, se L1 se recuperar e L2 pode se recuperar também. O contrato de keystore deve ser colocado na rede principal ou no L2 do ZK-rollup para que possa ser rapidamente confirmado no L1.
**Quanta conexão com Ethereum a outra cadeia precisa para manter o keystore armazenado na carteira Ethereum ou L2? **
Surpreendentemente, não muitos. Na verdade, nem precisa ser um Rollup.
Se for um L3 ou um validium, não há problema em armazenar carteiras lá, desde que os usuários armazenem armazenamento de chaves em L1 ou ZK-rollup, eles realmente precisam ter acesso direto à raiz do estado do Ethereum e estão dispostos a armazenar suas carteiras em Ethereum Ao refatorar, hard fork quando Ethereum hard forks.
Os esquemas baseados em pontes ZK têm propriedades técnicas atraentes, mas têm uma fraqueza importante, pois não são robustos contra ataques de 51% ou hard forks.
proteção de privacidade
Idealmente, os usuários também querem privacidade. Se um usuário tiver muitas carteiras gerenciadas pelo mesmo keystore, ele deseja garantir que:
Evite que o público saiba que essas carteiras estão todas conectadas umas às outras.
Os tutores de recuperação social não saberão qual é o endereço de sua tutela.
Mas isso cria um problema:
Não podemos usar as provas Merkle diretamente porque não preservam a privacidade.
Se usarmos KZG ou SNARKs, a prova precisa fornecer uma versão oculta da chave de verificação sem revelar a localização da chave de verificação.
Se usarmos agregação, o agregador não deve saber o local de forma clara; em vez disso, o agregador deve receber provas cegas e ter uma maneira de agregar essas provas.
Não podemos usar uma "versão leve" (atestado de cadeia cruzada apenas ao redigitar as chaves), porque isso criaria um vazamento de privacidade: se muitas carteiras forem atualizadas ao mesmo tempo devido ao atualizador, o tempo dessas carteiras podem ser informações relacionadas. Portanto, devemos usar a "versão completa" (prova cruzada de cada transação).
Para SNARKs, a solução é conceitualmente simples: as provas escondem informações por padrão e os agregadores precisam produzir SNARKs recursivos para provar SNARKs.
O principal desafio atual com essa abordagem é que a agregação exige que o agregador crie um SNARK recursivo, que é bastante lento.
Para KZG, podemos usar a não indexação para revelar o trabalho da prova KZG. No entanto, a agregação cega é um problema em aberto que requer mais atenção.
No entanto, embora ler L1 diretamente de L2 não proteja a privacidade, implementar esse recurso de leitura direta ainda seria muito útil - não apenas para minimizar a latência, mas para muitos outros casos de uso.
Ver original
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
Recompensa
gostar
1
Partilhar
Comentar
0/400
SickCatMakesAContrac
· 2023-08-02 05:51
Por que existe uma diferença tão grande entre os cérebros humanos. v cabeça de deus
V God Blog: Noções básicas sobre carteiras e outros casos de aplicação Leitura entre camadas da camada 2
Autor: Vitalik Buterin; Compilador: Bulu disse
No artigo The Three Transitions, Vitalik Buterin, o fundador da Ethereum, elaborou claramente a "rede principal (doravante denominada L1) + camada 2 cross-chain (doravante denominada cross-L2) support"" "Segurança da carteira" e "privacidade" são valores importantes como as funções necessárias da pilha do ecossistema. Eles não devem ser apenas alguns componentes adicionais, e uma carteira separada fornece funções relacionadas.
E este artigo, apontou Vitalik Buterin, se concentrará em uma questão técnica fundamental: como ler mais facilmente dados L1 de L2; ou ler dados L2 de L1; ou como ler mais facilmente dados L2 de um L2 Ler dados de outro L2 . **
Vitalik Buterin apontou que a chave para resolver os problemas acima está em como realizar a separação de ativos e keystores. Essa tecnologia também tem casos de uso muito valiosos em outras áreas além do dimensionamento, como a mobilidade de ativos entre L1 e L2.
** Qual é o objetivo de fazer isso? **
Assim que o L2 se tornar popular, os usuários poderão possuir ativos em vários L2s e possivelmente também no L1.
Uma vez que as carteiras de contratos inteligentes se tornem populares, as "chaves" agora comuns não serão mais usadas.
Uma vez que essas duas coisas aconteçam ao mesmo tempo, os usuários precisarão de um método que não exija um grande número de transações para alterar as chaves de contas diferentes.
Em particular, precisamos de uma maneira de lidar com endereços "contrafactuais" (também conhecidos como "endereços hipotéticos"): endereços que ainda não estão "registrados" na cadeia de forma alguma, mas ainda precisam receber e manter ativos com segurança .
Na verdade, todos nós contamos com essa "configuração contrafactual" de endereços: quando um usuário usa Ethereum pela primeira vez, o usuário pode gerar um endereço ETH e outros podem pagar para essa conta sem precisar se registrar no blockchain. Cadastre-se" o endereço (mas você precisará pagar taxas de transação, então você precisa manter algum ETH).
Para contas externas (EOA), de fato, todos os endereços começam no endereço do "cenário contrafactual".
Endereços "definidos contrafactualmente" ainda são possíveis com carteiras de contratos inteligentes, em grande parte graças ao CREATE2, que permite que você tenha um endereço ETH que só pode ser criado por código de contrato inteligente que corresponda a um preenchimento de hash específico.
△ Algoritmo de cálculo de endereço EIP-1014 (CREATE2).
No entanto, a introdução de carteiras de contrato inteligentes também traz novos desafios: **As chaves de acesso podem mudar. **Essa alteração é que o endereço é o valor hash do initcode, que pode conter apenas a chave de verificação inicial da carteira, e a chave de verificação atual será armazenada no armazenamento da carteira, mas o registro do armazenamento não será automaticamente transferido para outro L2.
Se um usuário tiver endereços em muitos L2s, apenas a Separação de ativos e arquitetura de armazenamento de chaves poderá ajudar os usuários a alterar suas chaves.
A estrutura dessa arquitetura dividida é que cada usuário tem (i) um "contrato de armazenamento de chaves" (no L1 ou em uma cadeia L2 específica) que armazena chaves de verificação para todas as carteiras e regras para alteração de chaves e (ii) "contratos de carteira " em L1 e em muitas cadeias L2, que obtêm chaves de verificação por meio de leituras cruzadas.
Há duas maneiras de implementar a arquitetura de separação de armazenamento de chaves e ativos:
Versão leve (ou seja, verifica apenas as chaves atualizadas): Cada carteira armazena a chave de verificação localmente e contém uma função que pode ser chamada para verificar a prova de cadeia cruzada do estado atual do armazenamento de chaves e atualizar o armazenamento local A autenticação chave a combinar. Chamar esta função para obter a chave de autenticação atual do keystore é necessário ao usar a carteira pela primeira vez em um L2.
Versão completa (ou seja, todas as transações são verificadas): Cada transação requer uma prova de cadeia cruzada mostrando a chave atual no armazenamento de chaves.
**O que é prova de cadeia cruzada? **
Para demonstrar a complexidade das provas de cadeia cruzada, selecionamos um dos cenários de aplicação mais complexos para demonstrar e explicar este princípio técnico. Este cenário de aplicação complexo é o seguinte: a chave é armazenada em um L2 e a carteira está em outro L2. Se o keystore na carteira estiver em L1, apenas metade desse design será necessário.
Suponha que o keystore esteja no Linea e a carteira esteja no Kakarot. O processo completo de certificação da chave da carteira precisa incluir:
Existem duas questões principais de implementação espinhosas aqui: "Que tipo de prova precisa ser usada? (É uma prova de Merkle? Ou outra coisa?)" e "Como L2 aprende a raiz do estado L1 mais próxima?" Ou, "L1 Como aprender a raiz do estado de L2?"
Então, em ambos os casos, quanto tempo demora entre quando um evento ocorre de um lado e quando a outra parte é capaz de fornecer provas?
**Quais esquemas de prova estão disponíveis para nós? **
Existem cinco métodos principais para escolher:
Em termos de trabalho de infraestrutura necessário e custos do usuário, eles podem ser classificados da seguinte forma:
"Agregação" refere-se à agregação de todas as provas fornecidas pelos usuários em cada bloco em uma grande metaprova, mesclando-as. Isso funciona para SNARKs e KZG, mas não para garfos Merkle.
Na verdade, a "agregação" só tem valor quando a solução possui um grande número de usuários.
**Como funcionam as provas Merkle? **
Este problema é muito simples e pode ser seguido diretamente pelo diagrama da seção anterior. Cada "prova" (assumindo que um L2 é provado ser outro L2, que é o cenário de aplicação mais difícil) incluirá:
Um fork Merkle que atesta a raiz do estado do keystore L2, a última raiz do estado do Ethereum conhecida por L2. As raízes de estado que contêm o keystore L2 são armazenadas em slots de armazenamento conhecidos em endereços conhecidos (contratos L1 representando L2), para que os caminhos possam ser codificados permanentemente.
Uma ramificação Merkle atestando a chave de verificação atual, de acordo com a raiz do estado que contém o keystore L2. Além disso, as chaves de autenticação são armazenadas em slots conhecidos em endereços conhecidos, portanto, os caminhos podem ser codificados permanentemente.
No entanto, as provas de estado no Ethereum são complicadas, mas existem bibliotecas que podem ser usadas para verificá-las e, se usar essas bibliotecas, o mecanismo não é muito complicado.
No entanto, o maior desafio é o custo. ** Merkle provou ser muito longo, e a árvore Patricia era 3,9 vezes mais longa do que o necessário - muito mais alto do que o preço base atual de 21.000 Gas Fee por transação.
Porém, se a prova for verificada em L2, a discrepância se agrava. A computação dentro de L2 é barata porque a computação é feita fora da cadeia e em um ecossistema com menos nós que L1.
Podemos calcular o que isso significa observando a comparação entre o custo da taxa de gás L1 e o custo da taxa de gás L2:
Atualmente, se for uma operação de envio relativamente simples, o custo na rede L1 é cerca de 15 a 25 vezes maior que o de L2, e o custo de troca de Token é cerca de 20 a 50 vezes maior que o de L2.
A operação de envio simples tem uma grande quantidade de dados; e a operação de troca requer maior poder de computação, portanto, a operação de troca é uma referência melhor para aproximar o custo do cálculo L1 e cálculo L2.
Juntando o que foi dito acima, se assumirmos uma relação de custo de 30x entre o custo computacional L1 e o custo computacional L2, isso parece implicar que o custo de colocar provas de Merkle em L2 pode ser equivalente a cerca de cinquenta transações regulares.
Claro, usar uma árvore Merkle binária reduziria o custo por um fator de cerca de 4, mas mesmo assim o custo ainda seria proibitivo na maioria dos casos, e se estivéssemos dispostos a desistir da compatibilidade com a árvore de estado hexa atual do Ethereum, isso poderia Irá procurar melhores opções.
**Como funciona a prova ZK-SNARK? **
O uso de ZK-SNARKs também é conceitualmente fácil de entender: basta substituir as provas de Merkle no diagrama acima por ZK-SNARKs provando a existência dessas provas de Merkle. O valor de cálculo de um ZK-SNARK é de cerca de 400.000 Gas Fee, cerca de 400 bytes; uma transação básica requer 21.000 Gas Fee e 100 bytes.
Portanto, do ponto de vista do cálculo, o custo do ZK-SNARK é 19 vezes o custo da transação básica atual; do ponto de vista dos dados, o custo do ZK-SNARK é 4 vezes o custo da transação básica atual e 16 vezes o futuro custo de transação básico.
Esses números representam uma grande melhoria em relação às provas de Merkle, mas ainda são bastante caros. Existem duas maneiras de melhorar esta situação: (i) provas KZG para fins especiais, ou (ii) agregação, semelhante à agregação ERC-4337.
**Como funciona a prova KZG para fins especiais? **
Primeiro, uma recapitulação de como as promessas KZG funcionam:
*[D_1 ...D_n] representa um conjunto de dados através do qual a prova polinomial KZG é derivada. *
*Especificamente, o polinômio P, onde P(w) = D_1, P(w²) = D_2 ... P(wⁿ) = D_n. onde é a "raiz uniforme", para algum Campo de avaliação tamanho N, valor wN = 1 (tudo isso é feito em campos finitos). *
G é o ponto gerador da curva
Pi é o coeficiente i do polinômio P
Si é o ponto i no cenário confiável
*E para provar que P(z) = a, criamos um quociente polinomial Q = (P - a) / (X - z) e criamos um compromisso com(Q). Só é possível criar tal polinômio se P(z) for realmente igual a a. *
Algumas propriedades importantes que você também deve conhecer incluem:
A prova é apenas o valor com(Q), que é de 48 bytes
com(P₁) + com(P₂) = com(P₁ + P₂)
*Isso também significa que você pode "editar" o valor em um contrato existente. *
Suponha que sabemos que D_i é atualmente a, queremos defini-lo como b e o compromisso existente para D é com(P). promessa "P, mas P(wⁱ) = b, e nenhuma outra mudança de avaliação", então definimos com(new_P) = com(P) + (ba)*com(Li), onde Li é "lag Langeriano polinomial", igual a 1 em wⁱ e 0 em outros pontos wj. *
Para executar essas atualizações com eficiência, cada cliente pode pré-computar e armazenar todos os compromissos N para o polinômio lagrangeano (com(Li)). Em um contrato on-chain, pode ser muito armazenar todos os compromissos N, então você pode fazer compromissos KZG para o conjunto de valores com(L_i), então sempre que alguém precisar atualizar a árvore on-chain, eles podem simplesmente enviar para Proper com(L_i) fornece prova de sua correção. *
Então, tenha uma estrutura que vá acrescentando valores ao final da lista crescente, mas com um certo limite de tamanho. Em seguida, use essa estrutura como uma estrutura de dados para (i) compromissos com a lista de chaves em cada L2, armazenados naquele L2 e espelhados em L1 e (ii) compromissos com a lista de compromissos com chaves L2, armazenados no Ethereum em L1 e espelhado para cada L2.
Manter os compromissos atualizados pode fazer parte da lógica L2 principal ou ser implementado por meio de uma ponte de depósito e retirada sem alterar o protocolo principal L2.
Uma prova completa requer o seguinte:
Na verdade, as duas provas KZG acima podem ser combinadas em uma com um tamanho total de apenas 100 bytes.
Observe um detalhe: como uma lista de chaves é uma lista, não um mapa de chave/valor como o estado é, as posições da lista de chaves devem ser atribuídas em ordem. O contrato de promessa de chave conterá seu próprio registro interno, mapeando cada keystore para um ID e, para cada chave, ele armazenará o hash (chave, o endereço do keystore) em vez de apenas a chave, para informar explicitamente outros L2s sobre qual keystore a que uma entrada específica se refere.
A vantagem dessa técnica é que ela funciona muito bem em L2. Cerca de 4 vezes mais curto que ZK-SNARK, muito mais curto que Merkle proof. O custo de cálculo é de cerca de 119.000 taxa de gás.
No L1, o poder de computação é mais importante do que os dados, então o KZG é um pouco mais caro do que a prova Merkle.
**Como funcionam as árvores Verkle? **
As árvores Verkle envolvem essencialmente o empilhamento de compromissos KZG juntos: para armazenar 2⁴⁸ valores, um compromisso KZG pode ser feito para uma lista de 2²⁴ valores, cada um dos quais é um compromisso KZG para 2²⁴ valores.
As árvores Verkle são consideradas para as árvores de estado Ethereum porque as árvores Verkle podem ser usadas para armazenar mapas de chave-valor.
As provas nas árvores Verkle são mais longas que as provas KZG, elas podem ter centenas de bytes de comprimento.
Na verdade, as árvores Verkle devem ser consideradas como as árvores Merkle, mas são mais viáveis sem o SNARKing, mas o SNARKing demonstrou ter um custo de prova menor.
A grande vantagem das árvores Verkle é que elas podem coordenar estruturas de dados: portanto, podem ser usadas diretamente para L1 ou L2, não há estrutura de superposição e o mesmo mecanismo é usado para L1 e L2.
Uma vez que os computadores quânticos se tornam um problema, ou uma vez que os ramos Merkle provam ser eficientes o suficiente, as árvores Verkle têm mais usos.
polimerização
Se N usuários fizerem N transações e precisarem provar N reivindicações de cadeia cruzada, podemos economizar muito Gas Fee agregando essas provas, o que pode significar:
Em todos os três casos, cada prova custa apenas algumas centenas de milhares de Gas Fee.
Os desenvolvedores precisam fazer uma dessas provas em cada L2 para os usuários dessa L2; assim, para que essa prova seja útil, todo o esquema precisa ter uso suficiente para que muitas vezes haja pelo menos algumas transações.
Se ZK-SNARKs forem usados, cada usuário pode precisar gastar milhares de taxas de gás L2. Se KZG multi-prova for usado, o verificador precisa adicionar 48 Gas Fees ao L2 de cada keystore usado no bloco.
Ainda assim, esses custos são muito mais baixos do que sem agregação, o que inevitavelmente envolve mais de 10.000 taxas de gás L1 e centenas de milhares de taxas de gás L2 por usuário.
Para a árvore Verkle, os usuários podem usar diretamente a prova múltipla Verkle, cada usuário adiciona cerca de 100 ~ 200 bytes, ou você pode fazer uma prova múltipla ZK-SNARK Verkle, seu custo é semelhante ao ZK-SNARK do ramo Merkle, mas a prova parece obviamente barata.
Do ponto de vista da implementação, pode ser melhor permitir que os empacotadores agreguem provas de cadeia cruzada por meio do padrão de abstração de conta ERC-4337. O ERC-4337 já possui um mecanismo para os construtores agregarem partes das operações do usuário de maneira personalizada. Existe até uma implementação para agregação de assinatura BLS, que pode reduzir a taxa de gás L2 de 1,5x a 3x.
** Leia o status diretamente **
Uma possibilidade final, e que só se aplica a L2 lendo L1 (em vez de L1 lendo L2), é modificar L2 para que eles façam chamadas estáticas diretamente para os contratos de L1.
Isso pode ser feito com um opcode ou pré-compilação que permite chamadas para o L1 onde você fornece o endereço de destino, gás e calldata e retorna a saída, embora, como essas chamadas são estáticas, elas não podem realmente alterar nenhum estado do L1. O L2 tem que saber o que está acontecendo com o L1 para processar os depósitos, então não há nada de fundamental que impeça que isso seja possível, é principalmente um desafio técnico de implementação.
Observe que, se o keystore estiver em L1 e L2 incorporar a funcionalidade de chamada estática de L1, nenhum atestado será necessário.
No entanto, se L2 não incorporar chamadas estáticas L1, ou se o keystore estiver em L2, a prova será necessária.
**Como o L2 aprende a raiz do estado Ethereum mais recente? **
Todos os esquemas acima exigem que o L2 acesse a raiz do estado L1 mais próximo ou todo o estado L1 mais próximo.
De fato, se L2 tiver uma função de depósito, você poderá usar esse L2 como está para mover a raiz do estado L1 para um contrato em L2: basta fazer com que o contrato em L1 chame o opcode BLOCKHASH e deposite-o como um ativo A mensagem é passada para L2. O cabeçalho de bloco completo pode ser recebido no lado L2 e sua raiz de estado extraída.
No entanto, cada L2 preferencialmente tem uma maneira explícita de acessar diretamente o último estado L1 completo ou a raiz do estado L1 mais próxima.
O principal desafio em otimizar a maneira como o L2 recebe a raiz do estado L1 mais recente é obter segurança e baixa latência ao mesmo tempo:
Além disso, na direção oposta (L1 lê L2):
Alguns deles são inaceitavelmente lentos para operações de cadeia cruzada sem confiança para muitos casos de uso de DeFi. No entanto, para o caso de uso de atualização de chaves de carteira, atrasos mais longos são mais aceitáveis - porque, em vez de atrasar as transações, está atrasando as alterações de chave.
Os usuários só precisam manter a chave antiga por um longo período de tempo. Se o usuário alterar a chave porque ela foi roubada, então realmente há um longo período de vulnerabilidade, mas pode ser mitigado, por exemplo. Por meio de uma carteira com funcionalidade de congelamento.
Em última análise, a melhor solução para minimizar a latência é fazer com que o L2 implemente leituras diretas otimizadas da raiz do estado L1, onde cada bloco L2 (ou log de computação da raiz do estado) contém um ponteiro para o bloco L1 mais recente, portanto, se L1 se recuperar e L2 pode se recuperar também. O contrato de keystore deve ser colocado na rede principal ou no L2 do ZK-rollup para que possa ser rapidamente confirmado no L1.
**Quanta conexão com Ethereum a outra cadeia precisa para manter o keystore armazenado na carteira Ethereum ou L2? **
Surpreendentemente, não muitos. Na verdade, nem precisa ser um Rollup.
Se for um L3 ou um validium, não há problema em armazenar carteiras lá, desde que os usuários armazenem armazenamento de chaves em L1 ou ZK-rollup, eles realmente precisam ter acesso direto à raiz do estado do Ethereum e estão dispostos a armazenar suas carteiras em Ethereum Ao refatorar, hard fork quando Ethereum hard forks.
Os esquemas baseados em pontes ZK têm propriedades técnicas atraentes, mas têm uma fraqueza importante, pois não são robustos contra ataques de 51% ou hard forks.
proteção de privacidade
Idealmente, os usuários também querem privacidade. Se um usuário tiver muitas carteiras gerenciadas pelo mesmo keystore, ele deseja garantir que:
Mas isso cria um problema:
Para SNARKs, a solução é conceitualmente simples: as provas escondem informações por padrão e os agregadores precisam produzir SNARKs recursivos para provar SNARKs.
O principal desafio atual com essa abordagem é que a agregação exige que o agregador crie um SNARK recursivo, que é bastante lento.
Para KZG, podemos usar a não indexação para revelar o trabalho da prova KZG. No entanto, a agregação cega é um problema em aberto que requer mais atenção.
No entanto, embora ler L1 diretamente de L2 não proteja a privacidade, implementar esse recurso de leitura direta ainda seria muito útil - não apenas para minimizar a latência, mas para muitos outros casos de uso.