Разобрать UTXO транзакции из состояния цепочки

Я делаю некоторый анализ набора UTXO, считывая данные из базы данных chainstate.

Я следил за документами, предоставленными 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).

Парсер нормально работал, когда количество UTXO невелико. Однако для следующего tx (с 2501 выходом) это не удалось:

2540b961f4a0b231db3bc5a23608307394eae037d8afd0462e9b794e02f00000

Для ключа 'c' + 2540b961f4a0b231db3bc5a23608307394eae037d8afd0462e9b794e02f00000значение (деобфускированное) в цепочке выглядит следующим образом:

01907050e140254150443a0c280004...

Где 01находится версия, которая сообщает, 9070является nCodeли это coinbase tx, неизрасходованным vout[0], vout[1]и длиной следующего битового вектора неизрасходованного для vout[2:]. Глядя на blockchain.info, есть 2501 вывод, поэтому за ними должны следовать (2501 - 2)/8 = 312байты. Однако разбор 9070как вариант, удаление последних трех бит и +1 дают мне только 2288 / 8 + 1 = 287. (Я получил 2288 от (0x90 - 0x80 + 1) * 0x80 + 0x70, это вариант MSB-128, используемый в протоколе биткойнов.)

Я что-то пропустил здесь? Как именно разбирается варинт?

Ответы (1)

Вы правы, однако вы не правильно интерпретируете результат. Значение действительно равно 287, то есть (2288 >> 3) + 1, однако это означает не то, что битвектор содержит 287 bytes, а то, что он содержит 287 non-zero bytes, поэтому при разборе битвектора следует уменьшать счетчик байтов только тогда, когда вы найдете ненулевое значение. Здесь у вас есть кусок кода, который имеет дело с этим ( nв 287данном случае):

# 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

Обратите внимание, что это всего лишь фрагмент кода. Недавно я написал полный декодер на Python, вы можете проверить код на github .

Хм, в этом есть смысл. Я прочитал много ваших вопросов и ответов на эту тему. Спасибо большое!
Могу я также спросить, как CTxOutsсериализуются? Я понимаю, что большинство из них имеют форму CompressedAmount + 00 + hash160 of pubkey, но есть много нестандартных транзакций, которые трудно разобрать.
Это также часть кода, который я указал в ответе, позвольте мне расширить ответ, включив в него эту часть кода (проверьте комментарии)
Нашел, спасибо. github.com/sr-gi/bitcoin_tools/blob/…
Точно, вот оно.