Introduction
We will describe in this document the global architecture of a Massa Node, from the ground up, and introduce relevant definitions and concepts.
The goal of the Massa network is to build a consensus between nodes to gather and order blocks that contain ordered lists of operations. An operation ultimate purpose once executed is to act as transitions for the global network state, called the ledger.
Operations are produced by external clients and sent to the Massa network via a node. Some operations are containing code to be run as smart contracts, enabling complex programmatic modifications of the ledger. Nodes will gather all the pending operations and group them to produce blocks. Each block contains a finite set of operations, limited by the fact that each block has a limited amount of space available to store operations. Traditional blockchains will then typically link blocks one after the other (including a hash of the previous block in the block header), to materialize their temporal ordering. However, unlike traditional blockchains, Massa blocks are not simply chained one after the other, but organized into a more complex spatio-temporal structure, which allows for parallelization and increased performances.
Instead of one chain, there are several threads (T=32) of chains running in parallel, with blocks equally spread on each thread over time, and stored inside slots that are spaced at fixed time intervals:
The time between two slots located on the same thread is called a period and lasts 16s (conventionally called \(t_0\)). Corresponding slots in threads are slightly shifted in time relative to one another, by one period divided by the number of threads, which is 16s/32 = 0.5s, so that a period contains exactly 32 slots equally spaced over the 32 threads. A cycle is defined as the succession of 128 periods and so lasts a bit more than 34min. Periods are numbered by increments of one, so can be used together with a thread number to uniquely identify a block slot. Period 0 is the genesis and contains genesis blocks with no parents.
The job of the Massa nodes network is to essentially collectively fill up slots with valid blocks. To do so, at each interval of 0.5s, a specific node in the network is elected to be allowed to create a block (more about the selection process below, and the proof of stake sybil resistance mechanism), and will be rewarded if it creates a valid block in time. It is also possible that a node misses its opportunity to create the block, in which case the slot will remain empty (this is called a block miss).
In traditional blockchains, blocks are simply referencing their unique parent, forming a chain. In the case of Massa, each block is referencing one parent block in each thread (so, 32 parents). Here is an example illustrated with one particular block:
Let’s introduce some relevant definitions and concepts generally necessary to understand how the Massa network operates. We will then explain the node architecture and how the whole system works.
Address
Each account in Massa has a public and private key associated with it. This is how messages can be signed and identity enforced.
The address of an account is simply the hash of its public key.
Ledger
The ledger is a map that stores a global mapping between addresses and information related to these addresses. It is replicated in each node and the consensus building mechanism ensures that agreement on what operations have been finalized (and in what order) will be reached over the whole network. The ledger is the state of the Massa network, and fundamentally operations (see below) are requests to modify the ledger.
The information stored in the ledger with each address is the following:
Ledger information associated with each address |
|
|
The amount of Massa coins owned by the address |
|
When the address references a smart contract, this is the compiled code
|
|
A key/value map that can store any persistent data related to a smart
|
Smart Contract
Smart contracts are a piece of code that can be run inside the Massa virtual machine and which can modify the ledger, accept incoming requests through a public interface (via smart contract operations). One particularity of Massa smart contracts compared to other blockchain smart contracts is their ability to wake up by themselves independently of an exterior request on their interface. This allows more autonomy and less dependency on external centralized services.
Smart contracts are currently written in assemblyscript, a stricter derivation from typescript, which is itself a type-safe version of javascript. AssemblyScript compiles to web assembly bytecode (wasm). Massa nodes Execution Module runs such bytecode. Smart contracts have access to their own datastore, so they can modify the ledger.
Operation
Fundamentally, the point of the Massa network is to gather, order and execute operations, recorded inside blocks that are located in slots. There are three types of operations: transactions, roll operations, and smart contract code execution. The general structure of an operation is the following, and the different types of operations differ by their payload:
Operation header |
|
|
The public key of the operation creator (32 bytes) |
|
Period after which the operation is expired (u64 varint) |
|
The amount of fees the creator is willing to pay (u64 varint) |
|
The type of operation (from 0 to 4: transaction, rollbuy,
|
|
The content of the operation (see below) |
|
signature of all the above with the private key of
|
Transactions operations
Transactions are operations that move native Massa coins between addresses. Here is the corresponding payload:
Transaction payload |
|
|
The amount of coins to transfer (u64 varint) |
|
The address of the recipient (32 bytes) |
Buy/Sell Rolls operations
Rolls are staking tokens that participants can buy or sell with native coins (more about staking below). This is done via special operations, with a simple payload:
Roll buy/sell payload |
|
|
The number of rolls to buy or to sell (u64 varint) |
Smart Contract operations
Smart Contracts are pieces of code that can be run inside the Massa virtual machine. There are two ways of calling for the execution of code:
Direct execution of bytecode
In this case, the code is provided in the operation payload and executed directly:
Execute SC payload |
|
|
The maximum gas spendable for this operation (u64 varint) |
|
The length of the bytecode field (u64 varint) |
|
The bytecode to run (in the context of the caller address) |
|
The number of the datastore keys (u64 varint), each record
|
list of datastore records |
Concatenation of |
Smart Contract function call
Here, the code is indirectly called via the call to an existing smart contract function, together with the required parameters:
Call SC |
|
|
The maximum gas spendable for this operation (u64 varint) |
|
The coins transferred in the call (u64 varint) |
|
The address of the targeted smart contract (32 bytes) |
|
The length of the name of the function that is called (u8) |
|
The name of the function that is called (utf8) |
|
The number of parameters of the function call (u64 varint) |
|
The parameters of the function call |
Block
A block is a data structure built by nodes and its function it to aggregate several operations. As explained above, for each new slot that becomes active, a particular node in the network is elected in a deterministic way with the task of creating the block that will be stored in that slot (more about this in the description of the Selector Module below). A block from a given thread can only contain operations originating from a creator_public_key whose hash’s five first bits designate the corresponding thread, thus implicitly avoiding collisions in operations integrated into parallel threads.
The content of a block is as follows:
Block header |
|
|
A description of the block slot, defined by a couple (period, thread) that
|
|
The public key of the block creator (32 bytes) |
|
A list of the 32 parents of the block, one parent per thread (parent blocks are
|
|
A list of the 16 endorsements for the block (more about endorsements below) |
|
A hash of all the operations included in the block (=hash of the block body below) |
|
signature of all the above with the private key of the block creator |
Block body |
|
|
The list of all operations included in the block |
Endorsements are optional inclusion in the block, but their inclusion is incentivized for block creators. They are validations of the fact that the parent block on the thread of the block is the best parent that could have been chosen, done by other nodes that have also been deterministically selected via the proof of stake probability distribution (see below). A comprehensive description of endorsements can be found here, so we will not go further into details in the context of this introduction.