Compact Size

O campo de tamanho variável usado nas mensagens da rede

Diagrama mostrando como o campo compact size indica o tamanho ou a contagem de itens a seguir.

Um campo compact size é usado em mensagens da rede para indicar o tamanho de um campo a seguir ou o número de campos a seguir.

Ele pode armazenar números entre 0 e 18446744073709551615.

O tamanho do campo aumenta conforme o número que ele contém aumenta. Ou seja, números menores ocupam menos espaço. Isso significa que você não precisa usar um campo de tamanho fixo maior o tempo todo para acomodar o maior número aceitável.

Ícone Ferramenta

Compact Size

Converta entre um número e sua codificação compact size (o varint usado no Bitcoin).

Estrutura

Um campo compact size é uma estrutura de bytes de tamanho variável. O byte inicial indica o tamanho do campo e também indica os bytes que contêm o número.

Diagrama mostrando os prefixos usados para campos compact size e os tamanhos de campo correspondentes.
Byte InicialNúmeroIntervaloTamanho do CampoExemplo
FC (e abaixo)O byte atual0 - 2521 byte64 (100)
FDPróximos 2 bytes253 - 655353 bytesFDE803 (1.000)
FEPróximos 4 bytes65536 - 42949672955 bytesFEA0860100 (100.000)
FFPróximos 8 bytes4294967296 - 184467440737095516159 bytesFF00E40B5402000000 (10.000.000.000)

Nota: Os bytes que contêm o número estão em little-endian.

Então, para números pequenos de 252 ou menos, você usa um único byte. Mas para números maiores você usa um prefixo de FD, FE ou FF, e o inteiro fica contido nos próximos 2, 4 ou 8 bytes.

O valor máximo que um campo compact size pode conter é 18446744073709551615, que é FFFFFFFFFFFFFFFFFF (um prefixo FF seguido de FFFFFFFFFFFFFFFFFF).

Na maioria das vezes você verá campos compact size contendo números de 252 ou menos. Então, à primeira vista, você pode supor que está olhando um campo simples de 1 byte e não perceber que está olhando um tipo especial de campo que pode variar de tamanho.

Um campo compact size começando com FF (para números de 8 bytes) é totalmente exagerado e nunca é usado no Bitcoin. Ele indicaria mais de 4 GB de dados a seguir, muito mais do que jamais caberia dentro de um bloco real.

Exemplos

Aqui estão alguns exemplos dos diferentes prefixos compact size encontrados em dados de transação:

FC (e abaixo)

Um único byte de FC ou abaixo é de longe o mais comum:

Este é só um exemplo rápido. Você pode procurar qualquer transação na blockchain e encontrará campos compact size simples de 1 byte. Eles estão em todo lugar.

FD

Você vai esbarrar no prefixo FD de vez em quando. Isso acontece quando há uma contagem de entradas/saídas acima da média, ou se um scriptsig/scriptpubkey for excepcionalmente grande:

FE e FF

Você vai esbarrar muito raramente nos prefixos FE ou FF (para números maiores que 65.535). Isso porque o tamanho máximo de scriptpubkey/scriptsig é 10.000 bytes, e, devido ao limite de tamanho do bloco de 4.000.000 unidades de peso, seria impossível ter mais de 65.535 entradas em uma única transação.

A única vez que você encontra um prefixo FE ou FF na prática é quando ele foi usado incorretamente para armazenar um número que poderia ter sido colocado em um campo compact size menor.

Onde aparece

Os campos compact size são usados em todo o conteúdo das transações brutas — para indicar o número de entradas, o número de saídas, o tamanho do scriptsig, o tamanho do scriptpubkey e o número de elementos da testemunha.

Aqui está um exemplo de transação legada com os campos compact size destacados em verde:

01000000
  01 <- contagem de entradas
    79fe743502ff8cd181121572fececac3feee5ef3034edfb3ccd2bfaa24537dae00000000
    6b <- tamanho do scriptsig
      483045022100d39e64...969a2270
    ffffffff
  01 <- contagem de saídas
    72c9000000000000
    19 <- tamanho do scriptpubkey
      76a91400bafac9185e183c1203025fbdac30a4be5af91088ac
00000000

Um campo compact size também é usado uma vez dentro de um bloco bruto, indicando o número de transações no bloco. E é usado nas várias mensagens que os nós enviam uns aos outros na rede bitcoin.

Transações e blocos também são mensagens enviadas pela rede bitcoin. Então o campo compact size ajuda a economizar espaço nas mensagens serializadas trocadas entre os nós. Você sempre quer enviar a menor quantidade de dados possível pela rede (por eficiência), e é por isso que o compact size é útil.

Benefícios

Por que campos compact size são usados no Bitcoin?

O campo compact size economiza alguns bytes extras de espaço.

Por exemplo, você consegue colocar confortavelmente alguns milhares de saídas em uma transação, mas na maioria das vezes você só cria uma ou duas. Uma solução básica seria fazer o campo de contagem de saídas ser fixo em 2 bytes o tempo todo, para permitir um número grande em raras ocasiões, mesmo que na vasta maioria das vezes isso não seja necessário:

Campo Fixo de 2 Bytes:

Número  | Bytes
--------|------
 2      | 0002
 27     | 001B
 3000   | 0BB8
 ...

 TOTAL = 40 bytes (em 10 transações)

Mas, usando um campo compact size flexível, podemos usar 1 byte na maioria das vezes e expandir até 3 bytes (1 byte de prefixo + 2 bytes de número) para acomodar números maiores nas raras ocasiões em que precisamos:

Campo Compact Size:

Número  | Bytes
--------|------
 2      | 02
 27     | 1B
 3000   | FD0BB8
 ...

 TOTAL = 24 bytes (em 10 transações)

É uma técnica de economia de espaço pequena. Mas, quando você tem vários desses campos em uma transação, e centenas de milhares de transações viajando entre computadores todos os dias (e bilhões de transações armazenadas na blockchain), os bytes se somam.

Resumo

Um campo compact size é usado para indicar um número de itens a seguir ou o tamanho de alguns dados a seguir, em mensagens da rede (ex.: transações brutas). Normalmente tem 1 byte, mas pode se expandir até 9 bytes quando necessário para codificar números maiores.

Ele faz parte do protocolo desde o primeiro lançamento do Bitcoin (v0.1.0) e pode ser encontrado em serialize.h. Acredito que essa codificação compact size é algo que o Satoshi criou ao programar o Bitcoin, pois não a vi sendo usada em nenhum outro lugar.

Recursos