Agradecimentos especiais a Dankrad Feist e Aditya Asgaonkar pela revisão
Sharding é o futuro da escalabilidade do Ethereum e será fundamental para ajudar o ecossistema a suportar muitos milhares de transações por segundo e permitir que grandes partes do mundo usem regularmente a plataforma a um custo acessível. No entanto, também é um dos conceitos mais incompreendidos no ecossistema Ethereum e nos ecossistemas blockchain de forma mais ampla. Refere-se a um conjunto muito específico de ideias com propriedades muito específicas, mas muitas vezes é confundido com técnicas que têm propriedades de segurança muito diferentes e muitas vezes muito mais fracas. O objetivo desta postagem será explicar exatamente quais propriedades específicas o sharding fornece, como ele difere de outras tecnologias que não são sharding e quais sacrifícios um sistema sharded precisa fazer para alcançar essas propriedades.
A melhor maneira de descrever o sharding começa com a declaração do problema que moldou e inspirou a solução: o Trilema da Escalabilidade .
O trilema da escalabilidade diz que existem três propriedades que um blockchain tenta ter e que, se você se ater a técnicas "simples", poderá obter apenas duas dessas três . As três propriedades são:
Escalabilidade : a cadeia pode processar mais transações do que um único nó regular (pense: um laptop de consumidor) pode verificar.
Descentralização : a cadeia pode ser executada sem nenhuma dependência de confiança em um pequeno grupo de grandes atores centralizados. Isso normalmente é interpretado como significando que não deve haver nenhuma confiança (ou mesmo suposição de maioria honesta) de um conjunto de nós que você não pode unir apenas com um laptop de consumidor.
Segurança : a cadeia pode resistir a uma grande porcentagem de nós participantes tentando atacá-la (idealmente 50%; qualquer coisa acima de 25% está bem, 5% definitivamente não está bem).
Agora podemos olhar para as três classes de "soluções fáceis" que obtêm apenas duas das três:
Blockchains tradicionais - incluindo Bitcoin, pré-PoS/sharding Ethereum, Litecoin e outras cadeias semelhantes. Eles dependem de cada participante executando um nó completo que verifica todas as transações e, portanto, têm descentralização e segurança, mas não escalabilidade.
Cadeias de alto TPS - incluindo a família DPoS, mas também muitas outras. Estes contam com um pequeno número de nós (geralmente 10-100) mantendo o consenso entre si, com os usuários tendo que confiar na maioria desses nós. Isso é escalável e seguro (usando as definições acima), mas não é descentralizado.
Ecossistemas de várias cadeias - refere-se ao conceito geral de "dimensionamento" por ter diferentes aplicativos ativos em diferentes cadeias e usar protocolos de comunicação entre cadeias para conversar entre eles. Isso é descentralizado e escalável, mas não é seguro, porque um invasor precisa apenas obter uma maioria de nós de consenso em uma das muitas cadeias (frequentemente <1% de todo o ecossistema) para quebrar essa cadeia e possivelmente causar efeitos de ondulação que causam grandes prejuízos para aplicações em outras cadeias.
Sharding é uma técnica que permite obter todos os três. Uma blockchain fragmentada é:
O restante da postagem descreverá como os blockchains fragmentados conseguem fazer isso.
A versão de fragmentação mais fácil de entender é a fragmentação por meio de amostragem aleatória. A fragmentação por meio de amostragem aleatória tem propriedades de confiança mais fracas do que as formas de fragmentação que estamos construindo no ecossistema Ethereum, mas usa uma tecnologia mais simples.
A ideia central é a seguinte. Suponha que você tenha uma proof of stake chain com um grande número (por exemplo, 10.000) validadores e um grande número (por exemplo, 100) blocos que precisam ser verificados. Nenhum computador é poderoso o suficiente para validar todos esses blocos antes que o próximo conjunto de blocos chegue.
Portanto, o que fazemos é dividir aleatoriamente o trabalho de fazer a verificação . Embaralhamos aleatoriamente a lista de validadores e atribuímos os primeiros 100 validadores na lista embaralhada para verificar o primeiro bloco, os segundos 100 validadores na lista embaralhada para verificar o segundo bloco etc. verificar um bloco (ou executar alguma outra tarefa) é chamado de comitê .
Quando um validador verifica um bloco, ele publica uma assinatura atestando o fato de que o fez. Todos os outros, em vez de verificar 100 blocos inteiros, agora verificam apenas 10.000 assinaturas - uma quantidade muito menor de trabalho, especialmente com agregação de assinatura BLS . Em vez de todos os blocos serem transmitidos pela mesma rede P2P, cada bloco é transmitido em uma sub-rede diferente, e os nós precisam apenas ingressar nas sub-redes correspondentes aos blocos pelos quais são responsáveis (ou têm interesse por outros motivos).
Considere o que acontece se o poder de computação de cada nó aumentar em 2x. Como cada nó agora pode validar com segurança 2x mais assinaturas, você pode reduzir o tamanho mínimo do depósito para suportar 2x mais validadores e, portanto, pode fazer 200 comitês em vez de 100.
Portanto, você pode verificar 200 blocos por slot em vez de 100. Além disso, cada bloco individual pode ser 2x maior. Assim, você tem 2x mais blocos de 2x o tamanho, ou 4x mais capacidade de corrente.
Podemos introduzir alguma linguagem matemática para falar sobre o que está acontecendo. Usando a notação Big O , usamos " O(C) " para nos referirmos à capacidade computacional de um único nó. Uma blockchain tradicional pode processar blocos de tamanho O(C) . Uma cadeia fragmentada conforme descrita acima pode processar blocos O(C) em paralelo (lembre-se, o custo para cada nó para verificar cada bloco indiretamente é O(1) porque cada nó só precisa verificar um número fixo de assinaturas) e cada bloco tem capacidade O(C) e, portanto, a capacidade total da cadeia fragmentada é O(C2) . É por isso que chamamos esse tipo de sharding quadrático sharding , e esse efeito é uma das principais razões pelas quais pensamos que, a longo prazo, o sharding é a melhor maneira de dimensionar um blockchain.
Existem duas diferenças fundamentais:
Essas duas diferenças garantem que o sharding crie um ambiente para aplicativos que preserva as principais propriedades de segurança de um ambiente de cadeia única, de uma forma que os ecossistemas de várias cadeias fundamentalmente não fazem.
Um refrão comum nos círculos de Bitcoin, e com o qual concordo totalmente, é que blockchains como Bitcoin (ou Ethereum) NÃO dependem completamente de uma suposição de maioria honesta . Se houver um ataque de 51% em tal blockchain, o invasor pode fazer algumas coisas desagradáveis, como reverter ou censurar transações, mas não pode inserir transações inválidas. E mesmo que revertam ou censurem transações, os usuários que executam nós regulares podem facilmente detectar esse comportamento, portanto, se a comunidade deseja se coordenar para resolver o ataque com uma bifurcação que tira o poder do invasor, eles podem fazer isso rapidamente.
A falta dessa segurança extra é um ponto fraco das cadeias de alto TPS mais centralizadas . Essas cadeias não têm e não podem ter uma cultura de usuários regulares executando nós e, portanto, os principais nós e participantes do ecossistema podem se reunir com muito mais facilidade e impor uma mudança de protocolo que a comunidade não gosta. Pior ainda, os nós dos usuários aceitariam por padrão. Depois de algum tempo, os usuários notariam, mas a essa altura a mudança forçada de protocolo seria um fato consumado: o ônus da coordenação recairia sobre os usuários para rejeitar a mudança e eles teriam que tomar a dolorosa decisão de reverter o valor de um dia ou mais de atividade que todos pensavam que já estava finalizada.
Idealmente, queremos ter uma forma de sharding que evite suposições de confiança de 51% para validade e preserve o poderoso baluarte de segurança que os blockchains tradicionais obtêm da verificação completa. E é exatamente disso que trata grande parte de nossa pesquisa nos últimos anos.
Podemos dividir o problema de validação escalável à prova de ataque de 51% em dois casos:
Computação de validação : verifica se alguma computação foi feita corretamente, assumindo que você possui todas as entradas para a computação.
Validando a disponibilidade de dados : verificando se as entradas para o próprio cálculo estão armazenadas de alguma forma onde você possa baixá-las se realmente precisar; essa verificação deve ser realizada sem realmente baixar as próprias entradas inteiras (porque os dados podem ser muito grandes para serem baixados para cada bloco).
Validar um bloco em um blockchain envolve computação e verificação de disponibilidade de dados: você precisa estar convencido de que as transações no bloco são válidas e que o novo hash raiz de estado reivindicado no bloco é o resultado correto da execução dessas transações, mas você também precisam ser convencidos de que dados suficientes do bloco foram realmente publicados para que os usuários que baixam esses dados possam calcular o estado e continuar processando o blockchain. Esta segunda parte é um conceito muito sutil, mas importante, chamado de problema de disponibilidade de dados ; mais sobre isso mais tarde.
A validação escalável da computação é relativamente fácil; existem duas famílias de técnicas: provas de fraude e ZK-SNARKs .
As duas tecnologias podem ser descritas simplesmente da seguinte forma:
C
com a entrada X
, obterá a saída Y
". Você confia nessas mensagens por padrão, mas deixa em aberto a oportunidade para outra pessoa com um depósito apostado fazer um desafio (uma mensagem assinada dizendo "Discordo, a saída é Z"). Somente quando há um desafio, todos os nós executam a computação. Qualquer uma das duas partes que estiver errada perde seu depósito e todos os cálculos que dependem do resultado desse cálculo são recalculados.C
na entrada X
dá saída Y
". A prova é criptograficamente "sólida": se C(x)
não for igual a Y
, é computacionalmente inviável fazer uma prova válida. A prova também é rápida de verificar, mesmo que a própria execução do C
leve muito tempo. Veja este post para mais detalhes matemáticos sobre ZK-SNARKs.
A computação baseada em provas de fraude é escalável porque "no caso normal" você substitui a execução de uma computação complexa pela verificação de uma única assinatura. Existe o caso excepcional, em que você precisa verificar o cálculo na cadeia porque há um desafio, mas o caso excepcional é muito raro porque acioná-lo é muito caro (o reclamante original ou o desafiante perde um grande depósito). Os ZK-SNARKs são conceitualmente mais simples - eles apenas substituem um cálculo por uma verificação de prova muito mais barata - mas a matemática por trás de como eles funcionam é consideravelmente mais complexa.
Existe uma classe de sistema semi-escalável que apenas verifica a computação de forma escalável, embora ainda exija que cada nó verifique todos os dados. Isso pode ser bastante eficaz usando um conjunto de truques de compactação para substituir a maioria dos dados por computação. Este é o reino dos rollups .
Uma prova de fraude não pode ser usada para verificar a disponibilidade de dados. As provas de fraude para computação dependem do fato de que as entradas para a computação são publicadas na cadeia no momento em que a reivindicação original é enviada e, portanto, se alguém desafiar, a execução do desafio está acontecendo exatamente no mesmo "ambiente" em que a execução original foi acontecendo. No caso de verificar a disponibilidade de dados, você não pode fazer isso, porque o problema é justamente o fato de haver muitos dados para verificar para publicar na cadeia. Portanto, um esquema à prova de fraude para disponibilidade de dados enfrenta um problema-chave: alguém pode alegar que "os dados X estão disponíveis" sem publicá-los, esperar para ser questionado e só então publicar os dados X e fazer o desafiante aparecer para o resto do mundo. rede está incorreta.
Isso é expandido no dilema do pescador :
A ideia central é que os dois "mundos", um em que V1 é um editor malvado e V2 é um desafiante honesto e o outro onde V1 é um editor honesto e V2 é um desafiante malvado, são indistinguíveis para qualquer um que não esteja tentando baixar aquele dado específico no momento. E, claro, em um blockchain descentralizado escalável, cada nodo individual só pode esperar baixar uma pequena parte dos dados, então apenas uma pequena parte dos nodos veria algo sobre o que aconteceu, exceto pelo mero fato de que houve um desacordo.
O fato de ser impossível distinguir quem estava certo e quem estava errado torna impossível ter um esquema à prova de fraude para disponibilidade de dados.
Infelizmente, a mera validade não é suficiente para garantir uma blockchain funcionando corretamente. Isso ocorre porque, se o blockchain for válido , mas todos os dados não estiverem disponíveis , os usuários não terão como atualizar os dados necessários para gerar provas de que qualquer bloco futuro é válido. Um invasor que gera um bloco válido, mas indisponível, mas depois desaparece, pode efetivamente interromper a cadeia. Alguém também pode reter os dados da conta de um usuário específico até que o usuário pague um resgate, portanto, o problema não é apenas uma questão de vivacidade.
Existem alguns fortes argumentos teóricos da informação de que esse problema é fundamental, e não há nenhum truque inteligente (por exemplo, envolvendo acumuladores criptográficos ) que possa contorná-lo. Consulte este documento para obter detalhes.
A chave é uma tecnologia chamada amostragem de disponibilidade de dados . A amostragem de disponibilidade de dados funciona da seguinte maneira:
Os códigos de eliminação transformam um problema de "verificação de 100% de disponibilidade" (todos os dados estão disponíveis) em um problema de "verificação de 50% de disponibilidade" (pelo menos metade dos dados estão disponíveis). A amostragem aleatória resolve o problema de disponibilidade de 50%. Se menos de 50% dos dados estiverem disponíveis, pelo menos uma das verificações quase certamente falhará e, se pelo menos 50% dos dados estiverem disponíveis, embora alguns nós possam não reconhecer um bloco como disponível, é necessário apenas um nó honesto para executar o procedimento de reconstrução do código de eliminação para trazer de volta os 50% restantes do bloco. E assim, ao invés de precisar baixar 1 MB para verificar a disponibilidade de um bloco de 1 MB, basta baixar alguns kilobytes. Isso torna possível executar a verificação de disponibilidade de dados em cada bloco. Veja esta postagem para saber como essa verificação pode ser implementada com eficiência com sub-redes ponto a ponto.
Um ZK-SNARK pode ser usado para verificar se a codificação de apagamento em uma parte dos dados foi feita corretamente e, em seguida, as ramificações do Merkle podem ser usadas para verificar partes individuais. Como alternativa, você pode usar compromissos polinomiais (por exemplo, compromissos Kate (também conhecido como KZG) ), que essencialmente fazem codificação de apagamento e comprovam elementos individuais e verificação de correção em um componente simples - e é isso que o sharding Ethereum está usando.
Suponha que você tenha 100 blocos e queira verificar com eficiência a exatidão de todos eles sem depender de comitês. Precisamos fazer o seguinte:
Cada cliente executa amostragem de disponibilidade de dados em cada bloco, verificando se os dados em cada bloco estão disponíveis, enquanto baixa apenas alguns kilobytes por bloco, mesmo que o bloco como um todo tenha um megabyte ou mais. Um cliente só aceita um bloqueio quando todos os dados de seus desafios de disponibilidade foram respondidos corretamente.
Agora que verificamos a disponibilidade dos dados, fica mais fácil verificar a exatidão. Existem duas técnicas:
Em qualquer um dos casos acima, cada cliente só precisa fazer uma pequena quantidade de trabalho de verificação por bloco, independentemente do tamanho do bloco. No caso de provas de fraude, ocasionalmente os blocos precisarão ser totalmente verificados na cadeia, mas isso deve ser extremamente raro porque acionar até mesmo um desafio é muito caro.
E isso é tudo! No caso de fragmentação do Ethereum, o plano de curto prazo é tornar os blocos fragmentados apenas para dados ; ou seja, os fragmentos são puramente um "mecanismo de disponibilidade de dados" e é o trabalho dos rollups de camada 2 usar esse espaço de dados seguro, além de provas de fraude ou ZK-SNARKs, para implementar recursos de processamento de transações seguras de alto rendimento. No entanto, é totalmente possível criar um sistema integrado para adicionar execução "nativa" de alto rendimento.
O principal objetivo do sharding é chegar o mais próximo possível da replicação das propriedades de segurança mais importantes dos blockchains tradicionais (não sharded), mas sem a necessidade de cada nó verificar pessoalmente cada transação.
A fragmentação chega bem perto. Em um blockchain tradicional:
Em um blockchain fragmentado com recursos avançados de segurança:
Blocos inválidos não podem passar porque:
Blocos indisponíveis não podem passar porque:
As correntes tradicionais de alto TPS sem sharding não têm como fornecer essas garantias. Os ecossistemas multichain não têm como evitar o problema de um invasor selecionar uma cadeia para ataque e facilmente assumi-la (as cadeias podem compartilhar a segurança, mas se isso for mal feito, ela se transformará em uma cadeia tradicional de alto TPS com todas as suas desvantagens, e se fosse bem feito, seria apenas uma implementação mais complicada das técnicas de sharding acima).
As sidechains são altamente dependentes de implementação, mas são tipicamente vulneráveis às fraquezas das cadeias tradicionais de alto TPS (isto é, se elas compartilham mineradores/validadores) ou às fraquezas dos ecossistemas multicadeias (isto é, se elas não compartilham mineradores/validadores ). Cadeias fragmentadas evitam esses problemas.
No entanto, existem algumas brechas na armadura do sistema fragmentado . Notavelmente:
Essas são preocupações válidas, embora, em nossa opinião, sejam superadas em muito pela redução na centralização no nível do usuário, permitindo que mais aplicativos sejam executados na cadeia em vez de por meio de serviços centralizados da camada 2. Dito isso, essas preocupações, especialmente as duas últimas, são, na prática, a verdadeira restrição ao aumento do throughput de uma cadeia fragmentada além de um certo ponto. Há um limite para a quadraticidade da fragmentação quadrática.
A propósito, os crescentes riscos de segurança de blockchains fragmentados se sua taxa de transferência se tornar muito alta também são a principal razão pela qual o esforço para estender a fragmentação superquadrática foi amplamente abandonado; parece que manter a fragmentação quadrática apenas quadrática é realmente o meio termo.
Uma alternativa à fragmentação frequentemente proposta é ter uma cadeia estruturada como uma cadeia de alto TPS centralizada, exceto que usa amostragem de disponibilidade de dados e fragmentação na parte superior para permitir a verificação da validade e disponibilidade.
Isso melhora as cadeias de alto TPS centralizadas como existem hoje, mas ainda é consideravelmente mais fraca do que um sistema fragmentado. Isso ocorre por alguns motivos:
Sistemas devidamente fragmentados são melhores como uma camada de base. Dada uma camada base fragmentada, você sempre pode criar um sistema de produção centralizado (por exemplo, porque você deseja um domínio de alto rendimento com capacidade de composição síncrona para defi ) em camadas no topo, construindo-o como um rollup. Mas se você tiver uma camada base com dependência da produção de blocos centralizados, não poderá criar uma camada 2 mais descentralizada no topo.
Também publicado aqui .