Analizar UTXO de una transacción de chainstate

Estoy haciendo un análisis en el conjunto UTXO leyendo de la base de datos chainstate.

Estaba siguiendo los documentos proporcionados por https://github.com/bitcoin/bitcoin/blob/d4a42334d447cad48fb3996cad0fd5c945b75571/src/coins.h#L19-L34

/** pruned version of CTransaction: only retains metadata and unspent transaction outputs
 *
 * Serialized format:
 * - VARINT(nVersion)
 * - VARINT(nCode)
 * - unspentness bitvector, for vout[2] and further; least significant byte first
 * - the non-spent CTxOuts (via CTxOutCompressor)
 * - VARINT(nHeight)
 *
 * The nCode value consists of:
 * - bit 1: IsCoinBase()
 * - bit 2: vout[0] is not spent
 * - bit 4: vout[1] is not spent
 * - The higher bits encode N, the number of non-zero bytes in the following bitvector.
 *   - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at
 *     least one non-spent output).

El analizador funcionó bien cuando el número de UTXO es pequeño. Sin embargo, para el siguiente tx (que tiene 2501 salidas), falló:

2540b961f4a0b231db3bc5a23608307394eae037d8afd0462e9b794e02f00000

Para la clave 'c' + 2540b961f4a0b231db3bc5a23608307394eae037d8afd0462e9b794e02f00000, el valor (desofuscado) en chainstate se ve así:

01907050e140254150443a0c280004...

Donde 01está la versión, 9070es la nCodeque indica si es un tx de base de monedas, la cantidad no gastada de vout[0], vout[1]y la longitud del siguiente vector de bits no gastado para vout[2:]. Al mirar blockchain.info, hay 2501 salidas, por lo que habrá (2501 - 2)/8 = 312bytes a continuación. Sin embargo, analizar 9070como una variante, eliminar los últimos bits y +1 solo me da 2288 / 8 + 1 = 287. (Obtuve 2288 por (0x90 - 0x80 + 1) * 0x80 + 0x70, que es la variante MSB-128 utilizada en el protocolo bitcoin).

¿Me perdí algo aquí? ¿Cómo se analiza exactamente la variante?

Respuestas (1)

Tienes razón, sin embargo no estás interpretando el resultado correctamente. 287De hecho , el valor es , es decir (2288 >> 3) + 1, sin embargo, esto no significa que el vector de bits contiene 287 bytes, sino que contiene 287 non-zero bytes, por lo que al analizar el vector de bits, debe disminuir el contador de bytes solo cuando encuentre un valor distinto de cero. Aquí tienes un fragmento de código que se ocupa de esto ( nes 287en este caso):

# If n is set, the encoded value contains a bitvector. The following bytes are parsed until n non-zero bytes have
# been extracted. (If a 00 is found, the parsing continues but n is not decreased)
if n > 0:
    bitvector = ""
    while n:
        data = utxo[offset:offset+2]
        if data != "00":
            n -= 1
        bitvector += data
        offset += 2

Tenga en cuenta que esto es solo un fragmento del código. He codificado un decodificador completo en Python recientemente, puede consultar el código en github .

Hmm, eso tiene sentido. He leído muchas preguntas y respuestas tuyas sobre este tema. ¡Muchas gracias!
¿Puedo preguntar también cómo se CTxOutsserializan? Entiendo que la mayoría son de la forma CompressedAmount + 00 + hash160 of pubkey, pero hay muchas transacciones no estándar que son difíciles de analizar.
También es parte del código que vinculé en la respuesta, permítanme extender la respuesta para incluir esa parte del código (verifique los comentarios)
Exacto, ahí está.