Olá, queridos Habrausers! Este artigo é sobre web 3.0, a Internet com descentralização. A Web 3.0 introduz o conceito de descentralização como base para a Internet moderna; muitos sistemas e redes de computadores precisam de propriedades de segurança e descentralização para suas necessidades. A solução de descentralização é chamada de tecnologia de registro distribuído ou blockchain.

Blockchain é um registro distribuído. Pode ser considerado como um enorme banco de dados que vive para sempre e não muda na história, o blockchain é usado como base para aplicativos ou serviços da web descentralizados.
Em essência, o blockchain não é apenas um banco de dados, é uma oportunidade de aumentar a confiança entre os participantes da rede com a capacidade de executar a lógica de negócios na rede.
Consenso bizantino aumenta a confiabilidade da rede resolve o problema de consistência
A escalabilidade que o DLT traz está mudando as redes comerciais existentes.
O Blockchain oferece novas vantagens muito importantes:
- Prevenção de erros caros.
- Transações transparentes.
- Digitalização para bens reais.
- Contratos inteligentes.
- Rapidez e segurança dos pagamentos.
O Opporty PoE é um projeto cujo objetivo é estudar protocolos criptográficos e melhorar as soluções DLT e blockchain existentes.
A maioria dos sistemas de registro distribuídos em público não possui propriedades de escalabilidade - sua taxa de transferência é bastante baixa. Por exemplo, o ethereum processa apenas ~ 20 tx / s.
Muitas soluções foram criadas para aumentar a propriedade de escalabilidade e não perder a descentralização (como você sabe, apenas 2 em 3 podem ser conhecidas: escalabilidade, segurança, descentralização).
Uma das mais eficazes é uma solução usando cadeias laterais.
Conceito de plasma
O conceito é que a cadeia raiz processa um pequeno número de confirmações de cadeias filho, para que a cadeia raiz atue como a camada mais segura e final para armazenar todos os estados intermediários. Cada cadeia filho funciona como seu próprio blockchain com seu próprio algoritmo de consenso, mas existem algumas ressalvas importantes.
- Contratos inteligentes são criados na cadeia raiz e agem como um ponto de verificação na cadeia filha na cadeia raiz.
- Uma cadeia filho é criada que funciona como sua própria blockchain com seu próprio consenso. Todos os estados da cadeia de processos filhos são protegidos por provas de fraude, que garantem que todas as transições entre estados são válidas e aplicam um protocolo de retirada.
- Contratos inteligentes específicos para dapp ou cadeia filho (lógica de aplicativo) podem ser implementados na cadeia filho.
- As ferramentas necessárias podem ser transferidas da cadeia raiz para a cadeia filho.
Os validadores têm incentivos econômicos para agir com honestidade e enviar comentários para a cadeia raiz - a camada da liquidação final da transação.
Como resultado, os usuários dapp que trabalham na cadeia filho não devem interagir com a cadeia raiz. Além disso, eles podem retirar seu dinheiro para a cadeia raiz sempre que quiserem, mesmo que a cadeia filha seja invadida. Essas saídas da cadeia de filhos permitem que os usuários armazenem seus fundos com segurança usando as provas Merkle, confirmando a propriedade de uma certa quantia de fundos.
As principais vantagens do plasma estão relacionadas à sua capacidade de facilitar significativamente os cálculos que atualmente sobrecarregam a cadeia principal. Além disso, o blockchain Ethereum pode processar conjuntos de dados mais extensos e mais paralelos. O tempo gasto na cadeia raiz também é transferido para os nós do Ethereum, que recebem menos requisitos de processamento e armazenamento.
O Plasma Cash é um design que fornece aos tokens de rede números de série exclusivos que os transformam em tokens exclusivos. As vantagens disso incluem a ausência da necessidade de confirmações, suporte mais simples para todos os tipos de tokens (incluindo tokens não fungíveis) e mitigação contra saídas em massa da cadeia infantil.
O problema do plasma está relacionado ao conceito de "saídas em massa" da cadeia infantil. Nesse cenário, uma saída simultânea coordenada da cadeia filha pode levar à falta de poder de computação para retirar todos os fundos. Como resultado, os usuários podem perder dinheiro.
Opções de implementação de plasma

O plasma base tem muitas opções para implementação.
As principais diferenças são:
- armazenar informações sobre o método de armazenar e apresentar o estado,
- tipos de tokens (divisíveis indivisíveis),
- segurança de transação
- tipo de algoritmo de consenso, etc.
As principais variações do plasma:
- Baseado em UTXO - cada transação consiste em entradas e saídas: uma transação pode ser conduzida e gasta, a lista de transações não gastas é um estado da própria cadeia filha.
- Baseado em conta - simplesmente contém um reflexo de cada conta-conta e seu saldo, esse tipo é usado no ethereum, pois cada conta pode ser de dois tipos - uma conta de usuário e uma conta de contrato inteligente. A vantagem desse tipo de armazenamento de estado é sua simplicidade, e o menos é que essa opção não é escalável (a propriedade nonce especial é usada para impedir que a transação seja executada duas vezes).
O objetivo deste artigo é explicar as estruturas de dados que são usadas na blockchain do Plasma Cash.
Para entender exatamente como o compromisso funciona, é necessário esclarecer o conceito da árvore Merkle.
Merkle árvores seu uso no plasma
As árvores Merkle são uma estrutura de dados extremamente importante no mundo da blockchain. Em essência, as árvores Merkle nos permitem capturar alguns conjuntos de dados de maneira a ocultar os dados, mas permitem que os usuários provem que algumas das informações estavam no conjunto. Por exemplo, se eu tiver dez números, posso criar uma prova para esses números e provar que um número específico estava nesse conjunto de números. Essas provas têm um tamanho pequeno e constante, o que as torna baratas para publicar na Ethereum.
Você pode usar isso para um conjunto de transações. Você também pode provar que uma transação específica está nesse conjunto de transações. É exatamente isso que o operador faz. Cada bloco consiste em um conjunto de transações que se transformam em uma árvore Merkle. A raiz dessa árvore é a prova, publicada no Ethereum, juntamente com cada bloco de plasma.
Os usuários devem poder retirar seus fundos da cadeia de plasma e, quando desejam sair da cadeia de plasma, enviam a transação de "saída" para a Ethereum.
O Plasma Cash usa a Merkle Tree especial, que permite não validar todo o bloco, mas validar apenas os ramos que correspondem ao token do usuário.
Ou seja, para transferir um token, você precisa percorrer o histórico e verificar apenas os tokens necessários para um determinado usuário. Ao transferir um token, o usuário simplesmente passa o histórico inteiro para outro usuário e ele já pode autenticar todo o histórico - e, o mais importante, fazê-lo rapidamente.

Estruturas de dados do Plasma Cash para armazenar status e histórico
No entanto, é necessário usar apenas algumas árvores Merkle, porque é necessário obter prova de inclusão e também prova de não inclusão da transação no bloco, por exemplo -
- Árvore de merkle esparsa
- Patricia trie
A Opporty concluiu sua implementação de Sparse Merkle Tree e Patricia Trie
Uma árvore Merkle esparsa é semelhante a uma árvore Merkle padrão, exceto que os dados que ela contém são indexados e cada ponto de dados é colocado em uma planilha que corresponde ao índice desse ponto de dados.
Digamos que temos uma árvore Merkle com quatro folhas. Vamos preencher esta árvore com algumas letras (A, D) para demonstração. A letra A é a primeira letra do alfabeto, portanto, devemos colocá-la na primeira folha. Da mesma forma, podemos colocar D na quarta folha.
Então, o que acontece na segunda e terceira folhas? Nós apenas os deixamos vazios. Mais precisamente, um valor especial (por exemplo, zero) é colocado em vez de colocar a letra.
A árvore finalmente se parece com isso:

A prova de inclusão funciona como em uma árvore Merkle comum.O que acontece se quisermos provar que C não faz parte dessa árvore Merkle? É fácil! Sabemos que se C fizesse parte de uma árvore, estaria na terceira folha. Se C não faz parte da árvore, a terceira folha deve ser zero.
Tudo o que é necessário é a prova padrão da inclusão de Merkle, mostrando que a terceira folha é zero.
A melhor parte de uma árvore Merkle esparsa é que elas realmente representam lojas de valor-chave dentro da árvore Merkle!
Aqui está parte do código do protocolo PoE que implementa a construção da Sparse Merkle Tree.
class SparseTree { //... buildTree() { if (Object.keys(this.leaves).length > 0) { this.levels = [] this.levels.unshift(this.leaves) for (let level = 0; level < this.depth; level++) { let currentLevel = this.levels[0] let nextLevel = {} Object.keys(currentLevel).forEach((leafKey) => { let leafHash = currentLevel[leafKey] let isEvenLeaf = this.isEvenLeaf(leafKey) let parentLeafKey = leafKey.slice(0, -1) let neighborLeafKey = parentLeafKey + (isEvenLeaf ? '1' : '0') let neighborLeafHash = currentLevel[neighborLeafKey] if (!neighborLeafHash) { neighborLeafHash = this.defaultHashes[level] } if (!nextLevel[parentLeafKey]) { let parentLeafHash = isEvenLeaf ? ethUtil.sha3(Buffer.concat([leafHash, neighborLeafHash])) : ethUtil.sha3(Buffer.concat([neighborLeafHash, leafHash])) if (level == this.depth - 1) { nextLevel['merkleRoot'] = parentLeafHash } else { nextLevel[parentLeafKey] = parentLeafHash } } }) this.levels.unshift(nextLevel) } } } }
Este código é bastante trivial. Temos um armazenamento de valor-chave com prova de inclusão / não inclusão.
Em cada iteração, um nível específico da árvore final é preenchido, começando com o último. Dependendo de qual tecla da planilha atual é par ou ímpar, pegamos duas planilhas adjacentes e consideramos o hash do nível atual. Se chegarmos ao final, escrevemos um único merkleRoot - um hash comum.
Você deve entender que essa árvore já está preenchida com valores inicialmente vazios! E se armazenarmos uma enorme quantidade de token IDS. temos um tamanho de árvore enorme e leva muito tempo para gerar!
Existem muitas soluções para essa não otimização, mas o Opporty decidiu mudar essa árvore para Patricia Trie.
Patricia Trie é uma mistura de Radix Trie e Merkle Trie.
A chave de dados Radix Trie armazenará o próprio caminho de dados! Isso permite que você crie uma estrutura de dados otimizada para memória!

Implementação oportuna
buildNode(childNodes, key = '', level = 0) { let node = {key} this.iterations++ if (childNodes.length == 1) { let nodeKey = level == 0 ? childNodes[0].key : childNodes[0].key.slice(level - 1) node.key = nodeKey let nodeHashes = Buffer.concat([Buffer.from(ethUtil.sha3(nodeKey)), childNodes[0].hash]) node.hash = ethUtil.sha3(nodeHashes) return node } let leftChilds = [] let rightChilds = [] childNodes.forEach((node) => { if (node.key[level] == '1') { rightChilds.push(node) } else { leftChilds.push(node) } }) if (leftChilds.length && rightChilds.length) { node.leftChild = this.buildNode(leftChilds, '0', level + 1) node.rightChild = this.buildNode(rightChilds, '1', level + 1) let nodeHashes = Buffer.concat([Buffer.from(ethUtil.sha3(node.key)), node.leftChild.hash, node.rightChild.hash]) node.hash = ethUtil.sha3(nodeHashes) } else if (leftChilds.length && !rightChilds.length) { node = this.buildNode(leftChilds, key + '0', level + 1) } else if (!leftChilds.length && rightChilds.length) { node = this.buildNode(rightChilds, key + '1', level + 1) } else if (!leftChilds.length && !rightChilds.length) { throw new Error('invalid tree') } return node }
Ou seja, passamos recursivamente e construímos subárvores filho esquerda e direita separadamente. Ao mesmo tempo, construir a chave é como um caminho nesta árvore!
Esta solução é ainda mais trivial e funciona mais rapidamente, sendo bastante otimizada! De fato, a árvore Patricia pode ser otimizada ainda mais com a introdução de novos tipos de nós - nó de extensão, nó de ramificação etc., como feito no protocolo ethereum, mas essa implementação satisfaz todas as nossas condições - obtemos uma estrutura de dados rápida e com otimização de memória.
Com a implementação dessas estruturas de dados, o Opporty tornou possível dimensionar o Plasma Cash, pois possibilita verificar o histórico do token e a inclusão de não incluir o token na árvore! Isso permite que você acelere bastante a validação de blocos e da própria cadeia de filhos de plasma.
Links úteis:
- Plasma de papel branco
- Hub Git
- Casos de uso e descrição da arquitetura
- Papel de rede relâmpago