1use super::*;
2
3impl Fbas {
4 pub fn assume_crash_faulty(&mut self, nodes: &NodeIdSet) {
8 for node_id in nodes.iter() {
9 self.nodes[node_id].quorum_set = QuorumSet::new_unsatisfiable();
10 }
11 }
12 pub fn assume_split_faulty(&mut self, nodes: &NodeIdSet) {
17 for node_id in nodes.iter() {
18 self.nodes[node_id].quorum_set = QuorumSet::new_unsatisfiable();
19 }
20 for node in self.nodes.iter_mut() {
21 node.assume_split_faulty(nodes);
22 }
23 }
24}
25impl Node {
26 pub fn assume_split_faulty(&mut self, nodes: &NodeIdSet) {
28 self.quorum_set.assume_split_faulty(nodes);
29 }
30}
31impl QuorumSet {
32 pub fn assume_split_faulty(&mut self, nodes: &NodeIdSet) {
34 let n_validators_before = self.validators.len();
35 self.validators = self
36 .validators
37 .iter()
38 .copied()
39 .filter(|&x| !nodes.contains(x))
40 .collect();
41 let n_validator_deletions = n_validators_before - self.validators.len();
42
43 for iqs in self.inner_quorum_sets.iter_mut() {
44 iqs.assume_split_faulty(nodes);
45 }
46 self.threshold = self.threshold.saturating_sub(n_validator_deletions);
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn assume_crash_faulty_makes_nodes_unsatisfiable() {
56 let mut fbas = Fbas::from_json_str(
57 r#"[
58 {
59 "publicKey": "n0",
60 "quorumSet": { "threshold": 2, "validators": ["n0", "n1"], "innerQuorumSets": [] }
61 },
62 {
63 "publicKey": "n1",
64 "quorumSet": { "threshold": 2, "validators": ["n0", "n1"], "innerQuorumSets": [] }
65 }
66 ]"#,
67 );
68 fbas.assume_crash_faulty(&bitset! {1});
69 let actual = fbas;
70 let expected = Fbas::from_json_str(
71 r#"[
72 {
73 "publicKey": "n0",
74 "quorumSet": { "threshold": 2, "validators": ["n0", "n1"], "innerQuorumSets": [] }
75 },
76 {
77 "publicKey": "n1",
78 "quorumSet": { "threshold": 1, "validators": [], "innerQuorumSets": [] }
79 }
80 ]"#,
81 );
82 assert_eq!(expected, actual);
83 }
84
85 #[test]
86 fn assume_split_faulty_makes_nodes_unsatisfiable() {
87 let mut fbas = Fbas::from_json_str(
88 r#"[
89 {
90 "publicKey": "n0",
91 "quorumSet": { "threshold": 2, "validators": ["n0", "n1"], "innerQuorumSets": [] }
92 },
93 {
94 "publicKey": "n1",
95 "quorumSet": { "threshold": 2, "validators": ["n0", "n1"], "innerQuorumSets": [] }
96 }
97 ]"#,
98 );
99 fbas.assume_split_faulty(&bitset! {0, 1});
100 assert!(!fbas.nodes[0].quorum_set.is_satisfiable());
101 assert!(!fbas.nodes[1].quorum_set.is_satisfiable());
102 }
103
104 #[test]
105 fn assume_split_faulty_removes_from_quorum_sets() {
106 let mut fbas = Fbas::from_json_str(
107 r#"[
108 {
109 "publicKey": "n0",
110 "quorumSet": { "threshold": 2, "validators": ["n0", "n1"], "innerQuorumSets": [] }
111 },
112 {
113 "publicKey": "n1",
114 "quorumSet": { "threshold": 2, "validators": ["n0", "n1"], "innerQuorumSets": [] }
115 }
116 ]"#,
117 );
118 fbas.assume_split_faulty(&bitset! {1});
119 let actual = fbas.nodes[0].quorum_set.clone();
120 let expected = QuorumSet::new(vec![0], vec![], 1);
121 assert_eq!(expected, actual);
122 }
123
124 #[test]
125 fn assume_split_faulty_works_on_a_more_complex_fbas() {
126 let mut fbas = Fbas::from_json_str(
127 r#"[
128 {
129 "publicKey": "n0",
130 "quorumSet": { "threshold": 3, "validators": ["n0", "n1", "n2"], "innerQuorumSets": [] }
131 },
132 {
133 "publicKey": "n1",
134 "quorumSet": { "threshold": 3, "validators": ["n0", "n1"], "innerQuorumSets": [
135 { "threshold": 2, "validators": ["n2", "n3"] }
136 ]}
137 },
138 {
139 "publicKey": "n2",
140 "quorumSet": { "threshold": 4, "validators": ["n0", "n1", "n2", "n3"], "innerQuorumSets": [] }
141 },
142 {
143 "publicKey": "n3",
144 "quorumSet": { "threshold": 4, "validators": ["n1", "n2", "n3", "n4"], "innerQuorumSets": [] }
145 }
146 ]"#,
147 );
148 fbas.assume_split_faulty(&bitset! {0, 2});
149 let actual = fbas;
150 let expected = Fbas::from_json_str(
151 r#"[
152 {
153 "publicKey": "n0"
154 },
155 {
156 "publicKey": "n1",
157 "quorumSet": { "threshold": 2, "validators": ["n1"], "innerQuorumSets": [
158 { "threshold": 1, "validators": ["n3"] }
159 ]}
160 },
161 {
162 "publicKey": "n2"
163 },
164 {
165 "publicKey": "n3",
166 "quorumSet": { "threshold": 3, "validators": ["n1", "n3", "n4"], "innerQuorumSets": [] }
167 }
168 ]"#,
169 );
170 assert_eq!(expected, actual);
171 }
172}