---
# System prepended metadata

title: Block construction data flow

---


Below, `parent` refers to the `block_state` of the parent block from which a new block is being constructed.

## dpos data

currently in controller.cpp, we have the `building_block` whose members are:

```c++
struct building_block {
   pending_block_header_state                 _pending_block_header_state;       // IF: Remove from building_block. See below for replacements.
   std::optional<producer_authority_schedule> _new_pending_producer_schedule;    // IF: Replaced by new_proposal_policy.
   vector<digest_type>                        _new_protocol_feature_activations; // IF: Comes from building_block_input::new_protocol_feature_activations
   size_t                                     _num_new_protocol_features_that_have_activated = 0; // Stays only in building_block
   deque<transaction_metadata_ptr>            _pending_trx_metas;                // Moved from building_block to assembled_block
   deque<transaction_receipt>                 _pending_trx_receipts;             // Moved from building_block to the transactions in the constructed block
   std::variant<checksum256_type, digests_t>  _trx_mroot_or_receipt_digests;     // IF: Extract computed trx mroot to assembled_block_input::transaction_mroot 
   digests_t                                  _action_receipt_digests;           // IF: Extract computed action mroot to assembled_block_input::action_mroot
};
```

the `assembled_block`:


```c++
struct assembled_block {
   block_id_type                     _id;                                        // Cache of _unsigned_block->calculate_id().
   pending_block_header_state        _pending_block_header_state;                // IF: Remove from assembled_block. See below for replacements.
   deque<transaction_metadata_ptr>   _trx_metas;                                 // Comes from building_block::_pending_trx_metas
                                                                                 // Carried over to put into block_state (optimization for fork reorgs)
   signed_block_ptr                  _unsigned_block;                            // IF: keep same member

   // if the _unsigned_block pre-dates block-signing authorities this may be present.
   std::optional<producer_authority_schedule> _new_producer_authority_cache;     // IF: Remove from assembled_block 
                                                                                 // pending_producers() not needed in IF. proposed_proposers() sufficient.
};
```

and the `pending_block_header_state`:

```c++

struct block_header_state_legacy_common {
  uint32_t                          block_num = 0;                               // IF: block_header::num_from_id(parent_id) + 1
  uint32_t                          dpos_proposed_irreversible_blocknum = 0;     // Unneeded for IF
  uint32_t                          dpos_irreversible_blocknum = 0;              // Unneeded during the building block stage for IF
  producer_authority_schedule       active_schedule;                             // IF: Replaced by active_proposer_policy stored in building_block.
  incremental_merkle                blockroot_merkle;                            // Unneeded during the building block stage for IF
  flat_map<account_name,uint32_t>   producer_to_last_produced;                   // Unneeded for IF
  flat_map<account_name,uint32_t>   producer_to_last_implied_irb;                // Unneeded for IF
  block_signing_authority           valid_block_signing_authority;               // IF: Get from within active_proposer_policy for building_block.producer.
  vector<uint8_t>                   confirm_count;                               // Unneeded for IF
};

struct pending_block_header_state : public detail::block_header_state_legacy_common {
   protocol_feature_activation_set_ptr  prev_activated_protocol_features;        // IF: building_block.prev_activated_protocol_features
   detail::schedule_info                prev_pending_schedule;                   // Unneeded for IF
   bool                                 was_pending_promoted = false;            // Unneeded for IF
   block_id_type                        previous;                                // Not needed but present anyway at building_block.parent_id
   account_name                         producer;                                // IF: building_block.producer
   block_timestamp_type                 timestamp;                               // IF: building_block.timestamp
   uint32_t                             active_schedule_version = 0;             // Unneeded for IF
   uint16_t                             confirmed = 1;                           // Unneeded for IF
};
```

and all this lives in `pending_state` which I believe can stay unchanged.

## IF data

The new storage for IF is:

```c++
struct block_header_state_core {
   uint32_t                last_final_block_num = 0;     // last irreversible (final) block.
   std::optional<uint32_t> final_on_strong_qc_block_num; // will become final if this header achives a strong QC.
   std::optional<uint32_t> last_qc_block_num;            //
   uint32_t                finalizer_policy_generation;  

   block_header_state_core next(uint32_t last_qc_block_num, bool is_last_qc_strong) const;
};

struct quorum_certificate {
  uint32_t                 block_num;
  valid_quorum_certificate qc;
};

struct block_header_state {
   block_header                         header;
   protocol_feature_activation_set_ptr  activated_protocol_features;
   block_header_state_core              core;
   incremental_merkle_tree              proposal_mtree;
   incremental_merkle_tree              finality_mtree;
   finalizer_policy_ptr                 active_finalizer_policy; // finalizer set + threshold + generation, supports `digest()`
   proposer_policy_ptr                  active_proposer_policy;  // producer authority schedule, supports `digest()`
   
   flat_map<block_timestamp_type, proposer_policy_ptr>  proposer_policies;
   flat_map<uint32_t, finalizer_policy_ptr>             finalizer_policies;

   digest_type           compute_finalizer_digest() const;
   
   proposer_policy_ptr   get_next_active_proposer_policy(block_timestamp_type next_timestamp) const {
      // Find latest proposer policy within proposer_policies that has an active_time <= next_timestamp.
      // If found, return the proposer policy that was found.
      // Otherwise, return active_proposer_policy.
   }
   
   block_timestamp_type  timestamp() const  { return header.timestamp; }
   account_name          producer() const  { return header.producer; }
   block_id_type         previous() const  { return header.previous; }
   uint32_t              block_num() const { return block_header::num_from_id(previous()) + 1; }
   
   // block descending from this need the provided qc in the block extension
   bool                  is_needed(const quorum_certificate& qc) const {
      return !core.last_qc_block_num || qc.block_num > *core.last_qc_block_num;
   }
   
   block_header_state   next(const block_header_state_input& data) const;
};

struct block_state {
   const block_header_state          bhs; 
   const signed_block_ptr            block;
   
   const block_id_type               id;  // cache of bhs.header.calculate_id() (indexed on this field)
   const digest_type                 finalizer_digest; // cache of bhs.compute_finalizer_digest()

   std::optional<pending_quorum_certificate>  pending_qc;
   std::optional<valid_quorum_certificate>    valid_qc; 
   
   std::optional<quorum_certificate> get_best_qc() const { 
      // If pending_qc does not have a valid QC, return valid_qc.
      // Otherwise, extract the valid QC from *pending_qc.
      // Compare that to valid_qc to determine which is better: Strong beats Weak. Break tie with highest accumulated weight.
      // Return the better one.
   }
   
   uint64_t block_num() const { return block_header::num_from_id(id); }
};

```

In addition, in IF `pending_state._block_stage` will still contain the three stages: `building_block`, `assembled_block`, and `completed_block`.

1. `building_block`:

```c++
struct building_block {
   const block_id_type                              parent_id;                        // Comes from building_block_input::parent_id
   const block_timestamp_type                       timestamp;                        // Comes from building_block_input::timestamp
   const account_name                               producer;                         // Comes from building_block_input::producer
   const vector<digest_type>                        new_protocol_feature_activations; // Comes from building_block_input::new_protocol_feature_activations
   const protocol_feature_activation_set_ptr        prev_activated_protocol_features; // Cached: parent.bhs.activated_protocol_features
   const proposer_policy_ptr                        active_proposer_policy;           // Cached: parent.bhs.get_next_active_proposer_policy(timestamp)

   // Members below start from initial state and are mutated as the block is built.
   size_t                                     num_new_protocol_features_that_have_activated = 0;
   std::optional<proposer_policy>             new_proposer_policy;
   std::optional<finalizer_policy>            new_finalizer_policy;
   deque<transaction_metadata_ptr>            pending_trx_metas;
   deque<transaction_receipt>                 pending_trx_receipts;
   std::variant<checksum256_type, digests_t>  trx_mroot_or_receipt_digests;
   digests_t                                  action_receipt_digests;
};
```

```
struct building_block {
   pending_block_header_state                 _pending_block_header_state;       // IF: Remove from building_block. See below for replacements.
   std::optional<producer_authority_schedule> _new_pending_producer_schedule;    // IF: Replaced by new_proposal_policy.
   vector<digest_type>                        _new_protocol_feature_activations; // IF: Comes from building_block_input::new_protocol_feature_activations
   size_t                                     _num_new_protocol_features_that_have_activated = 0; // Stays only in building_block
   deque<transaction_metadata_ptr>            _pending_trx_metas;                // Moved from building_block to assembled_block
   deque<transaction_receipt>                 _pending_trx_receipts;             // Moved from building_block to the transactions in the constructed block
   std::variant<checksum256_type, digests_t>  _trx_mroot_or_receipt_digests;     // IF: Extract computed trx mroot to assembled_block_input::transaction_mroot 
   digests_t                                  _action_receipt_digests;           // IF: Extract computed action mroot to assembled_block_input::action_mroot
};
```

which is constructed from:

```c++
struct building_block_input {
   block_id_type                     parent_id;
   block_timestamp_type              timestamp;
   account_name                      producer;
   vector<digest_type>               new_protocol_feature_activations;
};
```

When done with building the block, from `building_block` we can extract:

```c++

struct block_header_state_input : public building_block_input {
   digest_type                       transaction_mroot;    // Comes from std::get<checksum256_type>(building_block::trx_mroot_or_receipt_digests)
   digest_type                       action_mroot;         // Compute root from  building_block::action_receipt_digests
   std::optional<proposer_policy>    new_proposer_policy;  // Comes from building_block::new_proposer_policy
   std::optional<finalizer_policy>   new_finalizer_policy; // Comes from building_block::new_finalizer_policy
   std::optional<quorum_certificate> qc;                   // Comes from traversing branch from parent and calling get_best_qc()
                                                           // assert(qc->block_num <= num_from_id(previous));
   // ... ?
};
```

which is the input needed to `block_header_state::next` to compute the new block header state.

2. `assembled_block`:


```c++
struct assembled_block {
   block_header_state                new_block_header_state;
   deque<transaction_metadata_ptr>   trx_metas;                 // Comes from building_block::pending_trx_metas
                                                                // Carried over to put into block_state (optimization for fork reorgs)
   deque<transaction_receipt>        trx_receipts;              // Comes from building_block::pending_trx_receipts
   std::optional<quorum_certificate> qc;                        // QC to add as block extension to new block               
};
```

which is constructed from `building_block` and `parent.bhs`.

3. `completed_block`:

```c++
struct completed_block {
   block_state_ptr  block_state;
};
```

which is constructed from `assembled_block` and a block header signature provider.

   