Closed aesedepece closed 5 years ago
After discussing it with @Tommytrg, we found out that it is not possible to define arrays with fixed lengths with Flatbuffers. This affects data structures such as hashes, which, in our case, are limited to 256 bits.
Therefore, we thought about the following workarounds.
Option 1: less safe as the hash is not limited to 256 bits.
table Hash {
bytes: [ubyte];
}
Option 2: more safe but more verbose
table Hash {
b0: uint64;
b1: uint64;
b2: uint64;
b3: uint64;
}
Other options: even more verbose
Btw, there was an issue in the Flatbuffers project about that. Unfortunately, it was closed without merging any solution.
@mariocao I kind of prefer option 1. We can just limit how many bytes we read from hashes when going from flatbuffer-generated types to our own native types.
Context
Inventory exchange protocol
The inventory exchange protocol describes the interaction between nodes in order to synchronize themselves with the network and reestablish the full blockchain (in terms of blocks and transactions).
Inventory exchanges envision 2 main scenarios:
Block Download, for nodes in need of synchronizing their blockchains by requesting and downloading blocks.
Inventory Broadcasting, for nodes willing to broadcast transactional information, such as blocks and transactions.
Block Download
Block Download is performed by nodes that need to catch up with other nodes by downloading missing blocks in order to reconstruct their blockchains. For example, this is the case of nodes connecting to the blockchain for the first time or after a significant amount of downtime.
Starting from the block #0 (the hardcoded genesis block), the nodes need to validate all blocks up to the current tip of the blockchain. Therefore, in case of missing blocks, a local node will initiate the following process of synchronization with its outbound peers:
The local node will have already exchanged
version
messages with its remote outbound peers. Thoseversion
messages contain the last epoch known to others peers, i.e. the local peer can already compare how many blocks they each have and identify how many are missing.The local node will send a
get_blocks
message to all its outbound nodes (after successful handshake protocol). These messages contain the hash of the top block of the local blockchain.Remote peers will reply by sending another
get_blocks
message containing the hash of their top block of their respective blockchains.The peer with the longest blockchain will identify which blocks are required by the other peer in order to allow it to synchronize to its blockchain. The peer will select up to the first consecutive 500 blocks and it will transmit their hashes using an
inv
(inventory) message.After identifying which blocks are missing (it may already have some of them), the node may request them by using a
get_data
message, containing the hashes of the needed blocks. This message will help the node to catch up with the current full blockchain.After receiving the
get_data
message, the peer sends the requested blocks individually by usingblock
messages. The following diagram depicts the previously described process under the assumption that the peer with the longest blockchain isNodeB
(step 4).Inventory Broadcasting
Similarly to the previously described process of synchronization, any node may contribute to the synchronization of their outbound peers by advertising inventory objects such as blocks and transactions. Inventory broadcasting is also used in case a node creates transactions or mine blocks.
The inventory broadcasting can be described as the following sequence of steps:
A remote node broadcasts its inventory by sending an
inv
message, containing all the hashes of the advertised inventory objects.After receiving an
inv
message and filtering the inventory objects that may be missing in the local blockchain, the local node sends aget_data
message with the hashes of the needed objects.The remote note receives the
get_data
message and sends ablock
ortx
message per requested inventory object (identified by a hash).The following diagram depicts the previous step under the assumption that the local node (
NodeA
) sends aget_data
message requesting 3 blocks and 2 transactions.block
messageThe
block
message is used to transmit a single serialized block as a response to aget_data
message.The
block
message consists of a message header with theBLOCK
command and a payload formatted as follows:header
block_header
txn_count
u32
txns
tx[]
Actionables
block
as aCommand
in the FlatBuffers schema.block
as a native data structureblock
and its builder as aWitnetMessage
inwitnet_data_structures::types::Message
.