Skip to main content
O estado confirmado tem de satisfazer duas exigências que puxam em sentidos opostos. A execução quer o valor atual de uma chave, depressa, milhões de vezes. A verificação quer uma prova de que um valor era aquilo que a rede diz que era numa versão determinada. Servir ambas a partir de uma só estrutura significa fazer as duas mal. O armazenamento reparte, por isso, o problema por repositórios separados, cada um moldado ao seu próprio padrão de acesso.

Três repositórios

Bloco confirmado
Repositório do ledgertransações · resultados · eventos · escritas · acumuladores · metadados
Reexecução e auditoria
Repositório KV de estadovalores atuais e históricos, repartidos por 16 shards, estado quente em nível próprio
Consultas e execução
Repositório Merkle de estadoárvore de Merkle esparsa versionada, mais os índices dos nós substituídos
Verificação — provas
Uma leitura que só precisa de um valor não paga o percurso da árvore, e uma prova não se reconstrói de um repositório otimizado para pesquisas pontuais.
O repositório do ledger guarda o histórico da cadeia: transações, os seus resultados e dados auxiliares, eventos, conjuntos de escrita, metadados de bloco e os acumuladores. É isto que se reexecuta. O repositório KV de estado guarda os valores de estado, endereçados por chave e por versão. É o que a execução e as consultas leem. Está repartido por dezasseis shards, para que as escritas de um bloco se distribuam por dezasseis instâncias RocksDB independentes em vez de disputarem uma só. O estado acedido com frequência é ainda mantido num nível próprio, para que o conjunto de trabalho de um mercado ativo não tenha de ser encontrado no meio de tudo o que a cadeia alguma vez guardou. O repositório Merkle de estado guarda a estrutura autenticada — os nós da árvore que permitem provar um valor e os índices que registam que nós foram substituídos. Separá-los significa que uma leitura que só precisa de um valor não paga o percurso da árvore, e que uma prova não tem de ser reconstruída a partir de um repositório otimizado para pesquisas pontuais.

Autenticação

Duas estruturas de Merkle fazem trabalhos diferentes.
Árvore de Merkle esparsa versionada
Acumuladores
A chave e o seu valor
hash irmão
hash irmão
Raiz do estado, confirmada pelo consenso
Uma transação, ou um evento
Acumulador de transações · de eventoscada um fixa, por ordem, tudo o que foi incluído
Raiz do ledger, confirmada pelo consenso
A árvore prova qual era um valor; os acumuladores provam o que aconteceu e por que ordem. Juntos, tornam demonstrável «esta transação está na cadeia nesta posição» sem guardar a cadeia.
Uma árvore de Merkle esparsa versionada autentica o estado. Cada chave tem uma posição determinada pelo seu hash, e cada versão da árvore partilha os nós que não mudaram — escrever uma chave num bloco acrescenta um caminho, não uma árvore. A prova de uma chave numa dada versão é o caminho da folha dessa chave até à raiz que a rede confirmou. Os acumuladores autenticam a sequência. Um acumula transações e outro acumula eventos, produzindo cada um uma raiz que fixa, por ordem, tudo o que foi incluído até ao momento. É isto que torna demonstrável a afirmação «esta transação está na cadeia nesta posição» sem ter de guardar a cadeia. Entre as duas: a árvore de estado prova qual era um valor, os acumuladores provam o que aconteceu e por que ordem.

Estado especulativo

Os resultados de um bloco existem antes de serem confirmados. Em vez de os escrever na árvore durável e desfazer essa escrita caso o bloco não seja confirmado, o estado por confirmar é mantido numa camada esparsa de Merkle em memória, sobreposta à última versão confirmada. A execução lê através dessa camada e vê uma visão consistente. Se o bloco for confirmado, a camada é materializada. Se não for, a camada é descartada e nada de durável chegou a ser tocado. É isto que impede a execução especulativa de deixar detritos no armazenamento.

Cache

Os nós da árvore são mantidos em cache a dois níveis: uma cache consciente das versões, que mantém as versões recentes endereçáveis, e, por baixo dela, uma cache de substituição LRU (menos recentemente usado). O padrão de acesso de uma cadeia de negociação — um pequeno conjunto de chaves quentes tocadas em cada bloco, contra uma cauda longa raramente tocada — é exatamente o padrão para que estas caches existem.

Poda

Guardar todas as versões para sempre é uma escolha, não um requisito. Três podadores independentes correm sobre os três repositórios, cada um com a sua política de retenção: um sobre o ledger, um sobre os valores de estado, um sobre os nós de Merkle. Os podadores de Merkle e de valores de estado são guiados por índices de obsolescência escritos ao mesmo tempo que os dados. Quando uma versão substitui um nó ou um valor, a entrada substituída é registada como obsoleta nessa versão. A poda passa então a ser um varrimento de um intervalo de um índice, e não uma busca por lixo — quem escreveu já disse o que ficaria recolhível e a partir de quando.
A retenção é uma decisão do operador com consequências reais. Um nó podado de forma agressiva serve o estado atual com eficiência e não consegue responder a consultas históricas nem servir a sincronização de estado a um nó que arranque de mais atrás. Um nó de arquivo guarda tudo e paga por isso. Ver Operar um nó.

Cópias de segurança e reposição

Os repositórios podem ser copiados e repostos independentemente do nó em execução, e é isso que torna possível levantar um nó a partir de um snapshot em vez de reexecutar desde a génese, e verificar o estado de um nó reposto contra as raízes confirmadas em vez de confiar na cópia de segurança.

Para onde ir a seguir

Sincronização de estado

Como um nó alcança a cadeia sem reexecutar tudo.

Modelo de estado

O que está a ser guardado e qual a representação que tem autoridade.

Indexador

Reconstruir o histórico a partir dos registos confirmados.

Operar um nó

Os papéis de nó e como pedir informações sobre operar um.