Cada bloco na blockchain do bitcoin contém um resumo de todas as transações no bloco, usando uma
árvore de merkle.
Uma árvore de merkle, também conhecida como uma árvore de hash binário, é uma estrutura de dados usadas para resumir eficientemente e verificar a integridade da grandes conjuntos de dados. As árvores de merkle são árvores binárias contendo hashes criptográficos. O termo "árvore" é usado na ciência da computação para descrever uma estrutura de dados ramificada, mas essas árvores
geralmente são exibidas de cabeça para baixo com a "raiz" no topo e com as "folhas" na porção inferior de um diagrama, como você verá nos exemplos a seguir.
Figure 1. Blocos ligados em uma cadeia, pela referência ao hash do cabeçalho do bloco anterior
As árvores de Merkle são usadas no bitcoin para resumir todas as transações em um bloco, produzindo uma impressão digital eletrônica geral de todo o conjunto de transações, fornecendo um processo muito efeiciente para verificar se uma transação foi incluída em um bloco. Uma árvore de Merkle é construída através do hashing recursivo de pares de nodos até que haja apenas um hash, conhecido como a raiz ou raiz de merkle. O algoritmo de hash criptográfico usado nas árvores de merkle do bitcoin é o SHA256 aplicado duas vezes, também conhecido como SHA256-duplo.
Quando N elementos de dados sofrem hashing e são resumidos em uma árvore merkle, você pode verificar para ver se qualquer elemento de dados foi incluído na árvore com no máximo 2*log~2~(N) cálculos, o que demonstra que a árvore merkle é uma estrutura de dados muito eficiente.
A árvore de merkle é construída de baixo para cima. No exemplo a seguir, nós iniciamos com quatro transações, A, B, C e D, que formam as folhas da árvore de Merkle, como demonstrado em Calculando os nodos em uma árvore de merkle. As transações não são armazenadas na árvore de merkle; ao invés disso, seus dados são "hashed" e o hash resultante é armazenado em cada nodo folha como HA, HB, HC e
HD:
H~A~ = SHA256(SHA256(Transação A))
Os pares consecutivos de nodos folhas são então resumidos em um nodo pai, ao se concatenar dois hashes e fazendo um hashing dos dois juntos. Por exemplo, para construir um nodo pai HAB, os dois
hashes de 32-bytes dos filhos são concatenados para criar uma string de 64-bytes. Essa string sofre então um duplo hashing para produzir o hash do nodo pai:
H~AB~ = SHA256(SHA256(H~A~ + H~B~))
O processo continua até que haja apenas um nodo no topo, o nodo conhecideo como a raiz Merkle. Esse hash de 32-bytes é armazenado no cabeçalho do bloco e resume todos os dados em todas as quatro transações.
Figure 2. Calculando os nodos em uma árvore de merkle
Como a árvore de merkle é uma árvore binária, ela precisa de um número par de nodos folha. Se existir um número ímpar de transações para ser resumido, o hash da última transação será duplicado para criar uma árvore equilibrada, ou seja, uma árvore que contém um número par de nodos folhas. Isso é demonstrado em A duplicação de um elemento de dados gera um número par de elementos de dados, onde a transação C é duplicada.
Figure 3. A duplicação de um elemento de dados gera um número par de elementos de dados
O mesmo método para construir uma árvore a partir de quatro transações pode ser generalizado para construir árvores de qualquer tamanho. No bitcoin é comum que haja várias centenas a mais de
milhares de transações em um único bloco, que podem ser resumidas exatamente da mesma maneira, ao produzir apenas 32 bytes de dados como uma árvore de merkle única. Em Uma árvore de merkle resumindo muitos elementos de dados, você verá uma árvore construída a partir de 16 transações. Note que embora a raiz aparente ser maior do que os nodos-folha no diagrama, ela tem exatamente o mesmo tamanho, apenas 32 bytes. Independente de um bloco ter apenas uma ou centenas de milhares de transações, a raiz de merkle sempre as resume em 32 bytes.
Para provar que uma transação específica está incluída em um bloco, um nodo precisa apenas produzir log~2~(N) hashes de 32 bytes, constituindo um caminho de autenticação ou caminho merkle conectando a transação específica à raiz da árvore. Isso é especialmente importante à medida que o número de transações cresce, porque o logaritmo de base 2 do número de transações aumenta muito mais lentamente. Isso permite que os nodos de bitcoin produzam de maneira eficiente caminhos de 10 ou 12 hashes (320-384 bytes), que podem fornecer uma prova de uma transação individual em um meio de milhares de transações contidas em um bloco com tamanho de megabytes.
Figure 4. Uma árvore de merkle resumindo muitos elementos de dados
Em Um trajeto de merkle usado para provar a inclusão de um elemento de dados, um nodo pode provar que uma transação K é incluída em um bloco ao produzir um caminho merkle que tenha apenas quatro hashes de 32-bytes (128 bytes no total). O caminho consiste em quatro hashes (identificados em azul em Um trajeto de merkle usado para provar a inclusão de um elemento de dados) HL, HIJ, HMNOP e HABCDEFGH. Com esses quatro hashes fornecidos como um caminho de
autenticação, qualquer nodo pode provar que HK (identificado em verde no diagrama) está incluso na
raiz de merkle ao computar quatro hashes pair-wise HKL, HIJKL, HIJKLMNOP, e a raiz da árvore de merkle
Figure 5. Um trajeto de merkle usado para provar a inclusão de um elemento de dados
O código em Construindo uma árvore de Merkle demonstra o processo de criação de uma árvore de merkle desde os hashes dos nodos folha até a raiz, usando a livraria libbitcoin para algumas funções auxiliares.
Example 1. Construindo uma árvore de Merkle #include <bitcoin/bitcoin.hpp>
bc::hash_digest create_merkle(bc::hash_list& merkle) {
// Stop if hash list is empty. if (merkle.empty())
return bc::null_hash; else if (merkle.size() == 1) return merkle[0];
// While there is more than 1 hash in the list, keep looping... while (merkle.size() > 1)
{
// If number of hashes is odd, duplicate last hash in the list. if (merkle.size() % 2 != 0)
merkle.push_back(merkle.back()); // List size is now even.
assert(merkle.size() % 2 == 0); // New hash list.
bc::hash_list new_merkle;
// Loop through hashes 2 at a time.
for (auto it = merkle.begin(); it != merkle.end(); it += 2) {
bc::data_chunk concat_data(bc::hash_size * 2);
auto concat = bc::make_serializer(concat_data.begin()); concat.write_hash(*it);
concat.write_hash(*(it + 1));
assert(concat.iterator() == concat_data.end()); // Hash both of the hashes.
bc::hash_digest new_root = bc::bitcoin_hash(concat_data); // Add this to the new list.
new_merkle.push_back(new_root); }
// This is the new list. merkle = new_merkle;
// DEBUG output --- std::cout << "Current merkle hash list:" << std::endl; for (const auto& hash: merkle)
std::cout << " " << bc::encode_hex(hash) << std::endl; std::cout << std::endl;
// --- }
// Finally we end up with a single item. return merkle[0];
}
int main() {
// Replace these hashes with ones from a block to reproduce the same merkle root. bc::hash_list tx_hashes{{ bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000000"), bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000011"), bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000022"), }};
const bc::hash_digest merkle_root = create_merkle(tx_hashes);
std::cout << "Result: " << bc::encode_hex(merkle_root) << std::endl; return 0;
}
Compilando e executando o código de exemplo merkle mostra o resultado da compilação e execução do código de merkle
Example 2. Compilando e executando o código de exemplo merkle $ # Compilar o código merkle.cpp
$ g++ -o merkle merkle.cpp $(pkg-config --cflags --libs libbitcoin) $ # Rodar o executável merkle
$ ./merkle
Hash list de merkle atual:
32650049a0418e4380db0af81788635d8b65424d397170b8499cdc28c4d27006 30861db96905c8dc8b99398ca1cd5bd5b84ac3264a4e1b3e65afa1bcee7540c4 Hash list de merkle atual:
d47780c084bad3830bcdaf6eace035e4c6cbf646d103795d22104fb105014ba3
Resultado: d47780c084bad3830bcdaf6eace035e4c6cbf646d103795d22104fb105014ba3
A eficiência da árvore de merkle se torna óbvia na medida que ela cresce em escala. Eficiência da árvore de Merkle mostra a quantidade de dados que precisa ser trocada como um caminho de merkle para provar que uma transação faz parte de um bloco.
Table 3. Eficiência da árvore de Merkle
Número de transações Tamanho aprox. do
bloco Tamanho do caminho(hashes) Tamanho do caminho(bytes)
16 transações 4 kilobytes 4 hashes 128 bytes 512 transações 128 kilobytes 9 hashes 288 bytes 2.048 transações 512 kilobytes 11 hashes 352 bytes 65.535 transações 16 megabytes 16 hashes 512 bytes
Como você pode ver na tabela, enquanto o tamanho do bloco aumenta rapidamente, de 4 KB com 16 transações até um tamanho de bloco de 16 MB, para comportar 65.535 transações, o caminho merkle necessário para provar a inclusão de uma transação cresce muito mais lentamente, de 128 bytes para somente 512 bytes. Com árvores merkle, um nodo pode fazer apenas o download dos cabeçalhos dos blocos (80 bytes por bloco) e ainda ser capaz de identificar a inclusão de uma transação em um bloco ao adquirir um pequeno caminho merkle a partir de um nodo completo, sem armazenar ou transmitir a vasta maioria da blockchain, que pode ter vários gigabytes de tamanho. Os nodos que não mantém uma blockchain completa, chamados de nodos de verificação simplificada de pagamento (nodos VSP), usam caminhos merkle para verificar as transações sem ter que fazer o download dos blocos completos.