feat: document the structure of the Stacks node

This commit is contained in:
Jude Nelson
2022-10-10 20:38:14 -04:00
parent c3148e790c
commit b7b68790c5

View File

@@ -1,3 +1,141 @@
// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation
// Copyright (C) 2020 Stacks Open Internet Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/// Main body of code for the Stacks node and miner.
///
/// System schematic.
/// Legend:
/// |------| Thread
/// /------\ Shared memory
/// @------@ Database
/// .------. Code module
///
///
/// |------------------|
/// | RunLoop thread | [1,7]
/// | .----------. |--------------------------------------.
/// | .StacksNode. | |
/// |---.----------.---| |
/// [1] | | | [1] |
/// .----------------* | *---------------. |
/// | [3] | | |
/// V | V V
/// |----------------| | [9,10] |---------------| [11] |--------------------------|
/// .--- | Relayer thread | <-----------|-----------> | P2P Thread | <--- | ChainsCoordinator thread | <--.
/// | |----------------| V |---------------| |--------------------------| |
/// | | | /-------------\ [2,3] | | | | |
/// | [1] | *--------> / Globals \ <-----------*----|--------------* | [4] |
/// | | [2,3,7] /-------------\ | | |
/// | V V [5] V |
/// | |----------------| @--------------@ @------------------@ |
/// | | Miner thread | <------------------------------ @ Mempool DB @ @ Chainstate DBs @ |
/// | |----------------| [6] @--------------@ @------------------@ |
/// | ^ |
/// | [8] | |
/// *----------------------------------------------------------------------------------------* |
/// | [7] |
/// *--------------------------------------------------------------------------------------------------------*
///
/// [1] Spawns
/// [2] Synchronize unconfirmed state
/// [3] Enable/disable miner
/// [4] Processes block data
/// [5] Stores unconfirmed transactions
/// [6] Reads unconfirmed transactions
/// [7] Signals block arrival
/// [8] Store blocks and microblocks
/// [9] Pushes retrieved blocks and microblocks
/// [10] Broadcasts new blocks, microblocks, and transactions
/// [11] Notifies about new transaction attachment events
///
/// When the node is running, there are 4-5 active threads at once. They are:
///
/// * **RunLoop Thread**: This is the main thread, whose code body lives in src/run_loop/neon.rs.
/// This thread is responsible for:
/// * Bootup
/// * Running the burnchain indexer
/// * Notifying the ChainsCoordinator thread when there are new burnchain blocks to process
///
/// * **Relayer Thread**: This is the thread that stores and relays blocks and microblocks. Both
/// it and the ChainsCoordinator thread are very I/O-heavy threads, and care has been taken to
/// ensure that neither one attempts to acquire a write-lock in the underlying databases.
/// Specifically, this thread directs the ChainsCoordinator thread when to process new Stacks
/// blocks, and it directs the miner thread (if running) to stop when either it or the
/// ChainsCoordinator thread needs to acquire the write-lock.
/// This thread is responsible for:
/// * Receiving new blocks and microblocks from the P2P thread via a shared channel
/// * (Sychronously) requesting the CoordinatorThread to process newly-stored Stacks blocks and
/// microblocks
/// * Building up the node's unconfirmed microblock stream state, and sharing it with the P2P
/// thread so it can answer queries about the unconfirmed microblock chain
/// * Pushing newly-discovered blocks and microblocks to the P2P thread for broadcast
/// * Registering the VRF public key for the miner
/// * Spawning the block and microblock miner threads, and stopping them if their continued
/// execution would inhibit block or microblock storage or processing.
/// * Submitting the burnchain operation to commit to a freshly-mined block
///
/// * **Miner thread**: This is the thread that actually produces new blocks and microblocks. It
/// is spawned only by the Relayer thread to carry out mining activity when the underlying
/// chainstate is not needed by either the Relayer or ChainsCoordinator threeads.
/// This thread does the following:
/// * Walk the mempool DB to build a new block or microblock
/// * Return the block or microblock to the Relayer thread
///
/// * **P2P Thread**: This is the thread that communicates with the rest of the p2p network, and
/// handles RPC requests. It is meant to do as little storage-write I/O as possible to avoid lock
/// contention with the Miner, Relayer, and ChainsCoordinator threads. In particular, it forwards
/// data it receives from the p2p thread to the Relayer thread for I/O-bound processing. At the
/// time of this writing, it still requires holding a write-lock to handle some RPC request, but
/// future work will remove this so that this thread's execution will not interfere with the
/// others. This is the only thread that does socket I/O.
/// This thread runs the PeerNetwork state machines, which include the following:
/// * Learning the node's public IP address
/// * Discovering neighbor nodes
/// * Forwarding newly-discovered blocks, microblocks, and transactions from the Relayer thread to
/// other neighbors
/// * Synchronizing block and microblock inventory state with other neighbors
/// * Downloading blocks and microblocks, and passing them to the Relayer for storage and processing
/// * Downloading transaction attachments as their hashes are discovered during block processing
/// * Synchronizing the local mempool database with other neighbors
/// (notifications for new attachments come from a shared channel in the ChainsCoordinator thread)
/// * Handling HTTP requests
///
/// * **ChainsCoordinator Thread**: This thread process sortitions and Stacks blocks and
/// microblocks, and handles PoX reorgs should they occur (this mainly happens in boot-up). It,
/// like the Relayer thread, is a very I/O-heavy thread, and it will hold a write-lock on the
/// chainstate DBs while it works. Its actions are controlled by a CoordinatorComms structure in
/// the Globals shared state, which the Relayer thread and RunLoop thread both drive (the former
/// drives Stacks blocks processing, the latter sortitions).
/// This thread is responsible for:
/// * Responding to requests from other threads to process sortitions
/// * Responding to requests from other threads to process Stacks blocks and microblocks
/// * Processing PoX chain reorgs, should they ever happen
/// * Detecting attachment creation events, and informing the P2P thread of them so it can go
/// and download them
///
/// In addition to the mempool and chainstate databases, these threads share access to a Globals
/// singleton that contains soft state shared between threads. Mainly, the Globals struct is meant
/// to store inter-thread shared singleton communication media all in one convenient struct. Each
/// thread has a handle to the struct's shared state handles. Global state includes:
/// * The global flag as to whether or not the miner thread can be running
/// * The global shutdown flag that, when set, causes all threads to terminate
/// * Sender channel endpoints that can be shared between threads
/// * Metrics about the node's behavior (e.g. number of blocks processed, etc.)
///
/// This file may be refactored in the future into a full-fledged module.
use std::cmp;
use std::collections::HashMap;
use std::collections::{HashSet, VecDeque};