Saltar al contenido
buybitcoinsmart

Glosario / Referencia para desarrolladores

CompactSize

También se conoce como Entero de longitud variable o VarInt.

¿Qué es CompactSize?
CompactSize es el entero de longitud variable con el que bitcoin antepone recuentos y longitudes en los datos serializados, y cuesta un byte para valores inferiores a 253 y hasta nueve para el resto.

Los formatos binarios de Bitcoin no llevan nombres de campo, así que a un analizador hay que decirle cuántas entradas siguen y cuánto mide cada script. CompactSize responde con tan solo un byte: de 0 a 252 es solo ese byte, y los valores mayores ocupan un marcador más otros dos, cuatro u ocho. Cada pago que usted envía contiene al menos cuatro de ellos.

Cómo funciona

CompactSize lee su propio primer byte para decidir cuánto de sí mismo le queda.

Un primer byte inferior a 0xfd es el valor, así que los recuentos de 0 a 252 ocupan un byte y nada más. Un primer byte igual a 0xfd significa que el valor está en los dos bytes siguientes, 0xfe en los cuatro siguientes y 0xff en los ocho siguientes. Todos esos números posteriores son little endian (el byte menos significativo primero). La codificación más larga posible es de nueve bytes y puede expresar un valor superior a 18 mil millones de mil millones, algo que ninguna estructura real necesita ni de lejos.

Las codificaciones deben ser mínimas. Escribir el número 5 como 0xfd 0x05 0x00 es aritméticamente idéntico a escribir 0x05, y Bitcoin Core lo rechaza con un error de codificación no canónica al deserializar. Sin esa regla, la misma transacción podría escribirse de varias formas, cada una con un identificador distinto, lo que es un problema de maleabilidad de transacciones y no de pulcritud.

Hay un techo práctico muy por debajo del aritmético. Bitcoin Core se niega a reservar memoria para cualquier objeto deserializado que diga ser mayor de 0x02000000 bytes, alrededor de 33,5 megabytes, y, por separado, el protocolo entre pares limita un mensaje a 4.000.000 bytes. Por tanto, un par hostil no puede hacer que su nodo reserve gigabytes de memoria anunciando una transacción con mil millones de mil millones de entradas.

Conviene señalar una trampa de nomenclatura. La documentación del formato en la red lo llama var_int, las bibliotecas de billeteras suelen llamarlo VarInt, y el propio código fuente de Bitcoin Core usa el nombre VarInt para una codificación completamente distinta y sin relación, que solo aparece en su base de datos y en sus archivos de deshacer. Al leer código, compruebe cuál de los dos tiene delante.

Dónde aparece

CompactSize es la estructura que más a menudo aparece en bitcoin sin tener ningún nombre visible para el usuario.

En una transacción en bruto aparece justo después de la versión de cuatro bytes, o después del byte marcador y el byte indicador de SegWit cuando están presentes, y contiene el recuento de entradas. Vuelve a aparecer antes de cada script para dar su longitud, y otra vez antes del recuento de salidas. En un bloque serializado lleva el recuento de transacciones. En el protocolo entre pares abre la carga útil de los mensajes inv, getdata, addr y headers.

El mensaje headers muestra la codificación en su versión más extraña. Cada encabezado de bloque de 80 bytes va seguido de un recuento de transacciones CompactSize igual a cero, así que cada elemento ocupa 81 bytes en lugar de 80, y un lote completo de 2.000 encabezados de bloque suma 162.000 bytes en la red. El recuento siempre es cero porque un mensaje headers nunca lleva transacciones. El campo existe para que el mismo código de análisis pueda leer un encabezado de bloque tanto si le sigue el cuerpo de un bloque como si no.

Si usted decodifica a mano una transacción en bruto y los campos dejan de tener sentido a mitad de lectura, la causa casi siempre es un CompactSize mal leído. Si se consume un byte de menos, todo lo que viene después queda desplazado.

Preguntas frecuentes

¿Por qué recurre bitcoin a un entero de longitud variable?

Porque casi todos los recuentos de bitcoin son pequeños. Una transacción suele tener una o dos entradas, y gastar cuatro u ocho bytes en decirlo en cada campo de cada transacción realizada hasta hoy habría añadido un gran volumen de datos permanente para nada.

¿CompactSize es lo mismo que el VarInt de Bitcoin Core?

No, pese al apodo compartido. CompactSize es el formato en la red y en disco que se describe aquí, mientras que la clase llamada VarInt en Bitcoin Core es una codificación compacta distinta que solo se usa dentro de su propia base de datos y de sus archivos de deshacer.

Términos relacionados

Más en la sección Referencia para desarrolladores

Leer esta página en inglés