22

What is in the header? How is the header made? What information about the transactions is present? What is prunable? What part of the block is used for the PoW?

4
  • 1
    Objection, compound! I wonder whether that might be better split in several questions... It's not obviously too broad, though. Kinda on the fence.
    – user36303
    Commented Apr 3, 2017 at 7:03
  • 1
    Well, I think the only part that is above and beyond a strict use of the word format is the prunable question... but then again, it might not be. It might just be whats the format of a full block and whats the format of a pruned block? You just don't want to spend the time answering :P
    – Ginger Ale
    Commented Apr 3, 2017 at 11:22
  • Then how do you get this: static const char expected_block_hashes_hash[] = "0924bc1c47aae448321fde949554be192878dd800e6489379865218f84eacbca";
    – user7870
    Commented Jul 3, 2018 at 2:20
  • Welcome! But sorry, this is not an answer. If you're not allowed to comment, try posting a new question, referring to this one and making clear what is unexpected about the code you're quoting.
    – ProkhorZ
    Commented Jul 3, 2018 at 9:49

2 Answers 2

21

Block

A block is defined in CNS003 as:

block: a set of data (payload) with a block header

The structure of a block follows, and it is:

  1. Block Structure

    A block consists of three parts:

    • block header,

    • base transaction body,

    • list of transaction identifiers.

    The list starts with the number of transaction identifiers that it contains.

In Monero source code, it is implemented as the block class.

The class inherits the block header class and adds the base transaction body as transaction miner_tx;, and list of transaction identifiers as std::vector<crypto::hash> tx_hashes;.

Block Header

Block header is also defined in CNS003:

4.1 Block Header

Each block starts with a block header. The major version defines the block header parsing rules (i.e. block header format) and is incremented with each block header format update. The table below describes version 1 of the block header format. The minor version defines the interpretation details that are not related to block header parsing.

It is always safe to parse the block header of a particular major version with a parsing procedure suitable for said version, even if the minor version is unknown. Parsing the block header with an unknown major version is not safe as the content of the block header may be misinterpreted.

   +---------------+------------------+--------------------------------+
   |     Field     |       Type       |            Content             |
   +---------------+------------------+--------------------------------+
   | major_version | varint           | Major block header version     |
   |               |                  | (always 1)                     |
   +---------------+------------------+--------------------------------+
   | minor_version | varint           | Minor block header version     |
   |               |                  |                                |
   +---------------+------------------+--------------------------------+
   | timestamp     | varint           | Block creation time            |
   |               |                  | (UNIX timestamp)               |
   +---------------+------------------+--------------------------------+
   | prev_id       | hash             | Identifier of the previous     |
   |               |                  | block                          |
   +---------------+------------------+--------------------------------+
   | nonce         | 4 bytes          | Any value which is used in the |
   |               |                  | network consensus algorithm    |
   +---------------+------------------+--------------------------------+

             Table 4.1: Block header structure description 

The definition of block header is found in Monero source code as well.

  struct block_header
  {
    uint8_t major_version;
    uint8_t minor_version;  // now used as a voting mechanism, rather than how this particular block is built
    uint64_t timestamp;
    crypto::hash  prev_id;
    uint32_t nonce;

Note that major version is used for hard-fork upgrade counting, as seen in Monero source code (1, 2). Looks like it's not exactly following the CN specification, where it was supposed to be changed only if the header parsing scheme changes.

Block Identifier

Each block has a block ID. The block ID of the previous block is made part of header of current block. It is also defined in CNS003:

  1. Calculation of Block Identifier

    The identifier of a block is the result of hashing the following data with Keccak:

    • size of [block_header, Merkle root hash, and the number of transactions] in bytes (varint)

    • block_header,

    • Merkle root hash,

    • number of transactions (varint).

    The goal of the Merkle root hash is to "attach" the transactions referred to in the list to the block header: once the Merkle root hash is fixed, the transactions cannot be modified.

Note that the block identifier is the result of hashing the blob with Keccak and it is not the same as PoW hash.

Mining / PoW Input

The mining data blob is the block header + merkle root + number of TX-es. It's hashed with CryptoNight to obtain the block difficulty. It's similar to block identifier given above, and omits the "size of [block header, ..." which is used exclusively for the block identifier.

See get_block_hashing_blob implementation in Monero source code for details.

  blobdata get_block_hashing_blob(const block& b)
  {
    blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
    crypto::hash tree_root_hash = get_tx_tree_hash(b);
    blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
    blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
    return blob;
  }

As you can see, it retrieves the block header blob, and appends Merkle tree root and number of transactions to the blob.

Block PoW Hashing

For actual hashing, see get_block_longhash implementation in Monero source code and explanation of the "block 202612 bug workaround": What happened at block 202612?

Merkle Tree Root

Merkle tree root is computed as follows, as defined in CNS003:

5.1 Merkle Root Hash Calculation

Merkle root hash is computed from the list of transactions as follows: let tx[i] be the i-th transaction in the block, where 0 <= i <= n-1 (n is the number of transactions) and tx[0] is the base transaction. Let m be the largest power of two, less than or equal to n. Define the array h as follows:

   h[i] = H(h[2*i] || h[2*i+1]) 
     where 1 <= i <= m-1 or 3*m-n <= i <= 2*m-1.
   h[i] = H(tx[i-m])
     where m <= i <= 3*m-n-1
   h[i] = H(tx[i-4*m+n])
     where 6*m-2*n <= i <= 4*m-1.

Where H is the Keccak function that is used throughout CryptoNote, and || denotes concatenation. Then, h[1] is the root hash.

The figure below illustrates the calculation of Merkle root hash in a block with 9 transactions. Each arrow represents a computation of H.

+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
 |tx[0]| |tx[1]| |tx[2]| |tx[3]| |tx[4]| |tx[5]| |tx[6]| |tx[7]| |tx[8]|
 +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
    |       |       |       |       |       |       |       |       |
    |       |       |       |       |       |       |       V       V
    |       |       |       |       |       |       |    +-----+ +-----+
    |       |       |       |       |       |       |    |h[30]| |h[31]|
    |       |       |       |       |       |       |    +-----+ +-----+
    |       |       |       |       |       |       |       |       |
    |       |       |       |       |       |       |       +---+---+
    |       |       |       |       |       |       |           |
    V       V       V       V       V       V       V           V
  +----+ +----+  +-----+ +-----+ +-----+ +-----+ +-----+     +-----+
  |h[8]| |h[9]|  |h[10]| |h[11]| |h[12]| |h[13]| |h[14]|     |h[15]|
  +----+ +----+  +-----+ +-----+ +-----+ +-----+ +-----+     +-----+
    |       |       |       |       |       |       |           |
    +---+---+       +---+---+       +---+---+       +-----+-----+
        |               |               |                 |
        V               V               V                 V
      +----+         +----+           +----+           +----+
      |h[4]|         |h[5]|           |h[6]|           |h[7]|
      +----+         +----+           +----+           +----+
        |               |               |                 |
        +-------+-------+               +--------+--------+
                |                                |
                V                                V
              +----+                          +----+
              |h[2]|                          |h[3]|
              +----+                          +----+
                |                                |
                +----------------+---------------+
                                 |
                                 V
                           +-----------+
                           |root = h[1]|
                           +-----------+

           Figure 5.1: Merkle root hash calculation algorithm

Base Transaction Body / Coinbase TX

This is also known as "coinbase transaction" and is defined in CNS003:

Each valid block contains a single base transaction. The base transaction's validity depends on the block height due to the following reasons:

 - the emission rule is generally defined as a function of time;

 - without the block height field, two base transactions could be indistinguishable as they can have the same hash (see [BH] for a description of a similar problem in Bitcoin).

The structure is as follows:

   +---------------+------------------+--------------------------------+
   |     Field     |       Type       |            Content             |
   +---------------+------------------+--------------------------------+
   | version       | varint           | Transaction format version     |
   |               |                  |                                |
   +---------------+------------------+--------------------------------+
   | unlock_time   | varint           | UNIX timestamp. See [CNS004]   |
   |               |                  |                                |
   +---------------+------------------+--------------------------------+
   | input_num     | varint           | Number of inputs. Always 1 for |
   |               |                  | base transactions              |
   +---------------+------------------+--------------------------------+
   | input_type    | byte             | Always 0xff for base           |
   |               |                  | transactions                   |
   +---------------+------------------+--------------------------------+
   | height        | varint           | Height of the block which      |
   |               |                  | contains the transaction       |
   +---------------+------------------+--------------------------------+
   | output_num    | varint           | Number of outputs              |
   |               |                  |                                |
   +---------------+------------------+--------------------------------+
   | outputs       | array of outputs | Array of outputs. See [CNS004] |
   |               |                  |                                |
   +---------------+------------------+--------------------------------+
   | extra_size    | varint           | Number of bytes in the Extra   |
   |               |                  | field                          |
   +---------------+------------------+--------------------------------+
   | extra         | array of bytes   | Additional data associated with|
   |               |                  | a transaction                  |
   +---------------+------------------+--------------------------------+

           Table 4.2: Base transaction structure description

This is how a miner gets his reward. He is free to generate the output as he wishes, which will hold the newly issued monero. Normally, it would be an output which will belong to his wallet, but it doesn't have to be. For example, a pool miner would be hashing a block where the pool picked the coinbase destination.

List of Transaction Identifiers

It is also defined in CNS003:

4.3 List of Transaction Identifiers

Base transaction is followed by a list of transaction identifiers. A transaction identifier is a transaction body hashed with the Keccak hash function. The list starts with the number of identifiers and is followed by the identifiers themselves if it is not empty.

The structure is as follows:

   +---------------+------------------+--------------------------------+
   |     Field     |       Type       |            Content             |
   +---------------+------------------+--------------------------------+
   | tx_num        | varint           | Number of transaction          |
   |               |                  | identifiers                    |
   +---------------+------------------+--------------------------------+
   | identifiers   | array of hashes  | Array of transaction           |
   |               |                  | identifiers                    |
   +---------------+------------------+--------------------------------+

    Table 4.3: List of transaction identifiers structure description

What follows is the transaction bodies.

Transaction Structure

The transaction structure is explained here: Size requirements for different "pieces" of a Monero transaction

Examples

Monero Block

Command monerod print_block 1300000

timestamp: 1493568547
previous hash: 217b2757da92bc6369fc22d79ef16911fc0716bcea106450c94619e905f3c796
nonce: 25166505
is orphan: 0
height: 1300000
depth: 139416
hash: 31b34272343a44a9f4ac7de7a8fcf3b7d8a3124d7d6870affd510d2f37e74cd0
difficulty: 7877790006
reward: 7883911503742
{
  "major_version": 5, 
  "minor_version": 5, 
  "timestamp": 1493568547, 
  "prev_id": "217b2757da92bc6369fc22d79ef16911fc0716bcea106450c94619e905f3c796", 
  "nonce": 25166505, 
  "miner_tx": {
    "version": 2, 
    "unlock_time": 1300060, 
    "vin": [ {
        "gen": {
          "height": 1300000
        }
      }
    ], 
    "vout": [ {
        "amount": 7883911503742, 
        "target": {
          "key": "7c54ec2fad8c41bb40cde9b78c002572ba777b05bb3bc80d0055c0d3489fdb17"
        }
      }
    ], 
    "extra": [ 1, 116, 174, 179, 44, 181, 153, 245, 119, 27, 105, 192, 244, 181, 175, 62, 47, 244, 15, 129, 8, 223, 115, 234, 203, 131, 15, 62, 152, 103, 136, 144, 134, 2, 8, 0, 0, 0, 10, 174, 4, 8, 0
    ], 
    "rct_signatures": {
      "type": 0
    }
  }, 
  "tx_hashes": [ "140564273396a16135ba0867ded6b7981fdc28bda45c62f993dc51ff26cfb2e5", "a32087d20f25e45097da9c899d8ec17df1d7563abe19047b3d115fe894bbf383", "4d2996d78485bd41980c79a7573e91fb06960a96884eda6b47877be8bc0e4eb4"
  ]
}

Monero Transaction

Command monerod print_tx 140564273396a16135ba0867ded6b7981fdc28bda45c62f993dc51ff26cfb2e5

Found in blockchain at height 1300000
// raw TX data comes here, edited out due to size
{
  "version": 2, 
  "unlock_time": 0, 
  "vin": [ {
      "key": {
        "amount": 0, 
        "key_offsets": [ 58050, 114696, 565113
        ], 
        "k_image": "000b744c27385c6179d1327de7926c4663ecf59ead1fa297a09cc856f53b5ce9"
      }
    }
  ], 
  "vout": [ {
      "amount": 0, 
      "target": {
        "key": "5f68b6e26c114b773bbc1d982255691018a70ca8b307fb63a70761df7d6384cd"
      }
    }, {
      "amount": 0, 
      "target": {
        "key": "4e358822f55f27c6e12d51b0baf5ccfc471ae77208113ac9dc223197469d5c88"
      }
    }
  ], 
  "extra": [ 1, 160, 134, 200, 194, 248, 112, 79, 200, 127, 185, 129, 147, 143, 194, 243, 211, 149, 139, 61, 112, 185, 86, 156, 121, 117, 232, 58, 42, 174, 162, 137, 213
  ], 
  "rct_signatures": {
    "type": 1, 
    "txnFee": 100000000000, 
    "ecdhInfo": [ {
        "mask": "fb052c0d0bb478f75c8bf1a8e843473125d394caa4a1cec357792ae71ad2d30d", 
        "amount": "60f8c83df2b16931bcf0e9af074f287acea41bd45b20e3c345be83370e3b440a"
      }, {
        "mask": "e85d36af212af85c7f556ea1e689ceca581bc87cec26f83a1d77fc1a4bd1420c", 
        "amount": "b0e2961761673e749c0b36f8b1ac92dc85ebc6b9bda6ea804f3984028cc4e701"
      }], 
    "outPk": [ "3bf4e8e8de2bbdd353486a50a46fd3dd380f8a0c3ac90eee6d4592c07585c1f2", "184c27a770095246ba6142e9e2cc4afd1d7506ce15d592cb2bcc3b9e4ac0880e"]
  }, 
  "rctsig_prunable": {
    "rangeSigs": [ {
        "asig": "6b9c...6902", 
        "Ci": "78cc...3238"
      }, {
        "asig": "5d18...6d07", 
        "Ci": "ce44...941b"
      }], 
    "MGs": [ {
        "ss": [ [ "ce5f0dbb6a923862fd2a2e579520373721398774ec35485624888eeaab3ebd06", "120b8c025057494f357eab94cf8b81f6323d8d7639949e1efe889a119c96be0f"], [ "b5827d8931f597f37a0a445d526b279a9ab9b22caff1208c11e802b4b88e0e08", "f9977e6fd9aef346740b03491ddadcc6150f3206d0d40cde56de4d05c339f106"], [ "2a3438085f9ede8027257bbae261229e00f0a5f8fbe94a8e21050f42788e1d0e", "7b792d639af9fef1d2180fa60ee64a3940547fccf3e33b7653d6944e8e74f70c"]], 
        "cc": "b46f8fbc1b2fde02a1b11b717259f275f19f190c4a7f39d30ca928c785fd6903"
      }]
  }
}
2

Concerning the header, according to the file "src/cryptonote_basic/cryptonote_basic.h", it is made of:

  • major_version (varint)
  • minor_version (varint)
  • timestamp (varint)
  • prev_id (32 bytes)
  • nonce (4 bytes)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.