use fbas_analyzer::*;
use std::collections::HashMap;
use std::path::Path;
use sha3::{Digest, Sha3_256};
pub fn main() {
let nodes_json = Path::new("test_data/stellarbeat_nodes_2019-09-17.json");
let fbas = Fbas::from_json_file(nodes_json);
let inactive_nodes = FilteredNodes::from_json_file(nodes_json, |v| v["active"] == false);
let fbas = fbas.without_nodes_pretty(&inactive_nodes.into_pretty_vec());
let fbas = fbas.to_core();
let fbas = fbas.to_standard_form();
let fbas_hash = hex::encode(Sha3_256::digest(&fbas.to_json_string().into_bytes()));
println!(
"SHA3 hash of FBAS in standard form (when converted to JSON): {}",
fbas_hash
);
let mut results_cache: HashMap<Fbas, CustomResultsStruct> = HashMap::new();
let analysis_results = if let Some(cached_results) = results_cache.get(&fbas) {
cached_results.clone()
} else {
let new_results = do_analysis(&fbas);
results_cache.insert(fbas.clone(), new_results.clone());
new_results
};
let mbs: NodeIdSetVecResult = analysis_results.minimal_blocking_sets;
let mbs_pretty: Vec<Vec<String>> = mbs.clone().into_pretty_vec_vec(&fbas, None);
println!("Example smallest minimal blocking set: {:?}", mbs_pretty[0]);
let organizations = Groupings::organizations_from_json_file(
Path::new("test_data/stellarbeat_organizations_2019-09-17.json"),
&fbas, );
let mbs_by_orgs: NodeIdSetVecResult = mbs.merged_by_group(&organizations).minimal_sets();
println!(
"In the worst case, {} nodes across {} organizations are enough to compromise liveness.",
mbs.min(),
mbs_by_orgs.min()
);
let failing_nodes = vec![
String::from("GCGB2S2KGYARPVIA37HYZXVRM2YZUEXA6S33ZU5BUDC6THSB62LZSTYH"),
String::from("GABMKJM6I25XI4K7U6XWMULOUQIQ27BCTMLS6BYYSOWKTBUXVRJSXHYQ"),
];
let remaining_mbs = mbs
.without_nodes_pretty(&failing_nodes, &fbas, None)
.minimal_sets();
println!(
"After removing failing nodes, {} more node failures can cause a loss in liveness.",
remaining_mbs.min()
);
let evil_nodes = vec![0, 1, 2, 3, 4, 5, 6]; let remaining_mss = analysis_results
.minimal_splitting_sets
.without_nodes(&evil_nodes)
.minimal_sets();
if remaining_mss.contains_empty_set() {
println!("The FBAS lacks quorum intersection despite evil nodes!");
} else {
println!(
"{} more nodes need to become evil for safety to become endangered.",
remaining_mss.min()
);
}
}
fn do_analysis(fbas: &Fbas) -> CustomResultsStruct {
let analysis = Analysis::new(fbas);
CustomResultsStruct {
minimal_blocking_sets: analysis.minimal_blocking_sets(),
minimal_splitting_sets: analysis.minimal_splitting_sets(),
top_tier: analysis.top_tier(),
has_quorum_intersection: analysis.has_quorum_intersection(),
}
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
struct CustomResultsStruct {
minimal_blocking_sets: NodeIdSetVecResult,
minimal_splitting_sets: NodeIdSetVecResult,
top_tier: NodeIdSetResult,
has_quorum_intersection: bool,
}