massa_versioning/lib.rs
1// Copyright (c) 2022 MASSA LABS <info@massa.net>
2
3//! # General description
4//! MIP = Massa Improvement proposal (similar to Bitcoin Improvement Proposal - BIP or Ethereum - EIP)
5//!
6//! MipComponent -> A component that is going to be updated (e.g. Address v2)
7//! MIPInfo -> represent a MIP (name, versions, time ranges, components)
8//! MIPState -> Deployment state of a MIPInfo
9//! MIPStore -> A map of MIPInfo -> MipState
10//!
11//! Check massa-versioning/src/mips.rs file for a list of already defined MIPInfo.
12//!
13//! # Notes on MipInfo versions
14//!
15//! There is 2 different 'versions':
16//! * version == Network version -> This is the network version to announce and thus is stored in block header
17//! * component_version -> This is the version for the associated component (stored in a MIPInfo) and is used in VersioningFactory (e.g. KeyPair, Address, VM)
18//!
19//! # Notes on MipInfo timings and stats
20//!
21//! MipStore stats is in fact a voting system. Node runners can agree on a new version (a new list of MIPInfo) by
22//! updating their node software. If a majority of node runners do not update, the new version will be rejected.
23//!
24//! So in the execution module and after a block become final, we update the MipStore stats (in a blocking way).
25//! By updating the stats, we mean sending: (Slot timestamp, Option<(current: u32, announced: Option)>).
26//! Using the slot timestamp, ensure that the trigger (and the trigger timeout) is a consensus by all nodes
27//! (This means that the trigger and the trigger timeout are not timer based).
28//! In order to have all nodes in sync (because of node various delays), the state is set to active
29//! after an activation delay (duration is required to be > 1 cycle).
30//!
31//! About activation delay:
32//!
33//! At the slot when the activation happens, need to make sure that everyone knows it should happen,
34//! so we need to make sure that everyone has seen as final the slot that triggered the locked-in state,
35//! and the worst-case delay required for a slot to become final is the definition of a cycle.
36//!
37//! The activation delay counts how long we wait to activate after the vote threshold was reached,
38//! and we entered into locked-in state. During that delay, and after it, the number of blocks considered
39//! for the vote is not relevant. The only reason why we should consider a sufficient number of votes
40//! is to get a reasonable p-value on the vote itself:
41//!
42//! if we consider only 5 votes, the probability that a 30%-stake was selected to vote at least 50% of the times is 16%
43//! if we consider 1000 votes that probability falls to 5e-40.
44//!
45//! # Notes on MipState
46//!
47//! MipState has:
48//! * A state machine (stores the current state of deployment for a MipInfo)
49//! * Usual state changes: Defined -> Started -> LockedIn -> Active
50//! * A history (stores a list of `Advance` message that 'really' updated the state machine)
51//!
52//! An auto generated graph of the state machine can be found here:
53//! * dot -Tpng ./target/machine/componentstate.dot > ./target/machine/componentstate.png
54//! * xdg-open ./target/machine/componentstate.png
55//!
56//! History is there in order to:
57//! * Query the state at any time, so you can query MipStore and ask the best version at any time
58//! * Used a lot when merging 2 MipStore:
59//! * By replaying the history of the states of the received MipStore (bootstrap), we can safely update in the bootstrap process
60//! * + When we initialize a MipStore (at startup), this ensures that we have a time ranges & versions consistent list of MipInfo
61//! * For instance, this can avoid to have 2 MipInfo with the same name
62//!
63//! # Versioning Factory
64//!
65//! A Factory trait is there to ease the development of factory for Versioned component (e.g. address, block)
66//!
67//! All factories should query MIPStore in order to create a component with correct version; default implementation
68//! are provided by the trait to avoid re-writing these query functions.
69//!
70//! Unit tests in versioning_factory.rs shows a basic but realistic implementation of a AddressFactory (impl the Factory trait)
71//!
72//! # MipStore and Final state hash
73//!
74//! MipStore is written on disk after each block finalization. Writes are done in two separate column:
75//! * STATE_CF: 'Active' MIP info list
76//! * VERSIONING_CF: other MIP info + stats
77//!
78//! By writing only 'Active' MIP in state_cf column, we ensure that the final state hash remains the same between
79//! the versioning transition (e.g. User 1 has upgraded to network version 1 while User 2 has not yet upgraded)
80//!
81//! # Tests
82//!
83//! The massa-versioning module has a bunch of unit test in versioning.rs. Note that functional test,
84//! can be found in https://github.com/massalabs/massa-functional-tests/blob/main/tests_versioning.py.
85//! Note that those tests might not be up to date with the latest module code.
86
87// The MIP store errors are large by design. Boxing them would be an API break,
88// so the lint is silenced crate-wide rather than on each fallible function.
89#![allow(clippy::result_large_err)]
90
91pub mod address_factory;
92pub mod grpc_mapping;
93pub mod keypair_factory;
94pub mod mips;
95pub mod versioning;
96pub mod versioning_factory;
97pub mod versioning_ser_der;
98
99/// Test utils
100#[cfg(any(test, feature = "test-exports"))]
101pub mod test_helpers;