1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
//! Copyright (c) 2022 MASSA LABS <info@massa.net>
//! # General description
//!
//! This crate implements a final state that encompasses a final ledger and asynchronous message pool.
//! Nodes store only one copy of this final state which is very large
//! (the copy is attached to the output of the last executed final slot),
//! and apply speculative changes on it to deduce its value at a non-final slot
//! (see `massa-execution-exports` crate for more details).
//! Nodes joining the network need to bootstrap this state.
//!
//! # Architecture
//!
//! ## `final_state.rs`
//! Defines the `FinalState` that matches that represents the state of the node at
//! the latest executed final slot. It contains the final ledger and the asynchronous event pool.
//! It can be manipulated using `StateChanges` (see `state_changes.rs`).
//! The `FinalState` is bootstrapped using tooling available in bootstrap.rs
//!
//! ## `state_changes.rs`
//! Represents a list of changes the final state.
//! It can be modified, combined or applied to the final ledger.
//!
//! ## `executed_ops.rs`
//! Defines a structure to list and prune previously executed operations.
//! Used to detect operation reuse.
//!
//! ## `bootstrap.rs`
//! Provides serializable structures and tools for bootstrapping the final state.
//!
//! ## Test exports
//!
//! When the crate feature `test-exports` is enabled, tooling useful for test-exports purposes is exported.
//! See `test_exports/mod.rs` for details.
//!
//! # Network restart documentation
//!
//! ## Goals of the network restart
//! If the blockchain crashes (corrupted / attacked ledger, all nodes crash, etc.) and we want to keep the same main parameters of the network (same `GENESIS_TIMESTAMP`, same ledger, same final_state, etc.), then we can restart the network.
//!
//! **ONE** node should restart from a snapshot (which is just the RocksDB ledger, read as usual), and the other nodes should bootstrap from it.
//!
//! ## Command line
//!
//! ```sh
//! cargo run --release -- --restart-from-snapshot-at-period 200
//! ```
//!
//! Means: the node will restart from the ledger and final_state on disk (usual path in the config). Block production will start once the period given in args is reached (here, 200).
//!
//! ## Scenario
//!
//! 1. At period 40, the network crashes.
//! 2. We restart one node N0, at the time of period 80, with `cargo run --release -- --restart-from-snapshot-at-period 200`
//! 3. We start one other node N1, at the time of period 100, with `cargo run --release`
//! 4. The node N1 will bootstrap from N0. No blocks are produced yet.
//! 5. At the time of period 200, block production starts again.
//!
//! ## Additional notes
//!
//! ### Why is block production delayed?
//!
//! In order to give time to all nodes to rejoin the network after a crash and bootstrap. If we don't give them the time, their rolls would be sold because most stakers would have a lot of block miss.
//!
//! ### In sandbox
//!
//! Sandbox feature can be enabled. For instance, here is a test scenario:
//!
//! 1. Run the node as usual: `cargo run --release --features sandbox`
//! 2. Make transaction, buy rolls, etc.
//! 3. Shut down the node at slot S_0.
//! 4. Restart the network: `cargo run --release --features sandbox --restart-from-snapshot-at-period S_1`
//!
//! Here, the network will restart, and the network will start producing blocks again 10 seconds after launch.
//!
//! **/!\ This means that the genesis timestamp will be different between runs, but it should not matter in most cases.**
//!
//! ### Backups
//!
//! By default, the network restarts from the state associated with the last final slot before the shutdown.
//! However, we may sometimes want to recover from an earlier state (e.g. if an attacker stole 50% of all Massa, we want to restart with the state before the attack.
//! We use RocksDB checkpoint system to save the state at regular interval (see the `ledger_backup_periods_interval` in the `massa-node` config).
//! Backups for `Slot {period, thread}` are stored in `massa > massa-node > storage > ledger > rocks_db_backup > backup_[period]_[thread]`
//! Backups are hard links of the rocks_db, so the overhead of storing them should be minimal.
//! To recover from a backup, simply replace the contents of the rocks_db folder by the contents of the target backup folder.
#![warn(missing_docs)]
#![warn(unused_crate_dependencies)]
mod config;
mod controller_trait;
mod error;
mod final_state;
mod mapping_grpc;
mod state_changes;
pub use config::FinalStateConfig;
pub use controller_trait::FinalStateController;
pub use error::FinalStateError;
pub use final_state::FinalState;
use num as _;
pub use state_changes::{StateChanges, StateChangesDeserializer, StateChangesSerializer};
#[cfg(feature = "test-exports")]
pub use controller_trait::MockFinalStateController;
#[cfg(test)]
mod tests;
#[cfg(feature = "test-exports")]
pub mod test_exports;