monad-viz: A Visual Representation of MonadBFT

Byzantine Fault Tolerant (BFT) consensus algorithms are the cornerstone of blockchain technology, but it can be difficult to build intuition around their behavior.  They result in complex systems with many nodes, links, and messages in various states of authentication and processing. A robust consensus mechanism must be tolerant of a variety of unexpected networking conditions that lead to dropped or reordered messages.

In the process of building MonadBFT, our team at Category Labs recognized the need for a simulation environment that could test all of these corner cases. That's why we built mock-swarm, a simulation environment, and monad-debugger, which includes a visualization tool internally called monad-viz.

The simulation infrastructure provides multiple benefits:

  • It allowed us to implement a variety of tests, covering many corner cases of the algorithm by simulating inputs that are unlikely to happen in real world testing.
  • By using virtualized time, it enables simulation of thousands of consensus rounds in just a few seconds.

The simulation also helps build intuition about the algorithm. monad-viz displays the steps of the simulation, highlighting the state of validator nodes and the consensus messages being exchanged. By perturbing the latencies between nodes (even just randomly), we can observe how the alternate code paths (both “happy” and “unhappy”) work.

Below, you’ll find the visualization from one run of the simulation. The actual MonadBFT code (available at https://github.com/category-labs/monad-bft/) is being executed in your browser to display the visualization. Move the slider forward and backward to run the simulation forward and backward in time.

The complete source code for this visualization is available here. If you would like to customize your own simulated network, you can adjust simulated network parameters in the simulation_make function found here.

A couple places to start include the state config and the vector specifying the network topology (connectivity and latency between nodes).


 // Network state configuration
 let state_configs = make_state_configs::(
     4, // num_nodes
     ValidatorSetFactory::default,
     SimpleRoundRobin::default,
     || MockValidator,
     || PassthruBlockPolicy,
     || InMemoryStateInner::genesis(Balance::MAX, SeqNum(4)),
     SeqNum(4),                           // execution_delay
     Duration::from_millis(50),           // delta
     MockChainConfig::new(&CHAIN_PARAMS), // chain config
     SeqNum(2000),                        // val_set_update_interval
     Round(50),                           // epoch_start_delay
     SeqNum(100),                         // state_sync_threshold
 );

 // Simulation sequence
 vec![
    GenericTransformer::Latency(LatencyTransformer::new(
        Duration::from_millis(10),
    )),
    GenericTransformer::RandLatency(RandLatencyTransformer::new(
        0,
        Duration::from_millis(40),
    )),
    GenericTransformer::Periodic(PeriodicTransformer::new(
        Duration::from_millis(1_000),
        Duration::MAX,
    )),
    GenericTransformer::Drop(
        DropTransformer::new().drop_only_from(*all_peers.last().unwrap()),
    ),
 ],