Compact Size
El campo de tamaño variable usado en los mensajes de la red
Un campo compact size se usa en mensajes de la red para indicar el tamaño de un campo que viene después o el número de campos que vienen después.
Puede almacenar números entre 0 y 18446744073709551615.
El tamaño del campo crece a medida que crece el número que contiene. Es decir, los números más pequeños ocupan menos espacio. Eso significa que no necesitas usar un campo de tamaño fijo más grande todo el tiempo para acomodar el número más grande posible.
Estructura
Un campo compact size es una estructura de bytes de tamaño variable. El byte inicial indica el tamaño del campo y también indica los bytes que contienen el número.
| Byte inicial | Número | Intervalo | Tamaño del campo | Ejemplo |
|---|---|---|---|---|
FC (y menos) | El byte actual | 0 - 252 | 1 byte | 64 (100) |
FD | Los próximos 2 bytes | 253 - 65535 | 3 bytes | FDE803 (1.000) |
FE | Los próximos 4 bytes | 65536 - 4294967295 | 5 bytes | FEA0860100 (100.000) |
FF | Los próximos 8 bytes | 4294967296 - 18446744073709551615 | 9 bytes | FF00E40B5402000000 (10.000.000.000) |
Nota: Los bytes que contienen el número están en little-endian.
Entonces, para números pequeños de 252 o menos, usas un solo byte. Pero para números más grandes usas un prefijo FD, FE o FF, y el entero queda contenido en los próximos 2, 4 u 8 bytes.
El valor máximo que un campo compact size puede contener es 18446744073709551615, que es FFFFFFFFFFFFFFFFFF (un prefijo FF seguido de FFFFFFFFFFFFFFFFFF).
La mayoría de las veces verás campos compact size que contienen números de 252 o menos. Así que, a primera vista, puedes pensar que estás mirando un campo simple de 1 byte y no darte cuenta de que estás mirando un tipo especial de campo que puede variar de tamaño.
Un campo compact size que empieza con FF (para números de 8 bytes) es totalmente exagerado y nunca se usa en Bitcoin. Indicaría más de 4 GB de datos a continuación, mucho más de lo que cabría en un bloque real.
Ejemplos
Aquí tienes algunos ejemplos de los distintos prefijos compact size que aparecen en datos de transacción:
FC (y menos)
Un solo byte de FC o menos es con diferencia lo más común:
- a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d – Esta es la famosa transacción de la pizza. Para formar la salida de 10.000 BTC, esta transacción reunió 131 entradas, así que el conteo de entradas fue un campo compact size de 1 byte:
83.
Este es solo un ejemplo rápido. Puedes buscar cualquier transacción en la blockchain y encontrarás campos compact size simples de 1 byte. Están por todas partes.
FD
Te toparás con el prefijo FD de vez en cuando. Eso pasa cuando hay un conteo de entradas/salidas por encima de la media, o si un scriptsig/scriptpubkey es excepcionalmente grande:
- 6bb9c31f15c6940d4bd664054e398e420425339aadc65e8c491cf1151fe7ff4b – Esta transacción tiene 965 entradas, así que el campo compact size es
FDC503(no olvides que los dos últimos bytes están en little-endian, así que03C5= 965). - 3454605a6e24181a6061574720e93a79689865e7952c56c330ebcb98fa95e936 – Esta transacción tiene 254 salidas. Aunque un solo byte puede contener el número 254 en circunstancias normales, en un campo compact size el valor máximo de 1 byte es 252. Así que, en este caso, se usó el prefijo
FDy el número 254 se codificó en los 2 bytes siguientes, dando como resultado el campo compact sizeFDFE00.
FE y FF
Te toparás muy raramente con los prefijos FE o FF (para números mayores que 65.535). Esto se debe a que el tamaño máximo de scriptpubkey/scriptsig es 10.000 bytes, y, debido al límite de tamaño de bloque de 4.000.000 unidades de peso, sería imposible tener más de 65.535 entradas en una sola transacción.
La única vez que encuentras un prefijo FE o FF en la práctica es cuando se usó incorrectamente para almacenar un número que podría haberse colocado en un campo compact size más pequeño.
Dónde aparece
Los campos compact size se usan en todo el contenido de las transacciones brutas — para indicar el número de entradas, el número de salidas, el tamaño del scriptsig, el tamaño del scriptpubkey y el número de elementos de la testigo.
Aquí tienes un ejemplo de transacción heredada con los campos compact size resaltados en verde:
01000000
01 <- conteo de entradas
79fe743502ff8cd181121572fececac3feee5ef3034edfb3ccd2bfaa24537dae00000000
6b <- tamaño del scriptsig
483045022100d39e64...969a2270
ffffffff
01 <- conteo de salidas
72c9000000000000
19 <- tamaño del scriptpubkey
76a91400bafac9185e183c1203025fbdac30a4be5af91088ac
00000000
Un campo compact size también se usa una vez dentro de un bloque bruto, indicando el número de transacciones en el bloque. Y se usa en los distintos mensajes que los nodos se envían unos a otros en la red Bitcoin.
Transacciones y bloques también son mensajes enviados por la red Bitcoin. Así que el campo compact size ayuda a ahorrar espacio en los mensajes serializados que intercambian los nodos. Siempre quieres enviar la menor cantidad de datos posible por la red (por eficiencia), y por eso el compact size es útil.
Beneficios
¿Por qué se usan campos compact size en Bitcoin?
El campo compact size ahorra algunos bytes extra de espacio.
Por ejemplo, puedes meter cómodamente unos pocos miles de salidas en una transacción, pero la mayoría de las veces solo creas una o dos. Una solución básica sería hacer que el campo de conteo de salidas fuera fijo de 2 bytes todo el tiempo, para permitir un número grande en ocasiones raras, aunque en la enorme mayoría de los casos eso no sea necesario:
Campo Fijo de 2 Bytes:
Número | Bytes
--------|------
2 | 0002
27 | 001B
3000 | 0BB8
...
TOTAL = 40 bytes (en 10 transacciones)
Pero, usando un campo compact size flexible, podemos usar 1 byte la mayoría de las veces y expandirlo hasta 3 bytes (1 byte de prefijo + 2 bytes de número) para acomodar números más grandes en las raras ocasiones en que los necesitamos:
Campo Compact Size:
Número | Bytes
--------|------
2 | 02
27 | 1B
3000 | FD0BB8
...
TOTAL = 24 bytes (en 10 transacciones)
Es una técnica de ahorro de espacio pequeña. Pero, cuando tienes varios de estos campos en una transacción, y cientos de miles de transacciones viajando entre computadoras todos los días (y miles de millones de transacciones almacenadas en la blockchain), los bytes se acumulan.
Resumen
Un campo compact size se usa para indicar un número de elementos que vienen después o el tamaño de algunos datos que vienen después, en mensajes de la red (por ejemplo, transacciones brutas). Normalmente tiene 1 byte, pero puede expandirse hasta 9 bytes cuando hace falta para codificar números más grandes.
Forma parte del protocolo desde la primera versión de Bitcoin (v0.1.0) y puede encontrarse en serialize.h. Creo que esta codificación compact size es algo que Satoshi creó al programar Bitcoin, porque no la he visto usada en ningún otro lugar.