Skip to content
This repository was archived by the owner on Jul 20, 2021. It is now read-only.
This repository was archived by the owner on Jul 20, 2021. It is now read-only.

review block structure #628

@GlenDC

Description

@GlenDC

Since the release of the first Rivine-based chain, the Threefold Chain (tfchain in short) the block structure of such chains can be seen as a structure with the following properties in the order as defined:

  • ParentID
  • Timestamp
  • BlockStakeOutputIndexes
  • MinerPayouts
  • Transactions

The BlockStakeOutputIndexes is defined by the following structure:

// BlockStakeOutputIndexes groups the block height, the transaction index and the output index to uniquely identify a blockstake output.
// These indexes and the value are required for the POBS protocol.
BlockStakeOutputIndexes struct {
	 BlockHeight      BlockHeight
	 TransactionIndex uint64
	 OutputIndex      uint64
}

Each miner payout can be seen as a pair of a Value and an UnlockHash (the address which received the paired Value.

For the sake of this issue each transaction can be seen as an opaque binary object with the first byte indicating its version. How the object is to be decoded is defined by the chain, but not relevant for this issue.

Compared to other chains we make no difference between Header and Body. However given that you could see the first 3 properties as the header, with the next 2 being the body you could go from a conceptual concept to an implemented one. It would require at the very least one adaptation:

  • We do not have a property to uniquely and safely identify the transactions of the body. Other chains use often a MerkeRoot hash for this. Nothing prevents us from adding this property once we go for a header-body separation;

Besides this we might also want the following adaptations:

  • We could replace the BlockStakeOutputIndexes property with an opaque binary object, which could be called the settlement or however you wish to call it. The decoding of which depends on a version, either unique to this object or coupled directly to a block version as proposed in the next bullet point;
  • We currently do not have a block version, making it a lot more difficult to upgrade the block structure (again) in the future.

On top of that some chains also store a Nonce in the header. At the moment I am however not sure why this would be desired, given a Merkle Root hash together with the other properties (e.g. the parent ID) should be enough to make the header unique. If not, I would think you have an issues with your cryptographic primitives used. I might however mis something here.

In Memory we do already have a BlockHeader structure defined as follows:

// A BlockHeader, when encoded, is an 96-byte constant size field
// containing enough information to do headers-first block downloading.
// Hashing the header results in the block ID.
BlockHeader struct {
	 ParentID
	 BlockStakeOutputIndexes
	 Timestamp
	 MerkleRoot
}

This header is derived from the block structure listed earlier. As we already calculate the MerkleRoot based on the transactions, it wouldn't be hard to add it to an actually implementation used block header. Again I would propose to turn the BlockStakeOutputIndexes object into an opaque binary object linked to a version, so we can change the consensus algorithm when needed without hardcoding all these things in such a transparent manner. Further we again miss the version here.

The header is currently already transferred separately from the actual block between peers,
to allow the receiving peer to decide whether or not the actual block is desired.
It it is thus not unreasonable to go the extra mile here and also allow clients to actually
download headers-only by default, and downloading actual blocks only when desired.
That mile is however a long one.

Thus so far a proposal for new structures would be as follows:

type (
    BlockHeader struct {
        Version     byte
        ParentID    BlockID
        Settlement  []byte // find a better name
        Timestamp   Timestamp
        MerkleRoot  crypto.Hash
    }

    // Some chains also add a magic No in the front of a block when encoding,
    // to make sure during the decoding one can know for sure it is a block,
    // irrelevant on its actual version or content. Not sure about
    // if we really want this though.
    Block struct {
        Header BlockHeader
        // it is probably even better to remove the miner payouts property,
        // and turn them into a transaction (or transactions).
        MinerPayouts []MinerPayout
        Transactions []Transaction
    }
)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions