How does serializing in coins.h work?

2

1

I'm talking specifically about this:

/** 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).
 *
 * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e
 *          <><><--------------------------------------------><---->
 *          |  \                  |                             /
 *    version   code             vout[1]                  height
 *
 *    - version = 1
 *    - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
 *    - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
 *    - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
 *               * 8358: compact amount representation for 60000000000 (600 BTC)
 *               * 00: special txout type pay-to-pubkey-hash
 *               * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
 *    - height = 203998
 *
 *
 * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b
 *          <><><--><--------------------------------------------------><----------------------------------------------><---->
 *         /  \   \                     |                                                           |                     /
 *  version  code  unspentness       vout[4]                                                     vout[16]           height
 *
 *  - version = 1
 *  - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,
 *                2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow)
 *  - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
 *  - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
 *             * 86ef97d579: compact amount representation for 234925952 (2.35 BTC)
 *             * 00: special txout type pay-to-pubkey-hash
 *             * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160
 *  - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4
 *              * bbd123: compact amount representation for 110397 (0.001 BTC)
 *              * 00: special txout type pay-to-pubkey-hash
 *              * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
 *  - height = 120891
 */

I don't really understand how nCode works. Let's take the second example:

First bit is set to indicate it's a coinbase transaction. So far nCode = 01. vout[0] and vout[1] are spent, which means we add 1 because there is at least 1 unspent output. So the bitmask is 0001 0001, which is equal to 0x11.

So already we have a number bigger than 0x09. How the hell is that nCode = 0x09 computed?

stanm87

Posted 2014-10-15T14:03:35.507

Reputation: 237

Answers

2

(note: I'll be using a different bit numbering from the comment which goes from 0..B instead of 1..2^B, as I find that easier to read myself)

The binary representation of 0x9 separated in functional groups is

bit# ...6543 21 0
        ---------
        0001 00 1
  • Bit 0 is set because this is a coinbase
  • Bit 2 and 1 are 0, because vout[0] and vout[1] are spent
  • Bit 3+ contain just the binary number 1. As bit 1 and 2 are not set, these bits encode N-1. N=(9>>3)+1=2. N here is the number of bytes in the subsequent bit vector.

These two bytes that follow are 04 and 40, encoding the number 0x440, the number with bits 2 (1<<4=0x04) and 14 (1<<14=0x4000) set. As described in the example this means vout[2+2] and vout[14+2] are unspent.

How do you end up at 0x11?

wumpus

Posted 2014-10-15T14:03:35.507

Reputation: 311

I think my first confusion comes from the numbering, I agree yours is easier to read.stanm87 2014-10-15T14:50:24.427

However, I only follow you until you say N=(9&gt;&gt;3)+1=2 Where do you get this from?stanm87 2014-10-15T14:51:12.700

(9>>3) extracts bits 3+ from the input nCode using the shift-right operator. This is 1, to which 1 is added to result in 2.wumpus 2014-10-15T14:58:28.563

Ok thanks, I get it. But now I don't get the next part. Correct me if I'm wrong, but 2&lt;&lt;4=0x20and 2&lt;&lt;14=0x8000, no?stanm87 2014-10-15T15:09:51.703

I still don't see how 0x440 encodes bits 2 and 14. Sorry I'm pretty new at this.stanm87 2014-10-15T15:19:40.557

My bad, I skipped the part where it said least significant byte first. Now it makes sense to me.stanm87 2014-10-15T15:26:50.240

Sorry, my bad, you need to use 1&lt;&lt;2 and 1&lt;&lt;14. I'll correct my comment.wumpus 2014-10-17T07:38:02.097