Compact Size
O campo de tamanho variável usado nas mensagens da rede
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.
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.
| Byte Inicial | Número | Intervalo | Tamanho do Campo | Exemplo |
|---|---|---|---|---|
FC (e abaixo) | O byte atual | 0 - 252 | 1 byte | 64 (100) |
FD | Próximos 2 bytes | 253 - 65535 | 3 bytes | FDE803 (1.000) |
FE | Próximos 4 bytes | 65536 - 4294967295 | 5 bytes | FEA0860100 (100.000) |
FF | Próximos 8 bytes | 4294967296 - 18446744073709551615 | 9 bytes | FF00E40B5402000000 (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:
- a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d – Esta é a famosa transação da pizza. Para formar a saída de 10.000 BTC, esta transação reuniu 131 entradas, então a contagem de entradas foi um campo compact size de 1 byte:
83.
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:
- 6bb9c31f15c6940d4bd664054e398e420425339aadc65e8c491cf1151fe7ff4b – Esta transação tem 965 entradas, então o campo compact size é
FDC503(não esqueça que os dois últimos bytes estão em little-endian, então03C5= 965). - 3454605a6e24181a6061574720e93a79689865e7952c56c330ebcb98fa95e936 – Esta transação tem 254 saídas. Embora um único byte possa conter o número 254 em circunstâncias normais, em um campo compact size o valor máximo de 1 byte é 252. Então, neste caso, o prefixo
FDfoi usado e o número 254 foi codificado nos 2 bytes seguintes, resultando no campo compact sizeFDFE00.
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.