This script will simply do these,
- set up and compose the 2 quorums automatically with given numbers, and the
commons
(shared nodes between 2 quorums) is also considered. - by the possible number of faulty nodes, checking and calculating these factors,
safety
liveness
- minimum
threshold
I want to get the possible cases and by increasing the number of faulty nodes, how each factors are changed.
In this script, node will be limited to 'validator', which can participate to consensus process of network.
The paper, The Stellar Consensus Protocol by David Mazie`res, explains like this,
Definition (quorum). A set of nodes
𝑈 ⊆ 𝐕
in FBAS⟨𝐕,𝐐⟩
is a quorum iff𝑈 ≠ ∅
and𝑈
contains a slice for each member — i.e.,∀𝑣 ∈ 𝑈
,∃𝑞 ∈ 𝐐(𝑣)
such that𝑞 ⊆ 𝑈
.
A quorum is a set of nodes sufficient to reach agreement.
quorum slice
is the sufficient set of nodes for each node, but quorum
is for the network-level.
According to the official documentation of stellar.org,
For example, consider two nodes that respectively reference the sets Set1 and Set2 composed of some common nodes and some other nodes.
Set1 = Common + extra1, Set2 = Common + extra2
Simply to say, commons
is the shared nodes between quorums.
3.3. Safety and liveness
Definition (safety). A set of nodes in an FBAS enjoy safety if no two of them ever externalize different values for the same slot.
So we can simply get the number of nodes for satisfying safety
.
<commons> - 1 >= f
f
is the number of faulty nodes, that is, safety nodes will be greater than faulty nodes.
3.3. Safety and liveness
Definition (liveness). A node in an FBAS enjoys liveness if it can externalize new values without the participation of any failed (including ill-behaved) nodes.
liveness
also can be calculated,
<nodes in one quorum> - <commons> >= f
threshold
is the lowest number to reach agreement in one quorum.
$ pip install pygments termcolor
$ python check-quorums-are-stable.py -h
usage: check-quorums-are-stable.py [-h] qa qb commons
Checking the stability of 2 quorums
positional arguments:
qa number of nodes in quorum, `a`
qb number of nodes in quorum, `b`
commons number of commons(shared nodes) between quorums, `a` and `b`
optional arguments:
-h, --help show this help message and exit
$ python check-quorums-are-stable.py 5 4 2
- quorums ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
a: {"count": 5, "quorum": ["v00", "v01", "v02", "v03", "v04"]}
b: {"count": 4, "quorum": ["v03", "v04", "v05", "v06"]}
commons: {"commons": ["v03", "v04"], "count": 2}
- functions --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
fault tolerance: {"f": "<number of nodes> >= 3f + 1"}
max safety: {"f": "<commons> - 1 >= f"}
liveness: {"f": "<size of nodes> - <commons> >= f"}
threshold: {"f": "<size of not commons> + <safety> / <size of nodes>: https://www.stellar.org/developers/stellar-core/software/admin.html#quorum-intersection"}
or threshold: {"f": "1 - <commons p> + (<safety p> * <common p>)"}
- etc --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
max fault: {"fault": 1}
max safety: {"safety": 1}
============================================================================================================================================================================================================================================
- FAULT: 0 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
max_safety(all): {"FAULT": 0, "commons": 2, "max_safety": 1}
* safe_nodes: 2
safety(all): {"FAULT": 0, "is_safety": true, "max_safety": 1, "safe_nodes": 2, "safety": 1}
min threshold(a): {"FAULT": 0, "QUORUM": "a", "commons": 2, "commons_p": 0.4, "max_safety": 1, "min_threshold": 1.0, "safe_nodes": 2, "safety_p": 1.0}
min threshold(b): {"FAULT": 0, "QUORUM": "b", "commons": 2, "commons_p": 0.5, "max_safety": 1, "min_threshold": 1.0, "safe_nodes": 2, "safety_p": 1.0}
* safe_nodes: 1
safety(all): {"FAULT": 0, "is_safety": true, "max_safety": 1, "safe_nodes": 1, "safety": 0}
min threshold(a): {"FAULT": 0, "QUORUM": "a", "commons": 2, "commons_p": 0.4, "max_safety": 1, "min_threshold": 0.8, "safe_nodes": 1, "safety_p": 0.5}
min threshold(b): {"FAULT": 0, "QUORUM": "b", "commons": 2, "commons_p": 0.5, "max_safety": 1, "min_threshold": 0.75, "safe_nodes": 1, "safety_p": 0.5}
............................................................................................................................................................................................................................................
liveness(a): {"FAULT": 0, "QUORUM": "a", "commons": 2, "has_liveness": true, "is_safety": true, "max_safety": 1, "size_of_nodes": 5}
liveness(b): {"FAULT": 0, "QUORUM": "b", "commons": 2, "has_liveness": true, "is_safety": true, "max_safety": 1, "size_of_nodes": 4}
- FAULT: 1 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
max_safety(all): {"FAULT": 1, "commons": 2, "max_safety": 1}
* safe_nodes: 2
safety(all): {"FAULT": 1, "is_safety": true, "max_safety": 1, "safe_nodes": 2, "safety": 1}
min threshold(a): {"FAULT": 1, "QUORUM": "a", "commons": 2, "commons_p": 0.4, "max_safety": 1, "min_threshold": 0.8, "safe_nodes": 1, "safety_p": 0.5}
min threshold(b): {"FAULT": 1, "QUORUM": "b", "commons": 2, "commons_p": 0.5, "max_safety": 1, "min_threshold": 0.75, "safe_nodes": 1, "safety_p": 0.5}
* safe_nodes: 1
safety(all): {"FAULT": 1, "is_safety": false, "max_safety": 1, "safe_nodes": 1, "safety": 0}
............................................................................................................................................................................................................................................
liveness(a): {"FAULT": 1, "QUORUM": "a", "commons": 2, "has_liveness": true, "is_safety": false, "max_safety": 1, "size_of_nodes": 5}
liveness(b): {"FAULT": 1, "QUORUM": "b", "commons": 2, "has_liveness": true, "is_safety": false, "max_safety": 1, "size_of_nodes": 4}
- FAULT: 2 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
max_safety(all): {"FAULT": 2, "commons": 2, "max_safety": 1}
* safe_nodes: 2
safety(all): {"FAULT": 2, "is_safety": false, "max_safety": 1, "safe_nodes": 2, "safety": 1}
............................................................................................................................................................................................................................................
liveness(a): {"FAULT": 2, "QUORUM": "a", "commons": 2, "has_liveness": true, "is_safety": false, "max_safety": 1, "size_of_nodes": 5}
liveness(b): {"FAULT": 2, "QUORUM": "b", "commons": 2, "has_liveness": true, "is_safety": false, "max_safety": 1, "size_of_nodes": 4}
- FAULT: 3 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
max_safety(all): {"FAULT": 3, "commons": 2, "max_safety": 1}
* safe_nodes: 2
safety(all): {"FAULT": 3, "is_safety": false, "max_safety": 1, "safe_nodes": 2, "safety": 1}
............................................................................................................................................................................................................................................
liveness(a): {"FAULT": 3, "QUORUM": "a", "commons": 2, "has_liveness": true, "is_safety": false, "max_safety": 1, "size_of_nodes": 5}
liveness(b): {"FAULT": 3, "QUORUM": "b", "commons": 2, "has_liveness": false, "is_safety": false, "max_safety": 1, "size_of_nodes": 4}