Glosario / Referencia para desarrolladores
MSG_CMPCT_BLOCK
- ¿Qué es MSG_CMPCT_BLOCK?
- MSG_CMPCT_BLOCK, el tipo de inventario 4, es un código exclusivo de solicitudes: nunca aparece en un anuncio y solo es válido dentro de un mensaje getdata enviado a un par que lo aceptó antes.
Se especifica en el BIP-152.
Los bloques compactos se negocian, no se anuncian. Un par envía una vez el mensaje sendcmpct para indicar que los aceptará, y solo entonces la otra parte puede responder a un bloque nuevo con el tipo 4 en lugar del tipo 2. BIP152 llegó con Bitcoin Core 0.13.0 en agosto de 2016, y el ahorro es precisamente su razón de ser: seis bytes para nombrar una transacción que el destinatario ya tiene, en lugar de los doscientos o más que cuesta enviarla dos veces.
Cómo funciona
MSG_CMPCT_BLOCK solicita una descripción de un bloque en lugar del bloque, y esa descripción solo vale la pena cuando los dos nodos tienen mempools parecidas.
Primero viene la negociación. El mensaje sendcmpct lleva un indicador y un número de versión: la versión 1 identifica las transacciones por txid; la versión 2, por txid de testigo, y es la única en uso desde SegWit. Un nodo nunca debe poner el tipo 4 en un mensaje getdata dirigido a un par que no haya enviado sendcmpct, porque ese par no tiene ninguna obligación de entenderlo.
La respuesta es un mensaje cmpctblock que contiene el encabezado de 80 bytes del bloque, un nonce de ocho bytes, un identificador corto de seis bytes por transacción y unas pocas transacciones completas, entre ellas siempre la transacción coinbase, que el destinatario de ningún modo puede haber visto ya. Los identificadores cortos se generan con SipHash, con una clave derivada del encabezado del bloque y de ese nonce, así que cambian con cada bloque y con cada solicitud. La aleatorización es una defensa: un esquema fijo permitiría a un atacante precalcular dos transacciones que colisionen y atascar la reconstrucción en toda la red a la vez.
El destinatario compara los identificadores con su mempool, solicita lo que falte con un mensaje getblocktxn y reconstruye el bloque localmente. La validación posterior es la habitual, y no se toca ninguna regla de consenso.
La profundidad está limitada. Bitcoin Core sirve un bloque compacto solo para los cinco bloques más recientes y responde con un bloque completo a la solicitud de cualquier bloque más antiguo, porque un destinatario tan atrasado no tiene una mempool útil y acabaría solicitando todas las transacciones del bloque.
Dónde aparece
Donde mejor se ve MSG_CMPCT_BLOCK es en el propio registro de depuración de Bitcoin Core, que informa de lo bien que salió cada reconstrucción.
Inicie el nodo con -debug=cmpctblock y cada bloque nuevo generará una línea que indica cuántas transacciones venían precargadas, cuántas se encontraron en la mempool y cuántas hubo que descargar. En una máquina que lleva horas en marcha, el recuento de transacciones descargadas suele ser cero, y el bloque llega en forma de decenas de kilobytes en lugar de un megabyte y medio. Un bloque con 3.000 transacciones necesita 18.000 bytes de identificadores cortos, más el encabezado del bloque y la transacción coinbase.
Esa aritmética se viene abajo en un nodo recién iniciado. Con una mempool vacía, ningún identificador encuentra coincidencia, la solicitud posterior abarca el bloque entero y el viaje de ida y vuelta adicional hace que la ruta compacta sea más lenta que solicitar el bloque directamente. Por eso el código es propio de los nodos situados en la punta de la cadena y nunca aparece durante una sincronización inicial.
Para quien ejecuta un nodo en casa, esta es la funcionalidad que decide si una conexión corriente sigue el ritmo de la red o se queda atrás cada vez que se encuentra un bloque.