├── shell ├── bootstrapping │ ├── test │ │ ├── test2.test │ │ ├── test1.test │ │ └── test3.test │ ├── Hash.class │ ├── Parser.class │ ├── Samples.class │ ├── tla2tools.jar │ ├── Hash.tla │ ├── apalache │ │ ├── Hash.tla │ │ ├── Hash.java │ │ ├── MC_safety.cfg │ │ └── MC_safety.tla │ ├── automate │ │ ├── collect.pyc │ │ ├── gen_java.pyc │ │ ├── gen_tla.pyc │ │ ├── action_map.pyc │ │ ├── action_map.py │ │ ├── translate.py │ │ ├── collect.py │ │ ├── gen_tla.py │ │ └── gen_java.py │ ├── nodeActions │ │ ├── NodeActions.class │ │ └── NodeActions.jar │ ├── Samples.tla │ ├── Parser.tla │ ├── Hash.java │ ├── MC.tla │ ├── MC_safety.cfg │ ├── MC_liveness.cfg │ ├── MC.cfg │ ├── Samples.java │ ├── ActionTraceChecker.tla │ ├── MC_liveness.tla │ └── MC_safety.tla ├── distributed_db_abstract │ ├── Model_1 │ │ ├── MC.cfg │ │ ├── MC.tla │ │ ├── DB_Invariants.tla │ │ ├── DB_Activation.tla │ │ ├── DB_Maintenance.tla │ │ ├── DB_Request.tla │ │ ├── Utils.tla │ │ ├── DB.tla │ │ └── DB_TypeOK.tla │ ├── DB_Invariants.tla │ ├── DB_Activation.tla │ ├── DB_Maintenance.tla │ ├── DB_Request.tla │ ├── Utils.tla │ ├── DB.tla │ └── DB_TypeOK.tla ├── high_level │ ├── Model_more │ │ ├── MC.tla │ │ ├── MC.cfg │ │ ├── HL_Properties.tla │ │ └── Utils.tla │ ├── Model_simple │ │ ├── MC.cfg │ │ ├── MC.tla │ │ ├── HL_Properties.tla │ │ └── Utils.tla │ ├── HL_Properties.tla │ ├── README.md │ └── Utils.tla ├── mempool │ ├── Blocks.tla │ ├── MC_safety.cfg │ ├── Messages.tla │ ├── MC_liveness.cfg │ ├── Operations.tla │ ├── MC_safety.tla │ ├── MC_liveness.tla │ ├── Topology.tla │ └── README.md ├── distributed_db │ ├── DistributedDB.toolbox │ │ └── Model_1 │ │ │ ├── MC.cfg │ │ │ ├── MC.tla │ │ │ ├── DB_Activation.tla │ │ │ ├── DB_Maintenance.tla │ │ │ ├── DB_Receive.tla │ │ │ ├── DB_Invariants.tla │ │ │ ├── DB_Advertise.tla │ │ │ └── Utils.tla │ ├── DB_Activation.tla │ ├── DB_Maintenance.tla │ ├── DB_Receive.tla │ ├── DB_Invariants.tla │ ├── DB_Advertise.tla │ └── Utils.tla └── README.md ├── consensus ├── Emmy │ ├── seed_generation.png │ ├── Emmy_plus_safety.tla │ ├── README.md │ └── Emmy_star_safety.tla ├── Tenderbake │ ├── Hash.tla │ ├── Hash.java │ ├── MC_safety.tla │ ├── MC_safety.cfg │ ├── README.md │ └── Tenderbake.md └── README.md ├── p2p ├── counter │ ├── Model │ │ ├── MC.tla │ │ ├── MC.cfg │ │ ├── Utils.tla │ │ └── Counter.tla │ └── Utils.tla ├── scheduler_rw │ ├── Model │ │ ├── MC.tla │ │ ├── MC.cfg │ │ ├── Utils.tla │ │ └── MC.out │ └── Utils.tla ├── handshaking │ ├── MC.tla │ ├── MC_safety.tla │ ├── MC_liveness.tla │ ├── apalache │ │ ├── 2good_8bad │ │ │ ├── MC_safety_2good_8bad.tla │ │ │ └── MC_safety_2good_8bad.cfg │ │ └── 4good_1bad │ │ │ ├── MC_safety_4good_1bad.tla │ │ │ └── MC_safety_4good_1bad.cfg │ ├── MC_liveness.cfg │ ├── MC_safety.cfg │ ├── MC.cfg │ └── MC_safety.out ├── scheduler │ └── Scheduler.toolbox │ │ └── Scheduler │ │ ├── MC.cfg │ │ └── MC.tla └── README.md ├── .gitignore ├── LICENSE ├── README.md └── utils └── Utils.tla /shell/bootstrapping/test/test2.test: -------------------------------------------------------------------------------- 1 | WakeupEvent 2 | -------------------------------------------------------------------------------- /shell/bootstrapping/test/test1.test: -------------------------------------------------------------------------------- 1 | PeersDnsLookupInit> hello, 2 2 | -------------------------------------------------------------------------------- /shell/bootstrapping/Hash.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/Hash.class -------------------------------------------------------------------------------- /consensus/Emmy/seed_generation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/consensus/Emmy/seed_generation.png -------------------------------------------------------------------------------- /shell/bootstrapping/Parser.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/Parser.class -------------------------------------------------------------------------------- /shell/bootstrapping/Samples.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/Samples.class -------------------------------------------------------------------------------- /shell/bootstrapping/tla2tools.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/tla2tools.jar -------------------------------------------------------------------------------- /consensus/Tenderbake/Hash.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Hash ---- 2 | 3 | EXTENDS Integers 4 | 5 | Hash(val) == CHOOSE n \in Int : TRUE 6 | 7 | ==== -------------------------------------------------------------------------------- /shell/bootstrapping/Hash.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Hash ---- 2 | 3 | EXTENDS Integers 4 | 5 | Hash(val) == CHOOSE n \in Int : TRUE 6 | 7 | ==== -------------------------------------------------------------------------------- /shell/bootstrapping/apalache/Hash.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Hash ---- 2 | 3 | EXTENDS Integers 4 | 5 | Hash(val) == CHOOSE n \in Int : TRUE 6 | 7 | ==== -------------------------------------------------------------------------------- /shell/bootstrapping/automate/collect.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/automate/collect.pyc -------------------------------------------------------------------------------- /shell/bootstrapping/automate/gen_java.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/automate/gen_java.pyc -------------------------------------------------------------------------------- /shell/bootstrapping/automate/gen_tla.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/automate/gen_tla.pyc -------------------------------------------------------------------------------- /shell/bootstrapping/automate/action_map.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/automate/action_map.pyc -------------------------------------------------------------------------------- /shell/bootstrapping/nodeActions/NodeActions.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/nodeActions/NodeActions.class -------------------------------------------------------------------------------- /shell/bootstrapping/nodeActions/NodeActions.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tezedge/tezedge-specification/HEAD/shell/bootstrapping/nodeActions/NodeActions.jar -------------------------------------------------------------------------------- /shell/bootstrapping/Samples.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Samples ---- 2 | 3 | EXTENDS Integers, Sequences 4 | 5 | Samples(g, hash_seq) == CHOOSE x \in Seq(Int) : TRUE 6 | 7 | ==== 8 | -------------------------------------------------------------------------------- /p2p/counter/Model/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | EXTENDS Counter, TLC 3 | 4 | _alpha == 100 5 | _id == 0 6 | numCounters == 2 7 | _sizeBound == 1001 8 | 9 | ================== 10 | -------------------------------------------------------------------------------- /shell/bootstrapping/Parser.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Parser ---- 2 | 3 | EXTENDS Naturals, Sequences 4 | 5 | Data == STRING \X Seq(STRING \cup Nat) 6 | 7 | parse(path) == CHOOSE x \in Seq(Data) : TRUE 8 | 9 | ======================= 10 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/MC.cfg: -------------------------------------------------------------------------------- 1 | CONSTANT 2 | numChains <- num 3 | 4 | CONSTANT 5 | sizeBound <- size 6 | 7 | SPECIFICATION 8 | Spec 9 | 10 | INVARIANT 11 | Safety 12 | Consistency 13 | 14 | PROPERTY 15 | Liveness 16 | -------------------------------------------------------------------------------- /consensus/Tenderbake/Hash.java: -------------------------------------------------------------------------------- 1 | import tlc2.value.impl.IntValue; 2 | import tlc2.value.impl.Value; 3 | 4 | public class Hash { 5 | 6 | public static Value Hash(Value v) { 7 | return IntValue.gen(v.hashCode()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /shell/bootstrapping/Hash.java: -------------------------------------------------------------------------------- 1 | import tlc2.value.impl.IntValue; 2 | import tlc2.value.impl.Value; 3 | 4 | public class Hash { 5 | 6 | public static Value Hash(Value v) { 7 | return IntValue.gen(v.hashCode()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /shell/bootstrapping/apalache/Hash.java: -------------------------------------------------------------------------------- 1 | import tlc2.value.impl.IntValue; 2 | import tlc2.value.impl.Value; 3 | 4 | public class Hash { 5 | 6 | public static Value Hash(Value v) { 7 | return IntValue.gen(v.hashCode()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /shell/bootstrapping/test/test3.test: -------------------------------------------------------------------------------- 1 | PeersDnsLookupInit> hello, 666 2 | PeerConnectionOutgoingRandomInit 3 | PeerTryWrite> 0:1:2:3:4:5:6:7:1111 4 | PeersAddIncomingPeer> Alice, 0:1:2:3:4:5:6:7:2222 5 | StorageBlockHeadersPut> 1, 2, 3 6 | StorageRequestFinish> 13:666 7 | -------------------------------------------------------------------------------- /shell/high_level/Model_more/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | 3 | EXTENDS HighLevel, TLC 4 | 5 | peer_threshold == 2 6 | 7 | connection_threshold == 2 8 | 9 | num_nodes == 3 10 | 11 | num_joins == 2 12 | 13 | size_bound == 2 14 | 15 | =================== 16 | -------------------------------------------------------------------------------- /p2p/scheduler_rw/Model/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | 3 | EXTENDS RWScheduler, TLC 4 | 5 | max_speed == 1 6 | 7 | max_conn == 1 8 | 9 | max_count == 1 10 | 11 | max_msg == 1 12 | 13 | max_quota == 1 14 | 15 | hl_queue == 1 16 | 17 | in_queue == 1 18 | 19 | =================== -------------------------------------------------------------------------------- /shell/mempool/Blocks.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Blocks ---- 2 | 3 | EXTENDS Integers, Sequences 4 | 5 | CONSTANT OpHashes 6 | 7 | BlockHashes == Int 8 | Blocks == [ hash : BlockHashes, ops : Seq(OpHashes) ] 9 | 10 | block(h, ops) == [ hash |-> h, ops |-> ops ] 11 | 12 | ======================= 13 | -------------------------------------------------------------------------------- /p2p/counter/Model/MC.cfg: -------------------------------------------------------------------------------- 1 | CONSTANT 2 | None = None 3 | alpha <- _alpha 4 | id <- _id 5 | NumCounters <- numCounters 6 | sizeBound <- _sizeBound 7 | 8 | SPECIFICATION 9 | Spec 10 | 11 | INVARIANT 12 | StateOK 13 | RegisteredOK 14 | OnlyUnregisteredNullState 15 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | 3 | EXTENDS DB, TLC 4 | 5 | \* CONSTANTS 6 | num == 2 7 | 8 | size == 1 9 | 10 | \* Invariants & Properties 11 | Consistency == Invariants!Agreement 12 | 13 | Safety == TypeOK!TypeOK 14 | 15 | Liveness == ActiveNodeEventuallySyncs 16 | 17 | =================== 18 | -------------------------------------------------------------------------------- /p2p/handshaking/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | 3 | EXTENDS Handshaking_nack_peers, TLC 4 | 5 | \* @type: Set(Int); 6 | Bad_nodes == 0..0 7 | 8 | \* @type: Set(Int); 9 | Good_nodes == 1..2 10 | 11 | \* @type: Int; 12 | Max == 2 13 | 14 | \* @type: Int; 15 | Min == 1 16 | 17 | \* @type: Int; 18 | Min_peers == 2 19 | 20 | =================== 21 | -------------------------------------------------------------------------------- /shell/bootstrapping/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | 3 | EXTENDS ActionTraceChecker 4 | 5 | Nodes == {"a", "b"} 6 | Min_peers == 0 7 | Max_peers == 10 8 | Max_ops == 10 9 | Max_score == 100 10 | Incr_score == 10 11 | Decr_score == 10 12 | Init_chain == <> 13 | Init_head == gen_header 14 | Init_connections == {} 15 | 16 | =================== 17 | -------------------------------------------------------------------------------- /p2p/handshaking/MC_safety.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_safety ---- 2 | 3 | EXTENDS Handshaking, TLC 4 | 5 | \* @type: Set(Int); 6 | Bad_nodes == 0..0 7 | 8 | \* @type: Set(Int); 9 | Good_nodes == 1..2 10 | 11 | \* @type: Int; 12 | Max == 2 13 | 14 | \* @type: Int; 15 | Min == 1 16 | 17 | \* @type: Int; 18 | Min_peers == 2 19 | 20 | ========================== 21 | -------------------------------------------------------------------------------- /p2p/handshaking/MC_liveness.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_liveness ---- 2 | 3 | EXTENDS Handshaking, TLC 4 | 5 | \* @type: Set(Int); 6 | Bad_nodes == 0..0 7 | 8 | \* @type: Set(Int); 9 | Good_nodes == 1..2 10 | 11 | \* @type: Int; 12 | Max == 2 13 | 14 | \* @type: Int; 15 | Min == 1 16 | 17 | \* @type: Int; 18 | Min_peers == 2 19 | 20 | ============================ 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | ## important 4 | !*/ 5 | !*.tla 6 | !*.cfg 7 | !*.out 8 | !*.dot 9 | !*.md 10 | !*.png 11 | !*.java 12 | !*.class 13 | !*.jar 14 | !*.py 15 | !*.pyc 16 | 17 | ## generated by Toolbox/TLC 18 | *SnapShot* 19 | 20-* 20 | 21-* 21 | *TTrace* 22 | */states 23 | 24 | ## utils 25 | */Utils.toolbox 26 | 27 | ## Apalache 28 | */x 29 | !detailed.log 30 | -------------------------------------------------------------------------------- /shell/bootstrapping/automate/action_map.py: -------------------------------------------------------------------------------- 1 | # Maps action names to TLA+ definitions 2 | 3 | actionMap = {} 4 | 5 | actionMap['PeersDnsLookupInit'] = ' UNCHANGED vars' 6 | 7 | actionMap['PeersDnsLookupSuccess'] = ' UNCHANGED vars' 8 | 9 | # TODO 10 | 11 | def action(name): 12 | res = actionMap.get(name) 13 | if res != None: 14 | return res 15 | else: 16 | return ' UNCHANGED vars' 17 | -------------------------------------------------------------------------------- /p2p/handshaking/apalache/2good_8bad/MC_safety_2good_8bad.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_safety_2good_8bad ---- 2 | 3 | EXTENDS Handshaking, TLC 4 | 5 | \* @type: Set(Int); 6 | Bad_nodes == 0..7 7 | 8 | \* @type: Set(Int); 9 | Good_nodes == 8..9 10 | 11 | \* @type: Int; 12 | Max == 5 13 | 14 | \* @type: Int; 15 | Min == 1 16 | 17 | \* @type: Int; 18 | Min_peers == 3 19 | 20 | ===================================== 21 | -------------------------------------------------------------------------------- /p2p/handshaking/apalache/4good_1bad/MC_safety_4good_1bad.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_safety_4good_1bad ---- 2 | 3 | EXTENDS Handshaking, TLC 4 | 5 | \* @type: Set(Int); 6 | Bad_nodes == 0..0 7 | 8 | \* @type: Set(Int); 9 | Good_nodes == 1..4 10 | 11 | \* @type: Int; 12 | Max == 3 13 | 14 | \* @type: Int; 15 | Min == 1 16 | 17 | \* @type: Int; 18 | Min_peers == 2 19 | 20 | ===================================== 21 | -------------------------------------------------------------------------------- /shell/high_level/Model_simple/MC.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | a = a 3 | b = b 4 | ValidStates = {a, b} 5 | peerThreshold <- peer_threshold 6 | connectionThreshold <- connection_threshold 7 | NumNodes <- num_nodes 8 | NumJoins <- num_joins 9 | sizeBound <- size_bound 10 | 11 | SPECIFICATION 12 | Spec 13 | 14 | INVARIANT 15 | Inv 16 | 17 | PROPERTIES 18 | Prop1 19 | Prop2 20 | -------------------------------------------------------------------------------- /consensus/Tenderbake/MC_safety.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_safety ---- 2 | 3 | EXTENDS Tenderbake 4 | 5 | Correct_procs == 1..4 6 | 7 | Faulty_procs == 0..0 8 | 9 | Committee_size == 4 10 | 11 | Committee[ l \in Levels ] == 12 | IF l = 0 THEN Procs 13 | ELSE Procs \ {l % n} 14 | 15 | Proposer[ l \in Levels ] == 16 | [ r \in Rounds |-> 17 | IF r % n = 0 THEN (l + 1) % n 18 | ELSE (l + r) % n ] 19 | 20 | ========================== 21 | -------------------------------------------------------------------------------- /shell/high_level/Model_more/MC.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | a = a 3 | b = b 4 | ValidStates = {a, b} 5 | peerThreshold <- peer_threshold 6 | connectionThreshold <- connection_threshold 7 | NumNodes <- num_nodes 8 | NumJoins <- num_joins 9 | sizeBound <- size_bound 10 | 11 | SPECIFICATION 12 | Spec 13 | 14 | INVARIANT 15 | TypeOK!TypeOK 16 | 17 | PROPERTIES 18 | Properties!AllNodesHaveJoined 19 | Properties!AllNodesHaveSameState 20 | -------------------------------------------------------------------------------- /p2p/scheduler_rw/Model/MC.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | Messages = {a, b} 3 | Max_speed <- max_speed 4 | Max_conn <- max_conn 5 | Max_count <- max_count 6 | Max_msg <- max_msg 7 | Max_quota <- max_quota 8 | HL_queue <- hl_queue 9 | In_queue <- in_queue 10 | None = None 11 | 12 | SPECIFICATION 13 | Spec 14 | 15 | INVARIANTS 16 | StateOK 17 | QueueOK 18 | ConnOK 19 | QuotaOK 20 | CounterOK 21 | WaitingOK 22 | InParamOK 23 | -------------------------------------------------------------------------------- /consensus/Tenderbake/MC_safety.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | NULL = NULL \* model value 3 | CORRECT_PROCS <- Correct_procs 4 | FAULTY_PROCS <- Faulty_procs 5 | PROPOSER <- Proposer 6 | COMMITTEE <- Committee 7 | COMMITTEE_SIZE <- Committee_size 8 | 9 | SPECIFICATION 10 | Spec 11 | 12 | INVARIANTS 13 | TypeOK 14 | Agreement 15 | Validity 16 | CorrectLevels 17 | BoundedMessageBuffers 18 | PreendorsementQCs 19 | HeadCerts 20 | Endorsables 21 | LockedIffEndorsable 22 | -------------------------------------------------------------------------------- /shell/mempool/MC_safety.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | INIT_PEERS <- Init_peers 3 | INIT_CONNECTIONS <- Init_connections 4 | INIT_PREDECESSOR <- Init_predecessor 5 | MAX_HOPS <- Max_hops 6 | MIN_CONNECTIONS <- Min_connections 7 | MAX_CONNECTIONS <- Max_connections 8 | MIN_ENDORSEMENTS <- Min_endorsements 9 | MAX_HASH <- Max_hash 10 | NONE = NONE 11 | 12 | SPECIFICATION 13 | Spec 14 | 15 | INVARIANTS 16 | TypeOK 17 | ConnectionSymmetry 18 | ClassificationDisjointness 19 | 20 | \* VIEW 21 | \* View 22 | -------------------------------------------------------------------------------- /consensus/README.md: -------------------------------------------------------------------------------- 1 | # consensus 2 | 3 | There are two categories of consensus algorithms in Tezos: *Emmy* and *Tenderbake*. The specifications for each can be found in their respective directories. 4 | 5 | ## Emmy/Emmy+/Emmy★ 6 | 7 | Emmy is the original consensus algorithm used in Tezos which features probabilistic finality. This project contains a specification and models of this family of algorithms. 8 | 9 | ## Tenderbake 10 | 11 | Tenderbake is the new generation of consensus algorithm used in Tezos. This project contains a specification and models of this algorithm. 12 | -------------------------------------------------------------------------------- /shell/distributed_db/DistributedDB.toolbox/Model_1/MC.cfg: -------------------------------------------------------------------------------- 1 | \* CONSTANT definitions 2 | CONSTANT 3 | sizeBound <- const_1613429254548116000 4 | \* CONSTANT definitions 5 | CONSTANT 6 | numChains <- const_1613429254548117000 7 | \* CONSTANT definitions 8 | CONSTANT 9 | numNodes <- const_1613429254548118000 10 | \* SPECIFICATION definition 11 | SPECIFICATION 12 | Spec 13 | \* INVARIANT definition 14 | INVARIANT 15 | inv_1613429254549119000 16 | inv_1613429254549120000 17 | \* PROPERTY definition 18 | PROPERTY 19 | prop_1613429254549121000 20 | \* Generated on Mon Feb 15 15:47:34 MST 2021 -------------------------------------------------------------------------------- /shell/bootstrapping/MC_safety.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | MAX_OPS <- Max_ops 3 | MIN_PEERS <- Min_peers 4 | MAX_PEERS <- Max_peers 5 | MAX_LEVEL <- Max_level 6 | VALIDATOR <- Validator 7 | BAD_NODES <- Bad_nodes 8 | GOOD_NODES <- Good_nodes 9 | CURRENT_HEAD <- Current_head 10 | BLOCKS <- Good_node_blocks 11 | BAD_BOOTSTRAPPING <- Bad_bootstrapping 12 | GOOD_BOOTSTRAPPING <- Good_bootstrapping 13 | 14 | SPECIFICATION 15 | Spec 16 | 17 | INVARIANTS 18 | TypeOK 19 | Safety 20 | -------------------------------------------------------------------------------- /shell/mempool/Messages.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Messages ---- 2 | 3 | EXTENDS Sequences 4 | 5 | CONSTANT Nodes, Mempool, Blocks 6 | 7 | INSTANCE Operations 8 | 9 | \* Operation 10 | \* Advertisement request/response 11 | \* any others? 12 | 13 | MsgTypes == { "Head", "GetHead", "Operation" } 14 | AdvContents == Mempool 15 | OpContents == Operations 16 | Messages == 17 | [ type : {"Head"}, from : Nodes, contents : Blocks \X AdvContents ] \cup 18 | [ type : {"GetHead"}, from : Nodes ] \cup 19 | [ type : {"Operation"}, from : Nodes, contents : OpContents ] 20 | 21 | ========================= 22 | -------------------------------------------------------------------------------- /p2p/handshaking/MC_liveness.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | BAD_NODES <- Bad_nodes 3 | GOOD_NODES <- Good_nodes 4 | MAX <- Max 5 | MIN <- Min 6 | MIN_PEERS <- Min_peers 7 | 8 | SPECIFICATION 9 | Spec 10 | 11 | PROPERTIES 12 | OnceBlacklistedAlwaysBlacklisted 13 | PeerSaturationIsMonotonicIncreasing 14 | GoodNodesEventuallyExceedMinConnections 15 | GoodNodesAlwaysRespondToAckMessagesOrBlacklist 16 | GoodNodesAlwaysRespondToMetaMessagesOrBlacklist 17 | GoodNodesAlwaysRespondToConnectionMessagesOrBlacklist 18 | ConnectionsBetweenGoodNodesAreEventuallyBidirectionalOrClosed 19 | -------------------------------------------------------------------------------- /shell/bootstrapping/MC_liveness.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | MAX_OPS <- Max_ops 3 | MIN_PEERS <- Min_peers 4 | MAX_PEERS <- Max_peers 5 | MAX_LEVEL <- Max_level 6 | VALIDATOR <- Validator 7 | BAD_NODES <- Bad_nodes 8 | GOOD_NODES <- Good_nodes 9 | CURRENT_HEAD <- Current_head 10 | SAMPLES <- Node_samples 11 | BLOCKS <- Good_node_blocks 12 | BAD_BOOTSTRAPPING <- Bad_bootstrapping 13 | GOOD_BOOTSTRAPPING <- Good_bootstrapping 14 | 15 | SPECIFICATION 16 | Spec 17 | 18 | PROPERTIES 19 | Liveness 20 | -------------------------------------------------------------------------------- /shell/bootstrapping/apalache/MC_safety.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | MAX_OPS <- Max_ops 3 | MIN_PEERS <- Min_peers 4 | MAX_PEERS <- Max_peers 5 | MAX_LEVEL <- Max_level 6 | VALIDATOR <- Validator 7 | BAD_NODES <- Bad_nodes 8 | GOOD_NODES <- Good_nodes 9 | CURRENT_HEAD <- Current_head 10 | SAMPLES <- Node_samples 11 | BLOCKS <- Good_node_blocks 12 | BAD_BOOTSTRAPPING <- Bad_bootstrapping 13 | GOOD_BOOTSTRAPPING <- Good_bootstrapping 14 | 15 | SPECIFICATION 16 | Spec 17 | 18 | INVARIANTS 19 | TypeOK 20 | Safety 21 | -------------------------------------------------------------------------------- /shell/mempool/MC_liveness.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | INIT_PEERS <- Init_peers 3 | INIT_CONNECTIONS <- Init_connections 4 | INIT_PREDECESSOR <- Init_predecessor 5 | MAX_HOPS <- Max_hops 6 | MIN_CONNECTIONS <- Min_connections 7 | MAX_CONNECTIONS <- Max_connections 8 | MIN_ENDORSEMENTS <- Min_endorsements 9 | MAX_HASH <- Max_hash 10 | NONE = NONE 11 | 12 | SPECIFICATION 13 | Spec 14 | 15 | PROPERTIES 16 | OperationClassification 17 | BranchDelayedMonotonicity 18 | BranchRefusedMonotonicity 19 | RefusedMonotonicity 20 | EndorsementPropagation 21 | BlockPropagation 22 | 23 | \* VIEW 24 | \* View 25 | -------------------------------------------------------------------------------- /shell/bootstrapping/MC.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | NODES <- Nodes 3 | MIN_PEERS <- Min_peers 4 | MAX_PEERS <- Max_peers 5 | MAX_OPS <- Max_ops 6 | MAX_SCORE <- Max_score 7 | INCR_SCORE <- Incr_score 8 | DECR_SCORE <- Decr_score 9 | INIT_CHAIN <- Init_chain 10 | INIT_HEAD <- Init_head 11 | INIT_CONNECTIONS <- Init_connections 12 | NONE = NONE 13 | 14 | SPECIFICATION 15 | ComposedSpec 16 | 17 | \* this invariant will be: 18 | \* - satisfied by an incorrect trace 19 | \* - violated by a correct trace 20 | INVARIANT 21 | Incorrect 22 | 23 | \* this property will be: 24 | \* - violated by an incorrect trace 25 | \* - satisfied by a correct trace 26 | \* PROPERTY 27 | \* Finished 28 | -------------------------------------------------------------------------------- /shell/bootstrapping/automate/translate.py: -------------------------------------------------------------------------------- 1 | from collect import * 2 | from gen_java import * 3 | from gen_tla import * 4 | 5 | # relevant files 6 | actionsFile = '../rust/action.rs' 7 | nodeActionsDir = '../nodeActions/' 8 | nodeActionsFile = nodeActionsDir + 'NodeActions.java' 9 | nodeActionsJar = nodeActionsDir + 'NodeActions.jar' 10 | actionTranslatorFile = '../ActionTranslator.tla' 11 | 12 | # Get the list of all action names 13 | actionNames = collectActionNames(actionsFile) 14 | 15 | # Generate the java collection of all action names 16 | generateJavaClassAndCompile(actionNames, nodeActionsFile, nodeActionsJar) 17 | 18 | # Generate the corresponding ActionTranslator.tla file 19 | generateTLA(actionNames, actionTranslatorFile) 20 | -------------------------------------------------------------------------------- /p2p/handshaking/MC_safety.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | BAD_NODES <- Bad_nodes 3 | GOOD_NODES <- Good_nodes 4 | MAX <- Max 5 | MIN <- Min 6 | MIN_PEERS <- Min_peers 7 | 8 | SPECIFICATION 9 | Spec 10 | 11 | INVARIANTS 12 | TypeOK 13 | NoSelfInteractions 14 | GoodNodesOnlyConnectWithPeers 15 | GoodNodesDoNotExceedMaxConnections 16 | GoodNodesOnlyExchangeMessagesWithPeers 17 | GoodNodesNeverHaveMessagesFromBlacklistedPeers 18 | GoodNodesHaveExlcusiveInProgressAndConnections 19 | GoodNodesOnlyConnectToNodesWithWhomTheyHaveExchangedAllMessages 20 | GoodNodesOnlyExchangeMetaMessagesAfterSendingAndReceivingConnectionMessages 21 | GoodNodesOnlyExchangeAckMessagesAfterSendingAndReceivingConnectionAndMetaMessages 22 | -------------------------------------------------------------------------------- /shell/bootstrapping/Samples.java: -------------------------------------------------------------------------------- 1 | import tlc2.value.impl.IntValue; 2 | import tlc2.value.impl.TupleValue; 3 | import tlc2.value.impl.Value; 4 | 5 | import java.util.*; 6 | 7 | public class Samples { 8 | 9 | public static Value Samples(IntValue good_node, TupleValue hash_seq) { 10 | int x = (int) Math.pow(2, good_node.val); 11 | Random rng = new Random(x); 12 | List values = new ArrayList<>(); 13 | values.add((IntValue) hash_seq.getElem(0)); 14 | int n = hash_seq.size(); 15 | for (int i = 1; i < n; i++) { 16 | boolean keep = rng.nextBoolean(); 17 | if (keep) { 18 | values.add((IntValue) hash_seq.getElem(i)); 19 | } 20 | }; 21 | return new TupleValue(values.toArray(new Value[0])); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /p2p/handshaking/apalache/2good_8bad/MC_safety_2good_8bad.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | BAD_NODES <- Bad_nodes 3 | GOOD_NODES <- Good_nodes 4 | MAX <- Max 5 | MIN <- Min 6 | MIN_PEERS <- Min_peers 7 | 8 | SPECIFICATION 9 | Spec 10 | 11 | INVARIANTS 12 | TypeOK 13 | NoSelfInteractions 14 | GoodNodesOnlyConnectWithPeers 15 | GoodNodesDoNotExceedMaxConnections 16 | GoodNodesOnlyExchangeMessagesWithPeers 17 | GoodNodesNeverHaveMessagesFromBlacklistedPeers 18 | GoodNodesHaveExlcusiveInProgressAndConnections 19 | GoodNodesOnlyConnectToNodesWithWhomTheyHaveExchangedAllMessages 20 | GoodNodesOnlyExchangeMetaMessagesAfterSendingAndReceivingConnectionMessages 21 | GoodNodesOnlyExchangeAckMessagesAfterSendingAndReceivingConnectionAndMetaMessages 22 | -------------------------------------------------------------------------------- /p2p/handshaking/apalache/4good_1bad/MC_safety_4good_1bad.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | BAD_NODES <- Bad_nodes 3 | GOOD_NODES <- Good_nodes 4 | MAX <- Max 5 | MIN <- Min 6 | MIN_PEERS <- Min_peers 7 | 8 | SPECIFICATION 9 | Spec 10 | 11 | INVARIANTS 12 | TypeOK 13 | NoSelfInteractions 14 | GoodNodesOnlyConnectWithPeers 15 | GoodNodesDoNotExceedMaxConnections 16 | GoodNodesOnlyExchangeMessagesWithPeers 17 | GoodNodesNeverHaveMessagesFromBlacklistedPeers 18 | GoodNodesHaveExlcusiveInProgressAndConnections 19 | GoodNodesOnlyConnectToNodesWithWhomTheyHaveExchangedAllMessages 20 | GoodNodesOnlyExchangeMetaMessagesAfterSendingAndReceivingConnectionMessages 21 | GoodNodesOnlyExchangeAckMessagesAfterSendingAndReceivingConnectionAndMetaMessages 22 | -------------------------------------------------------------------------------- /shell/high_level/Model_simple/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | 3 | EXTENDS HighLevel, TLC 4 | 5 | peer_threshold == 2 6 | 7 | connection_threshold == 1 8 | 9 | num_nodes == 2 10 | 11 | num_joins == 2 12 | 13 | size_bound == 1 14 | 15 | Inv == TypeOK!TypeOK 16 | 17 | Prop1 == Properties!AllNodesHaveJoined 18 | 19 | Prop2 == Properties!AllNodesHaveSameState 20 | 21 | \* For Apalache 22 | UNROLL_TIMES_isSubSeq == 2 * size_bound 23 | UNROLL_DEFAULT_isSubSeq == <<>> 24 | 25 | UNROLL_TIMES_TypeOK_isSubSeq == 2 * size_bound 26 | UNROLL_DEFAULT_TypeOK_isSubSeq == <<>> 27 | 28 | UNROLL_TIMES_Properties_isSubSeq == 2 * size_bound 29 | UNROLL_DEFAULT_Properties_isSubSeq == <<>> 30 | 31 | UNROLL_TIMES_Properties_Act_isSubSeq == 2 * size_bound 32 | UNROLL_DEFAULT_Properties_Act_isSubSeq == <<>> 33 | 34 | =================== 35 | -------------------------------------------------------------------------------- /shell/bootstrapping/automate/collect.py: -------------------------------------------------------------------------------- 1 | # Get the list of all action names from [actionsFile] 2 | 3 | def collectActionNames(actionsFile): 4 | 5 | # get action file contents 6 | fr = open(actionsFile, 'r') 7 | actionNames = fr.read() 8 | fr.close() 9 | 10 | # return the list of all action names 11 | actionNames = actionNames.split('pub enum Action {') 12 | actionNames = actionNames[1] 13 | actionNames = actionNames.split('}') 14 | actionNames = actionNames[0] 15 | actionNames = actionNames.splitlines() 16 | 17 | # remove empty lines 18 | while '' in actionNames: 19 | actionNames.remove('') 20 | 21 | actionNames = map(str.strip, actionNames) 22 | actionNames = map(lambda s: s.split('(')[0], actionNames) 23 | 24 | # remove comments 25 | for line in actionNames: 26 | if line.startswith('//'): 27 | actionNames.remove(line) 28 | 29 | return actionNames 30 | -------------------------------------------------------------------------------- /shell/distributed_db/DistributedDB.toolbox/Model_1/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | EXTENDS DistributedDB, TLC 3 | 4 | \* CONSTANT definitions @modelParameterConstants:0sizeBound 5 | const_1613429254548116000 == 6 | 1 7 | ---- 8 | 9 | \* CONSTANT definitions @modelParameterConstants:1numChains 10 | const_1613429254548117000 == 11 | 1 12 | ---- 13 | 14 | \* CONSTANT definitions @modelParameterConstants:2numNodes 15 | const_1613429254548118000 == 16 | 2 17 | ---- 18 | 19 | \* INVARIANT definition @modelCorrectnessInvariants:0 20 | inv_1613429254549119000 == 21 | DB_Invariants!ActiveAgreement 22 | ---- 23 | \* INVARIANT definition @modelCorrectnessInvariants:1 24 | inv_1613429254549120000 == 25 | DB_TypeOK!TypeOK 26 | ---- 27 | \* PROPERTY definition @modelCorrectnessProperties:0 28 | prop_1613429254549121000 == 29 | DB_Invariants!ActiveNodesEventuallySync 30 | ---- 31 | ================================================================================ 32 | -------------------------------------------------------------------------------- /p2p/scheduler/Scheduler.toolbox/Scheduler/MC.cfg: -------------------------------------------------------------------------------- 1 | \* MV CONSTANT declarations 2 | CONSTANTS 3 | a = a 4 | \* CONSTANT declarations 5 | CONSTANT None = None 6 | \* MV CONSTANT definitions 7 | CONSTANT 8 | Messages <- const_16092824186411304000 9 | \* CONSTANT definitions 10 | CONSTANT 11 | HL <- const_16092824186411305000 12 | \* CONSTANT definitions 13 | CONSTANT 14 | IO <- const_16092824186411306000 15 | \* CONSTANT definitions 16 | CONSTANT 17 | M <- const_16092824186411307000 18 | \* CONSTANT definitions 19 | CONSTANT 20 | N <- const_16092824186411308000 21 | \* CONSTANT definitions 22 | CONSTANT 23 | Q <- const_16092824186411309000 24 | \* CONSTANT definitions 25 | CONSTANT 26 | S <- const_16092824186411310000 27 | \* CONSTANT definitions 28 | CONSTANT 29 | Max_read <- const_16092824186411311000 30 | \* CONSTANT definitions 31 | CONSTANT 32 | Max_write <- const_16092824186411312000 33 | \* SPECIFICATION definition 34 | SPECIFICATION 35 | Spec 36 | \* Generated on Tue Dec 29 15:53:38 MST 2020 -------------------------------------------------------------------------------- /p2p/README.md: -------------------------------------------------------------------------------- 1 | # p2p 2 | 3 | This directory contains all the specifications and models related to the p2p overlay network. 4 | 5 | ## handshaking 6 | 7 | This project contains a specification and models of the handshaking protocol (see [P2p_socket](https://gitlab.com/tezos/tezos/-/blob/master/src/lib_p2p/p2p_socket.ml)). 8 | 9 | ## counter 10 | 11 | This project contains a specification and models of the counter used for I/O resource management (see [Moving_average](https://gitlab.com/tezos/tezos/-/blob/master/src/lib_stdlib_unix/moving_average.ml)) 12 | 13 | ## scheduler 14 | 15 | This project contains a specification and models for the fair I/O scheduler (see [P2p_io_scheduler](https://gitlab.com/tezos/tezos/-/blob/master/src/lib_p2p/p2p_io_scheduler.ml)) 16 | 17 | ## scheduler_rw 18 | 19 | This project contains a specification and models for a simple read (or write) scheduler (see [P2p_io_scheduler](https://gitlab.com/tezos/tezos/-/blob/master/src/lib_p2p/p2p_io_scheduler.ml)). This specification is instantiated in the `scheduler` specification. 20 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/DB_Invariants.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE DB_Invariants ----------------------------- 2 | 3 | EXTENDS DB_Defs 4 | 5 | (**************) 6 | (* Properties *) 7 | (**************) 8 | 9 | \* If node remains active on [chain], then eventually they will learn about all the blocks 10 | \* on all the branches of [chain] 11 | EventuallySyncs(chain) == <>[](\A b \in Branches : node_blocks[chain][b] = blocks[chain][b]) 12 | 13 | -------------------------------------------------------------------------------- 14 | 15 | (**************) 16 | (* Invariants *) 17 | (**************) 18 | 19 | \* network and node are in agreement 20 | Agreement == \A chain \in activeChains : 21 | \* branches 22 | /\ node_branches[chain] /= <<>> => current_branch[chain] <= branch[chain] 23 | \* blocks 24 | /\ \A b \in branchSet[chain] : isSubSeq(node_blocks[chain][b], blocks[chain][b]) 25 | \* height 26 | /\ \A b \in branchSet[chain] : node_height[chain][b] <= height[chain][b] 27 | 28 | ================================================================================ 29 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/DB_Invariants.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE DB_Invariants ----------------------------- 2 | 3 | EXTENDS DB_Defs 4 | 5 | (**************) 6 | (* Properties *) 7 | (**************) 8 | 9 | \* If node remains active on [chain], then eventually they will learn about all the blocks 10 | \* on all the branches of [chain] 11 | EventuallySyncs(chain) == <>[](\A b \in Branches : node_blocks[chain][b] = blocks[chain][b]) 12 | 13 | -------------------------------------------------------------------------------- 14 | 15 | (**************) 16 | (* Invariants *) 17 | (**************) 18 | 19 | \* network and node are in agreement 20 | Agreement == \A chain \in activeChains : 21 | \* branches 22 | /\ node_branches[chain] /= <<>> => current_branch[chain] <= branch[chain] 23 | \* blocks 24 | /\ \A b \in branchSet[chain] : isSubSeq(node_blocks[chain][b], blocks[chain][b]) 25 | \* height 26 | /\ \A b \in branchSet[chain] : node_height[chain][b] <= height[chain][b] 27 | 28 | ================================================================================ 29 | -------------------------------------------------------------------------------- /shell/README.md: -------------------------------------------------------------------------------- 1 | # shell 2 | 3 | ## bootstrapping 4 | 5 | This project contains specifications and models of the shell's bootstrapping protocol (see [Bootstrap_pipeline](https://gitlab.com/tezos/tezos/-/blob/master/src/lib_shell/bootstrap_pipeline.ml)). Please see this project's readme for more information. 6 | 7 | ## distributed_db 8 | 9 | This project contains a specification and models of the shell's distributed database (see [Distributed_db](https://gitlab.com/tezos/tezos/-/blob/master/src/lib_shell/distributed_db.ml)). Please see this project's readme for more information. 10 | 11 | ## distributed_db_abstract 12 | 13 | This project contains a specification and models of the shell's distributed database with selected parts abstract away to cut down on the size of the state space. Please see this project's readme for more information. 14 | 15 | ## high_level 16 | 17 | This project contains a high-level specification and models of the handshaking and bootstrapping processes. 18 | 19 | ## mempool 20 | 21 | This project contains a specification and models of the shell's mempool propagation and maintanence processes. 22 | -------------------------------------------------------------------------------- /shell/mempool/Operations.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Operations ---- 2 | 3 | EXTENDS Integers 4 | 5 | (* Granada operations *) 6 | 7 | \* seed_nonce_revelation level nonce 8 | \* endorsement_with_slot [endorsement shell protocol_data] slot 9 | \* double_endorsement_evidence [endorsement shell protocol_data] [endorsement shell protocol_data] slot 10 | \* double_baking_evidence block_header block_header 11 | \* activate_account id activation_code 12 | \* endorsement level 13 | \* proposals source period (proposals : Protocol_hash list) 14 | \* ballot source period (proposal : Protocol_hash) (ballot : Vote_repr.ballot) 15 | \* failing_noop string 16 | 17 | \* Manager operations 18 | \* reveal pub_key 19 | \* transaction amount ?parameters (entrypoint : string) (dest : Contract_repr.contract) 20 | \* origination delegate ?script credit (preorigination : Contract_repr.t option) 21 | \* delegation (pkh : Public_key_hash.t option) 22 | 23 | OpHashes == Int 24 | OpTypes == { "Endorsement", "Other" } 25 | Operations == [ type : OpTypes, hash : OpHashes ] 26 | 27 | OperationsWithHash(h) == [ type : OpTypes, hash : {h} ] 28 | 29 | =========================== 30 | -------------------------------------------------------------------------------- /p2p/handshaking/MC.cfg: -------------------------------------------------------------------------------- 1 | CONSTANTS 2 | BAD_NODES <- Bad_nodes 3 | GOOD_NODES <- Good_nodes 4 | MAX <- Max 5 | MIN <- Min 6 | MIN_PEERS <- Min_peers 7 | 8 | SPECIFICATION 9 | Spec 10 | 11 | INVARIANTS 12 | TypeOK 13 | NoSelfInteractions 14 | GoodNodesOnlyConnectWithPeers 15 | GoodNodesDoNotExceedMaxConnections 16 | GoodNodesOnlyExchangeMessagesWithPeers 17 | GoodNodesNeverHaveMessagesFromBlacklistedPeers 18 | GoodNodesHaveExlcusiveInProgressAndConnections 19 | GoodNodesOnlyConnectToNodesWithWhomTheyHaveExchangedAllMessages 20 | GoodNodesOnlyExchangeMetaMessagesAfterSendingAndReceivingConnectionMessages 21 | GoodNodesOnlyExchangeAckMessagesAfterSendingAndReceivingConnectionAndMetaMessages 22 | 23 | PROPERTIES 24 | OnceConnectedAlwaysConnected 25 | OnceBlacklistedAlwaysBlacklisted 26 | PeerSaturationIsMonotonicIncreasing 27 | GoodNodesEventuallyExceedMinConnections 28 | GoodNodesAlwaysRespondToAckMessagesOrBlacklist 29 | GoodNodesAlwaysRespondToMetaMessagesOrBlacklist 30 | GoodNodesAlwaysRespondToConnectionMessagesOrBlacklist 31 | ConnectionsBetweenGoodNodesAreEventuallyBidirectionalOrClosed 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 simplestaking.com 4 | Copyright (c) 2021 viablesystems.io 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /shell/high_level/HL_Properties.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE HL_Properties ----------------------------- 2 | 3 | CONSTANTS NumNodes, NumJoins, ValidStates, peerThreshold, connectionThreshold, sizeBound 4 | 5 | VARIABLES state, secured, mailbox, recv, sent, joined, peers, phase 6 | 7 | INSTANCE HL_Utils 8 | Act == INSTANCE HL_Actions 9 | 10 | vars == <> 11 | 12 | (***********************) 13 | (* Liveness properties *) 14 | (***********************) 15 | 16 | \* Every joining node joins the network 17 | AllNodesJoined == joining = joined 18 | 19 | AllNodesHaveJoined == <>[]AllNodesJoined 20 | 21 | \* All nodes have the same state 22 | AllNodesSameState == 23 | /\ \A j \in joined, n \in nodes : state.node[n] \in ToSet(state.join[j]) 24 | /\ \A i, j \in joined : ToSet(state.join[i]) = ToSet(state.join[j]) 25 | 26 | AllNodesHaveSameState == []<>AllNodesSameState 27 | 28 | (***********************) 29 | (* Negative Properties *) 30 | (***********************) 31 | 32 | NeverJoin == \E j \in joining: [](j \notin joined) 33 | 34 | ================================================================================ 35 | -------------------------------------------------------------------------------- /shell/high_level/Model_more/HL_Properties.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE HL_Properties ----------------------------- 2 | 3 | CONSTANTS NumNodes, NumJoins, ValidStates, peerThreshold, connectionThreshold, sizeBound 4 | 5 | VARIABLES state, secured, mailbox, recv, sent, joined, peers, phase 6 | 7 | INSTANCE HL_Utils 8 | Act == INSTANCE HL_Actions 9 | 10 | vars == <> 11 | 12 | (***********************) 13 | (* Liveness properties *) 14 | (***********************) 15 | 16 | \* Every joining node joins the network 17 | AllNodesJoined == joining = joined 18 | 19 | AllNodesHaveJoined == <>[]AllNodesJoined 20 | 21 | \* All nodes have the same state 22 | AllNodesSameState == 23 | /\ \A j \in joined, n \in nodes : state.node[n] \in ToSet(state.join[j]) 24 | /\ \A i, j \in joined : ToSet(state.join[i]) = ToSet(state.join[j]) 25 | 26 | AllNodesHaveSameState == []<>AllNodesSameState 27 | 28 | (***********************) 29 | (* Negative Properties *) 30 | (***********************) 31 | 32 | NeverJoin == \E j \in joining: [](j \notin joined) 33 | 34 | ================================================================================ 35 | -------------------------------------------------------------------------------- /shell/high_level/Model_simple/HL_Properties.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE HL_Properties ----------------------------- 2 | 3 | CONSTANTS NumNodes, NumJoins, ValidStates, peerThreshold, connectionThreshold, sizeBound 4 | 5 | VARIABLES state, secured, mailbox, recv, sent, joined, peers, phase 6 | 7 | INSTANCE HL_Utils 8 | Act == INSTANCE HL_Actions 9 | 10 | vars == <> 11 | 12 | (***********************) 13 | (* Liveness properties *) 14 | (***********************) 15 | 16 | \* Every joining node joins the network 17 | AllNodesJoined == joining = joined 18 | 19 | AllNodesHaveJoined == <>[]AllNodesJoined 20 | 21 | \* All nodes have the same state 22 | AllNodesSameState == 23 | /\ \A j \in joined, n \in nodes : state.node[n] \in ToSet(state.join[j]) 24 | /\ \A i, j \in joined : ToSet(state.join[i]) = ToSet(state.join[j]) 25 | 26 | AllNodesHaveSameState == []<>AllNodesSameState 27 | 28 | (***********************) 29 | (* Negative Properties *) 30 | (***********************) 31 | 32 | NeverJoin == \E j \in joining: [](j \notin joined) 33 | 34 | ================================================================================ 35 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/DB_Activation.tla: -------------------------------------------------------------------------------- 1 | --------------------------- MODULE DB_Activation ---------------------------- 2 | 3 | EXTENDS DB_Defs 4 | 5 | (*******************************) 6 | (* Activate/Deactivate actions *) 7 | (*******************************) 8 | 9 | \* node becomes active on [chain] 10 | Activate( chain) == 11 | /\ node_active' = node_active \cup {chain} 12 | /\ UNCHANGED <> 13 | /\ UNCHANGED <> 14 | 15 | \* if node is inactive on some chain, node can become active 16 | Activation == 17 | \E chain \in activeChains : 18 | /\ chain \notin node_active 19 | /\ Activate(chain) 20 | 21 | \* node becomes inactive on [chain] 22 | Deactivate(chain) == 23 | /\ node_active' = node_active \ {chain} 24 | /\ UNCHANGED <> 25 | /\ UNCHANGED <> 26 | 27 | \* if node is inactive on some chain, node can become inactive 28 | Deactivation == 29 | \E chain \in activeChains : 30 | /\ chain \in node_active 31 | /\ Deactivate(chain) 32 | 33 | ============================================================================= 34 | -------------------------------------------------------------------------------- /shell/bootstrapping/automate/gen_tla.py: -------------------------------------------------------------------------------- 1 | # Generates the corresponding ActionTranslator.tla file 2 | # from the actions in the implementation 3 | 4 | from action_map import * 5 | 6 | def generateTLA(actionNames, actionTranslatorFile): 7 | 8 | tlaHeader = '''\ 9 | ---- MODULE ActionTranslator ---- 10 | 11 | EXTENDS Bootstrap 12 | 13 | ''' 14 | 15 | def actionOperatorDef(name): 16 | return '{name}Action(data) =={actionDef}\n'.format(name=name, actionDef=action(name)) 17 | 18 | tlaActionDecls = '' 19 | 20 | for name in actionNames: 21 | tlaActionDecls += actionOperatorDef(name) 22 | 23 | def translation(idx, name): 24 | if idx == 0: 25 | return 'act = "{name}" -> {name}Action(data)\n'.format(name=name) 26 | else: 27 | return ' [] act = "{name}" -> {name}Action(data)\n'.format(name=name) 28 | 29 | actionTranslator = '''\ 30 | 31 | ActionTranslator(input) == 32 | LET act == input[1] 33 | data == input[2] 34 | IN 35 | CASE ''' 36 | 37 | for idx, name in enumerate(actionNames): 38 | actionTranslator += translation(idx, name) 39 | 40 | ending = '\n====\n' 41 | 42 | fw = open(actionTranslatorFile, 'w') 43 | fw.write(tlaHeader + tlaActionDecls + actionTranslator + ending) 44 | fw.close() 45 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/DB_Activation.tla: -------------------------------------------------------------------------------- 1 | --------------------------- MODULE DB_Activation ---------------------------- 2 | 3 | EXTENDS DB_Defs 4 | 5 | (*******************************) 6 | (* Activate/Deactivate actions *) 7 | (*******************************) 8 | 9 | \* node becomes active on [chain] 10 | Activate( chain) == 11 | /\ node_active' = node_active \cup {chain} 12 | /\ UNCHANGED <> 13 | /\ UNCHANGED <> 14 | 15 | \* if node is inactive on some chain, node can become active 16 | Activation == 17 | \E chain \in activeChains : 18 | /\ chain \notin node_active 19 | /\ Activate(chain) 20 | 21 | \* node becomes inactive on [chain] 22 | Deactivate(chain) == 23 | /\ node_active' = node_active \ {chain} 24 | /\ UNCHANGED <> 25 | /\ UNCHANGED <> 26 | 27 | \* if node is inactive on some chain, node can become inactive 28 | Deactivation == 29 | \E chain \in activeChains : 30 | /\ chain \in node_active 31 | /\ Deactivate(chain) 32 | 33 | ============================================================================= 34 | -------------------------------------------------------------------------------- /p2p/scheduler/Scheduler.toolbox/Scheduler/MC.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC ---- 2 | EXTENDS Scheduler, TLC 3 | 4 | \* MV CONSTANT declarations@modelParameterConstants 5 | CONSTANTS 6 | a 7 | ---- 8 | 9 | \* MV CONSTANT definitions Messages 10 | const_16092824186411304000 == 11 | {a} 12 | ---- 13 | 14 | \* CONSTANT definitions @modelParameterConstants:0HL 15 | const_16092824186411305000 == 16 | 2 17 | ---- 18 | 19 | \* CONSTANT definitions @modelParameterConstants:1IO 20 | const_16092824186411306000 == 21 | 2 22 | ---- 23 | 24 | \* CONSTANT definitions @modelParameterConstants:2M 25 | const_16092824186411307000 == 26 | 2 27 | ---- 28 | 29 | \* CONSTANT definitions @modelParameterConstants:3N 30 | const_16092824186411308000 == 31 | 2 32 | ---- 33 | 34 | \* CONSTANT definitions @modelParameterConstants:4Q 35 | const_16092824186411309000 == 36 | 2 37 | ---- 38 | 39 | \* CONSTANT definitions @modelParameterConstants:5S 40 | const_16092824186411310000 == 41 | 2 42 | ---- 43 | 44 | \* CONSTANT definitions @modelParameterConstants:6Max_read 45 | const_16092824186411311000 == 46 | 3 47 | ---- 48 | 49 | \* CONSTANT definitions @modelParameterConstants:9Max_write 50 | const_16092824186411312000 == 51 | 3 52 | ---- 53 | 54 | ============================================================================= 55 | -------------------------------------------------------------------------------- /shell/bootstrapping/automate/gen_java.py: -------------------------------------------------------------------------------- 1 | # Generate the java collection of all action names 2 | 3 | import os 4 | 5 | def generateJavaClassAndCompile(actionNames, nodeActionsFile, nodeActionsJar): 6 | 7 | javaHeader = '''\ 8 | package nodeActions; 9 | import java.util.*; 10 | 11 | public class NodeActions { 12 | 13 | ''' 14 | 15 | def mkJavaString(name): 16 | return ' public static final String {name} = new String("{name}");\n'.format(name=name) 17 | 18 | javaActionDecls = '' 19 | 20 | for name in actionNames: 21 | javaActionDecls += mkJavaString(name) 22 | 23 | allActionsMethod = '''\ 24 | 25 | public static Set allActions() { 26 | Set acts = new HashSet(); 27 | ''' 28 | 29 | def addToSet(obj): 30 | return ' acts.add({obj});\n'.format(obj=obj) 31 | 32 | for name in actionNames: 33 | allActionsMethod += addToSet(name) 34 | 35 | allActionsMethod += '''\ 36 | return acts; 37 | } 38 | } 39 | ''' 40 | 41 | # write NodeActions java class 42 | fw = open(nodeActionsFile, 'w') 43 | fw.write(javaHeader + javaActionDecls + allActionsMethod) 44 | fw.close() 45 | 46 | # compile NodeActions 47 | os.system('javac {file}'.format(file=nodeActionsFile)) 48 | os.system('jar cvf {jar} *'.format(jar=nodeActionsJar)) 49 | -------------------------------------------------------------------------------- /consensus/Emmy/Emmy_plus_safety.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Emmy_plus_safety ---- 2 | 3 | EXTENDS Consensus 4 | 5 | Rolls == 0..9 6 | Delegates == 1..5 7 | 8 | Max_bake == 2 9 | Max_cycle == 3 10 | Max_delay == 5 11 | Max_endorse == 4 12 | Min_endorse == 1 13 | Max_time == 10 14 | Max_balance == 1000 15 | Max_deposit == 20 16 | Max_reward == 100 17 | Min_block_delay == 1 18 | Baking_delay == 2 19 | Endorsement_delay == 1 20 | Initial_endorsers == 2 21 | Tokens_per_roll == 300 22 | Blocks_per_cycle == 3 23 | \* Blocks_per_snapshot == 1 24 | Init_balance == [ d \in Delegates |-> 200 ] 25 | Init_rolls_snapshot == [ d \in Delegates |-> {} ] 26 | Init_safety_deposit == [ d \in Delegates |-> 100 ] 27 | 28 | level_rewards_prio_zero == 40 29 | level_rewards_prio_nonzero == 3 30 | 31 | Baking_priority == {} \* TODO 32 | Endorsement_rights == {} \* TODO 33 | 34 | emmy_plus_delay(p, e) == 35 | Min_block_delay + Baking_delay * p + Endorsement_delay * max(0, Initial_endorsers - e) 36 | 37 | baking_reward_(c, bs, r) == 38 | LET p == baking_priority(c, bs, r) 39 | e == endorsements[c][bs][r] 40 | IN 41 | IF p = 0 THEN ((level_rewards_prio_zero \div 2) * e) \div MAX_ENDORSE 42 | ELSE (level_rewards_prio_nonzero * e) \div MAX_ENDORSE 43 | 44 | endorsing_reward(c, bs, r) == 45 | LET p == baking_priority(c, bs, r) IN 46 | IF p = 0 THEN baking_reward_(c, bs, r) 47 | ELSE (baking_reward_(c, bs, r) * 2) \div 3 48 | 49 | \* Baking_reward[c][bs][d] == {} \* TODO 50 | 51 | \* Endorsement_reward[c][bs][d] == {} \* TODO 52 | 53 | ================================= 54 | -------------------------------------------------------------------------------- /shell/bootstrapping/ActionTraceChecker.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE ActionTraceChecker ---- 2 | 3 | (* Action trace checker spec *) 4 | 5 | EXTENDS ActionTranslator, Parser 6 | 7 | \* action trace reader variables 8 | VARIABLES 9 | i, 10 | action 11 | 12 | tvars == <> 13 | 14 | \* supply file path 15 | ActionTrace == parse("./test/test3.test") 16 | 17 | InitTrace == 18 | /\ i = 1 19 | /\ action = ActionTrace[1] 20 | 21 | ReadNextAction == 22 | \* more actions to read and apply 23 | \/ /\ i < Len(ActionTrace) 24 | /\ i' = i + 1 25 | /\ action' = ActionTrace[i'] 26 | \* we've applied the last action in the trace 27 | \/ /\ i = Len(ActionTrace) 28 | /\ i' = i + 1 29 | /\ action' = "Done" 30 | 31 | NextTrace == 32 | /\ ReadNextAction 33 | /\ ActionTranslator(action) 34 | 35 | ---- 36 | 37 | \* Compose spec and reader next actions 38 | Compose(NextA, varsA, NextB, varsB) == 39 | \/ NextA /\ NextB 40 | \/ UNCHANGED varsB /\ NextA 41 | \/ UNCHANGED varsA /\ NextB 42 | 43 | ComposedNext == Compose(Next, vars, NextTrace, tvars) 44 | 45 | ComposedSpec == 46 | /\ Init 47 | /\ InitTrace 48 | /\ [][ComposedNext]_<> 49 | 50 | \* this invariant will be: 51 | \* - satisfied by an incorrect trace 52 | \* - violated by a correct trace 53 | Incorrect == i <= Len(ActionTrace) 54 | 55 | \* this property will be: 56 | \* - violated by an incorrect trace 57 | \* - satisfied by a correct trace 58 | Finished == 59 | \/ ENABLED ComposedNext 60 | \/ action = "Done" 61 | 62 | ======================================= 63 | -------------------------------------------------------------------------------- /consensus/Emmy/README.md: -------------------------------------------------------------------------------- 1 | # Emmy family specification 2 | 3 | For more information about the Emmy family of consensus protocols, see [Emmy_protocol_details](./Emmy_family_details.md) 4 | 5 | ## Spec design 6 | 7 | There are two phases for each `cycle`: 8 | - `active` - occurs in every block slot of the cycle 9 | - `cycle_admin` - only occurs in the last block slot of the cycle 10 | 11 | Assume we are in block slot `bs` of cycle `c`: 12 | 13 | In the `active` phase, bakers (roll ids) can bake blocks (represented by `<>`) according to the priority found in `BAKING_PRIORITY[c][bs]`. A baker's priority determines when they are eligible to bake a block wrt the time of the latest block they know of (which can be from baking or endorsing). 14 | 15 | For each block slot in each cycle, `MAX_BAKE` baking slots are assigned. Once a block has been baked in block slot `bs`, the endorsers for the this block slot can start endorsing a block. Endorsers also add their endorsed block to their chain (the variable `delegate_blocks`). For each block slot in each cycle, `MAX_ENDORSE` endorsement slots are assigned. Any endorser in `ENDORSEMENT_RIGHTS[c][bs]` can endorse a block in this slot. Once the block delay has been met, bakers in the next slot can bake their blocks. `time` progresses during this phase. 16 | 17 | In the last block slot of a cycle, after baking some blocks and a sufficient number of endorsers have endorsed a block, we can move to the `cycle_admin` phase. 18 | 19 | In the `cycle_admin` phase, baking rewards and endorsements rewards are calculated and debited to the coresponding accounts and rolls are managed. `time` does not progress during this phase. Once the rewards have been paid and rolls managed, we increment the `cycle` and move to the `active` phase. 20 | -------------------------------------------------------------------------------- /shell/mempool/MC_safety.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_safety ---- 2 | 3 | EXTENDS Mempool_global, TLC 4 | 5 | NN == 3 6 | 7 | char(n) == 8 | CASE n = 1 -> "a" 9 | [] n = 2 -> "b" 10 | [] n = 3 -> "c" 11 | [] n = 4 -> "d" 12 | [] n = 5 -> "e" 13 | 14 | int_of_char(c) == 15 | CASE c = "a" -> 1 16 | [] c = "b" -> 2 17 | [] c = "c" -> 3 18 | [] c = "d" -> 4 19 | [] c = "e" -> 5 20 | 21 | Ns == Map_set(1..NN, char) 22 | 23 | exclude(n) == {n, char((int_of_char(n) % Cardinality(Ns)) + 1)} 24 | 25 | ---- 26 | 27 | Init_peers[ n \in Ns ] == Ns \ {n} 28 | 29 | \* NN = 2 30 | \* Init_connections[ n \in Ns ] == Ns \ {n} 31 | 32 | \* NN = 3 33 | \* a --- b --- c 34 | Init_connections[ n \in Ns ] == IF n /= "b" THEN {"b"} ELSE {"a", "c"} 35 | 36 | \* NN = 5 37 | \* Init_connections[ n \in Ns ] == 38 | \* CASE n = "a" -> {"b", "c"} 39 | \* [] n = "b" -> {"a", "c"} 40 | \* [] n = "c" -> {"a", "b", "d"} 41 | \* [] n = "d" -> {"c", "e"} 42 | \* [] n = "e" -> {"d"} 43 | 44 | Init_predecessor[ n \in Ns ] == block(0, <<>>) 45 | 46 | Max_hops == 3 47 | 48 | Min_connections == 1 49 | 50 | Max_connections == 4 51 | 52 | Min_endorsements == 2 53 | 54 | Max_hash == 25 55 | 56 | View == [ 57 | shell |-> [ 58 | peers |-> peers, 59 | connections |-> connections, 60 | messages |-> messages 61 | ], 62 | pv |-> [ 63 | predecessor |-> predecessor, 64 | branch_delayed |-> branch_delayed, 65 | branch_refused |-> branch_refused, 66 | refused |-> refused, 67 | pending |-> pending, 68 | advertisement |-> advertisement 69 | ], 70 | mp |-> [ 71 | known_valid |-> known_valid, 72 | mp_pending |-> mp_pending 73 | ] 74 | ] 75 | 76 | ========================== 77 | -------------------------------------------------------------------------------- /shell/mempool/MC_liveness.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_liveness ---- 2 | 3 | EXTENDS Mempool_global, TLC 4 | 5 | NN == 3 6 | 7 | char(n) == 8 | CASE n = 1 -> "a" 9 | [] n = 2 -> "b" 10 | [] n = 3 -> "c" 11 | [] n = 4 -> "d" 12 | [] n = 5 -> "e" 13 | 14 | int_of_char(c) == 15 | CASE c = "a" -> 1 16 | [] c = "b" -> 2 17 | [] c = "c" -> 3 18 | [] c = "d" -> 4 19 | [] c = "e" -> 5 20 | 21 | Ns == Map_set(1..NN, char) 22 | 23 | exclude(n) == {n, char((int_of_char(n) % Cardinality(Ns)) + 1)} 24 | 25 | ---- 26 | 27 | Init_peers[ n \in Ns ] == Ns \ {n} 28 | 29 | \* NN = 2 30 | \* Init_connections[ n \in Ns ] == Ns \ {n} 31 | 32 | \* NN = 3 33 | \* a --- b --- c 34 | Init_connections[ n \in Ns ] == IF n /= "b" THEN {"b"} ELSE {"a", "c"} 35 | 36 | \* NN = 5 37 | \* Init_connections[ n \in Ns ] == 38 | \* CASE n = "a" -> {"b", "c"} 39 | \* [] n = "b" -> {"a", "c"} 40 | \* [] n = "c" -> {"a", "b", "d"} 41 | \* [] n = "d" -> {"c", "e"} 42 | \* [] n = "e" -> {"d"} 43 | 44 | Init_predecessor[ n \in Ns ] == block(0, <<>>) 45 | 46 | Max_hops == 3 47 | 48 | Min_connections == 1 49 | 50 | Max_connections == 4 51 | 52 | Min_endorsements == 2 53 | 54 | Max_hash == 25 55 | 56 | View == [ 57 | shell |-> [ 58 | peers |-> peers, 59 | connections |-> connections, 60 | messages |-> messages 61 | ], 62 | pv |-> [ 63 | predecessor |-> predecessor, 64 | branch_delayed |-> branch_delayed, 65 | branch_refused |-> branch_refused, 66 | refused |-> refused, 67 | pending |-> pending, 68 | advertisement |-> advertisement 69 | ], 70 | mp |-> [ 71 | known_valid |-> known_valid, 72 | mp_pending |-> mp_pending 73 | ] 74 | ] 75 | 76 | ============================ 77 | -------------------------------------------------------------------------------- /p2p/handshaking/MC_safety.out: -------------------------------------------------------------------------------- 1 | $ tlc MC_safety.tla -workers 4096 -deadlock 2 | TLC2 Version 2.15 of Day Month 20?? (rev: eb3ff99) 3 | Running breadth-first search Model-Checking with fp 128 and seed 217741586123855676 with 4096 workers on 64 cores with 27305MB heap and 64MB offheap memory [pid: 35559] (Linux 5.3.0-64-generic amd64, Ubuntu 11.0.7 x86_64, MSBDiskFPSet, DiskStateQueue). 4 | Parsing file /home/tla/models/handshaking/blacklist_timeouts/nack_peers/MC_safety.tla 5 | Parsing file /home/tla/models/handshaking/blacklist_timeouts/nack_peers/Handshaking_nack_peers.tla 6 | Parsing file /tmp/TLC.tla 7 | Parsing file /tmp/FiniteSets.tla 8 | Parsing file /tmp/Naturals.tla 9 | Parsing file /tmp/Sequences.tla 10 | Semantic processing of module Naturals 11 | Semantic processing of module Sequences 12 | Semantic processing of module FiniteSets 13 | Semantic processing of module Handshaking_nack_peers 14 | Semantic processing of module TLC 15 | Semantic processing of module MC_safety 16 | Starting... (2021-04-20 01:22:35) 17 | Computing initial states... 18 | Finished computing initial states: 1 distinct state generated at 2021-04-20 01:22:35. 19 | Progress(16) at 2021-04-20 01:22:43: 7,782,455 states generated (7,782,455 s/min), 678,479 distinct states found (678,479 ds/min), 227,964 states left on queue. 20 | Model checking completed. No error has been found. 21 | Estimates of the probability that TLC did not check all reachable states 22 | because two distinct states had the same fingerprint: 23 | calculated (optimistic): val = 1.1E-5 24 | based on the actual fingerprints: val = 8.3E-7 25 | 64276179 states generated, 3389508 distinct states found, 0 states left on queue. 26 | The depth of the complete state graph search is 32. 27 | The average outdegree of the complete state graph is 1 (minimum is 0, the maximum 14 and the 95th percentile is 4). 28 | Finished in 33s at (2021-04-20 01:23:08) 29 | -------------------------------------------------------------------------------- /shell/high_level/README.md: -------------------------------------------------------------------------------- 1 | # High Level Handshaking and Bootstrapping Model 2 | 3 | ## Assumptions/Simplifications 4 | 5 | - no notion of different chains or protocols 6 | - no blocks/headers/operations, just abstract states 7 | - no explicit scheduling for message passing 8 | - once peers are obtained, they do not change 9 | - fixed set of nodes, i.e. nodes do not activate/deactivate 10 | - once nodes have a secure connection, they keep it forever 11 | - once a joining node has sufficiently many secure connections, they do not gain or lose any 12 | - bootstrapping nodes only request state from one established node at a time 13 | - no advertisement of states 14 | 15 | ## Requesting Peers 16 | 17 | Joining nodes request peers atomically. They get a set of peers all at once. 18 | 19 | ## Handshaking process 20 | 21 | Secure connections between joining nodes and established nodes are made one by one. 22 | 23 | ## Bootstrapping process 24 | 25 | Once a joining node has connected to sufficiently many peers (established nodes), they can begin bootstrapping. Once in the bootstrapping phase, a joining node requests the current state from any of their connections (established nodes). Joining nodes only communicate with established nodes and established nodes only communicate with joining nodes. 26 | 27 | ### Messages 28 | 29 | - joining nodes only send `Get_current_state` and `Ack_current_state` messages to established nodes 30 | - established nodes only send `Current_state` messages in response to a `Get_current_state` message from a joining node 31 | 32 | Each node has 3 queues for message passing: 33 | 34 | - `mailbox`: queue of messages sent to the given node 35 | - `sent`: queue of messages sent by the given node 36 | - `recv`: queue of messages the node has received (these messages are "consumed" and responded to accordingly by the `Handle` action) 37 | 38 | The lengths of these queues are all bounded by the constant `sizeBound`. 39 | -------------------------------------------------------------------------------- /shell/distributed_db/DB_Activation.tla: -------------------------------------------------------------------------------- 1 | --------------------------- MODULE DB_Activation ---------------------------- 2 | 3 | CONSTANTS numChains, numNodes, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, blocks, branch, chains, mailbox, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | LOCAL INSTANCE Utils 11 | 12 | ---------------------------------------------------------------------------- 13 | 14 | (*******************************) 15 | (* Activate/Deactivate actions *) 16 | (*******************************) 17 | 18 | \* [node] becomes active on [chain] 19 | \* [node] immediately receives current system branch on [chain] 20 | Activate(node, chain) == 21 | LET welcome_msg == Msg(sys, node, "Current_branch", [ branch |-> branch[chain] ]) 22 | IN /\ active' = [ active EXCEPT ![chain] = @ \cup {node} ] 23 | /\ Send(sys, chain, welcome_msg) 24 | /\ node_active' = [ node_active EXCEPT ![node] = @ \cup {chain} ] 25 | /\ UNCHANGED <> 26 | /\ UNCHANGED <> 28 | 29 | \* An inactive node on some chain becomes active 30 | Activation == 31 | \E chain \in activeChains : 32 | \E node \in inactiveNodes[chain] : Activate(node, chain) 33 | 34 | \* [node] becomes inactive on [chain] 35 | \* [node] immediately drops all [chain] messages 36 | Deactivate(node, chain) == 37 | /\ active' = [ active EXCEPT ![chain] = @ \ {node} ] 38 | /\ node_active' = [ node_active EXCEPT ![node] = @ \ {chain} ] 39 | /\ UNCHANGED <> 40 | /\ UNCHANGED <> 42 | 43 | \* An active node on some chain becomes inactive 44 | Deactivation == 45 | \E chain \in activeChains : 46 | \E node \in activeNodes[chain] : Deactivate(node, chain) 47 | 48 | ============================================================================= 49 | -------------------------------------------------------------------------------- /shell/distributed_db/DistributedDB.toolbox/Model_1/DB_Activation.tla: -------------------------------------------------------------------------------- 1 | --------------------------- MODULE DB_Activation ---------------------------- 2 | 3 | CONSTANTS numChains, numNodes, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, blocks, branch, chains, mailbox, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | LOCAL INSTANCE Utils 11 | 12 | ---------------------------------------------------------------------------- 13 | 14 | (*******************************) 15 | (* Activate/Deactivate actions *) 16 | (*******************************) 17 | 18 | \* [node] becomes active on [chain] 19 | \* [node] immediately receives current system branch on [chain] 20 | Activate(node, chain) == 21 | LET welcome_msg == Msg(sys, node, "Current_branch", [ branch |-> branch[chain] ]) 22 | IN /\ active' = [ active EXCEPT ![chain] = @ \cup {node} ] 23 | /\ Send(sys, chain, welcome_msg) 24 | /\ node_active' = [ node_active EXCEPT ![node] = @ \cup {chain} ] 25 | /\ UNCHANGED <> 26 | /\ UNCHANGED <> 28 | 29 | \* An inactive node on some chain becomes active 30 | Activation == 31 | \E chain \in activeChains : 32 | \E node \in inactiveNodes[chain] : Activate(node, chain) 33 | 34 | \* [node] becomes inactive on [chain] 35 | \* [node] immediately drops all [chain] messages 36 | Deactivate(node, chain) == 37 | /\ active' = [ active EXCEPT ![chain] = @ \ {node} ] 38 | /\ node_active' = [ node_active EXCEPT ![node] = @ \ {chain} ] 39 | /\ UNCHANGED <> 40 | /\ UNCHANGED <> 42 | 43 | \* An active node on some chain becomes inactive 44 | Deactivation == 45 | \E chain \in activeChains : 46 | \E node \in activeNodes[chain] : Deactivate(node, chain) 47 | 48 | ============================================================================= 49 | -------------------------------------------------------------------------------- /consensus/Emmy/Emmy_star_safety.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Emmy_star_safety ---- 2 | 3 | EXTENDS Consensus 4 | 5 | Rolls == 0..9 6 | Delegates == 1..5 7 | 8 | Max_bake == 2 9 | Max_cycle == 3 10 | Max_delay == 5 11 | Max_endorse == 4 12 | Min_endorse == 1 13 | Max_time == 10 14 | Max_balance == 1000 15 | Max_deposit == 20 16 | Max_reward == 100 17 | 18 | \* block delay 19 | Min_block_delay == 1 20 | Baking_delay == 2 21 | Endorsement_delay == 1 22 | Initial_endorsers == 2 23 | 24 | Tokens_per_roll == 300 25 | Blocks_per_cycle == 3 26 | \* Blocks_per_snapshot == 1 27 | Init_balance == [ d \in Delegates |-> 200 ] 28 | Init_rolls_snapshot == [ d \in Delegates |-> 29 | LET n == 2 * (d - 1) IN 30 | n..(n + 1) ] 31 | Init_safety_deposit == [ d \in Delegates |-> 100 ] 32 | 33 | level_rewards_prio_zero == 40 34 | level_rewards_prio_nonzero == 3 35 | 36 | emmy_plus_delay(p, e) == 37 | Min_block_delay + Baking_delay * p + Endorsement_delay * max(0, Initial_endorsers - e) 38 | 39 | emmy_star_delay(p, e) == 40 | IF p = 0 /\ 5 * e >= 3 * Max_endorse THEN Min_block_delay 41 | ELSE emmy_plus_delay(p, e) 42 | 43 | Block_delay[ p \in 0..(Max_bake - 1) ] == [ e \in 0..Max_endorse |-> 44 | Min_block_delay + Baking_delay * p + Endorsement_delay * max(0, Initial_endorsers - e) 45 | ] 46 | 47 | baking_reward_(c, bs, r) == 48 | LET p == baking_priority(c, bs, r) 49 | e == endorsements[c][bs][r] 50 | IN 51 | IF p = 0 THEN ((level_rewards_prio_zero \div 2) * e) \div Max_endorse 52 | ELSE (level_rewards_prio_nonzero * e) \div Max_endorse 53 | 54 | endorsing_reward(c, bs, r) == 55 | LET p == baking_priority(c, bs, r) IN 56 | IF p = 0 THEN baking_reward_(c, bs, r) 57 | ELSE (baking_reward_(c, bs, r) * 2) \div 3 58 | 59 | \* TODO 60 | \* find all rolls controlled by delegate 61 | \* find lowest priority baking roll [r] 62 | \* 63 | \* cycle -> block_slot -> delegate -> int 64 | Baking_reward[ c \in 0..Max_cycle ] == 65 | [ bs \in 0..(Blocks_per_cycle - 1) |-> 66 | [ d \in Delegates |-> 67 | 0 68 | ] 69 | ] 70 | 71 | \* cycle -> block_slot -> delegate -> int 72 | Endorsement_reward[ c \in 0..Max_cycle ] == 73 | [ bs \in 0..(Blocks_per_cycle - 1) |-> 74 | [ d \in Delegates |-> 75 | 0 76 | ] 77 | ] 78 | 79 | Baking_priority == {} \* TODO 80 | Endorsement_rights == {} \* TODO 81 | 82 | ================================= 83 | -------------------------------------------------------------------------------- /shell/mempool/Topology.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE Topology ---- 2 | 3 | EXTENDS FiniteSets, Naturals, Sequences, Utils 4 | 5 | \* defined via refinement mapping upon instantiation 6 | CONSTANTS 7 | NONE, 8 | Nodes, 9 | connections \* set of each node's connections 10 | 11 | ---- 12 | 13 | \* lte(NONE, _) = FALSE 14 | \* lte(_, NONE) = TRUE 15 | \* lte(x, y) = x <= y 16 | lte(x, y) == 17 | /\ x /= NONE 18 | /\ \/ y = NONE 19 | \/ x <= y 20 | 21 | RECURSIVE _max_set(_, _) 22 | _max_set(S, n) == 23 | IF n = NONE \/ S = {} THEN n 24 | ELSE 25 | LET x == Pick(S) IN 26 | IF lte(x, n) THEN _max_set(S \ {x}, n) 27 | ELSE _max_set(S \ {x}, x) 28 | 29 | Max(S) == 30 | IF S = {} THEN NONE 31 | ELSE 32 | LET x == Pick(S) IN 33 | _max_set(S \ {x}, x) 34 | 35 | \* Every node in S is directly connected to another node in S 36 | Weakly_connected(S) == \A x \in S : \E y \in S : y \in connections[x] 37 | 38 | \* x and y are connected by p : x = p[1] <-> ... <-> y = p[n] 39 | connected_by_path(x, y, p) == 40 | LET n == Len(p) IN 41 | /\ n > 1 42 | /\ x = p[1] 43 | /\ y = p[n] 44 | /\ \A i \in 1..(n - 1) : p[i] \in connections[p[i + 1]] 45 | 46 | \* length of a minimal path connecting x to y, excluding x and y 47 | RECURSIVE min_path_len(_, _, _, _) 48 | min_path_len(x, y, S, n) == 49 | CASE n = 2 /\ y \in connections[x] -> 1 50 | [] n > Cardinality(S) -> NONE 51 | [] OTHER -> 52 | IF \E p \in SeqOfLen(S, n) : connected_by_path(x, y, p) THEN n - 1 53 | ELSE min_path_len(x, y, S, n + 1) 54 | 55 | Min_path_len(x, y) == min_path_len(x, y, Nodes, 2) 56 | 57 | \* a minimal path connecting x to y 58 | RECURSIVE min_path(_, _, _) 59 | min_path(x, y, S) == 60 | LET n == min_path_len(x, y, S, 2) IN 61 | CASE n = NONE -> <<>> 62 | [] n = 0 -> <> 63 | [] OTHER -> 64 | LET inter == CHOOSE p \in SeqOfLen(S, n) : connected_by_path(x, y, Append(Cons(x, p), y)) IN 65 | Append(Cons(x, inter), y) 66 | 67 | Min_path(x, y) == 68 | IF y \in connections[x] THEN <<>> 69 | ELSE min_path(x, y, Nodes) 70 | 71 | \* maximum length of the minimal paths originating from x 72 | Max_path(x, S) == 73 | LET min_paths == { Min_path_len(x, y) : y \in S } IN 74 | Max(min_paths) 75 | 76 | \* longest minimal path connecting any two points of S 77 | Max_path_len(S) == Max({ Max_path(x, S \ {x}) : x \in S }) 78 | 79 | \* subsets of S which have max path length <= n 80 | Connected(n, S) == { ss \in SUBSET S : lte(Max_path_len(ss), n) } 81 | 82 | ========================= 83 | -------------------------------------------------------------------------------- /shell/mempool/README.md: -------------------------------------------------------------------------------- 1 | # Mempool specification 2 | 3 | This is the formal specification for the Tezedge node's mempool. The main focus is to verify desirable liveness properties of endorsement propagation, specifcally that, in the absence of complete network failures, all nodes will eventually see each endorsement. 4 | 5 | This directory contains two main TLA+ specifications: `Mempool` and `Mempool_global`. `Mempool` is a local spec; it only focuses on a single correct node and makes claims about only that node's behavior. `Mempool_global` is a global spec; it takes into consideration the entire network and the nodes' collective behavior. As always, the TLA+ specification models the protocol as a state machine. 6 | 7 | ## Mempool_global spec 8 | 9 | This spec tracks all nodes in the network, i.e. a state is determined by the aggregation of all node variables. In this way we can verify global properties of the network behavior. 10 | 11 | Each node participates in the propagation of operations on the P2P layer and keeps a local chain of blocks based on the messages they receive. Nodes aggregate and propagate operations via their *mempool*, a data structure consisting of an ordered collection of "known valid" operations and an unordered collection of "pending" operations. 12 | 13 | Each node's shell has a prevalidator which classifies pending operations into one of four sets: `applied`, `branch_delayed`, `branch_refused`, and `refused`. Applied operations are those which have been applied. Branch delayed operations are those which are for a block in the future on the node's current branch. Branch refused operations are for a different branch than the node's current branch. Refused operations are not valid for any branch. 14 | 15 | Nodes communicate via the typical P2P layer messages: `Current_head`, `Get_current_head`, etc. 16 | 17 | ### Mempool spec 18 | 19 | This spec only tracks the local information of a single node, i.e. the state is determined by only this one node's variables. The purpose of this spec is to use it for trace checking the behavior from an actual Tezedge node. We do this to gain confidence about the conformance of our source code with the specification. 20 | 21 | ## Endorsement propagation 22 | 23 | The `Mempool_global` spec satisfies several [liveness properties](./Mempool_global.tla#L465). The most important of which being `EndorsementPropagation`. This property says that all (valid) endorsement operations will eventually be included in a block in every node's local chain. 24 | 25 | ## Run the code = verify the spec's properties 26 | 27 | To verify all the liveness properties of the spec using TLC, 28 | 29 | 1. Clone the repo 30 | 2. From the mempool directory (/shell/mempool), do `tlc MC_liveness.tla` 31 | -------------------------------------------------------------------------------- /shell/bootstrapping/MC_liveness.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_liveness ---- 2 | 3 | EXTENDS Bootstrap, TLC 4 | 5 | Bad_nodes == 0..0 6 | 7 | Good_nodes == 1..2 8 | 9 | Bad_bootstrapping == 3..3 10 | 11 | Good_bootstrapping == 4..4 12 | 13 | Min_peers == 1 14 | 15 | Max_peers == 2 16 | 17 | Max_level == 2 18 | 19 | Max_ops == 2 20 | 21 | Threshold == 0 22 | 23 | \* block 0 = genesis 24 | \* block 1 25 | \* header(level, predecessor, context, fitness, ops_hash) 26 | LOCAL ctx1 == hash_nums(0, 0) 27 | LOCAL hd1 == header(1, 0, ctx1, 0, 1) 28 | LOCAL hsh1 == hash(hd1) 29 | LOCAL ops1 == operations(hsh1, 0..0) 30 | LOCAL fit1 == 1 31 | LOCAL b1 == block(hd1, ops1) 32 | \* block 2 33 | LOCAL ctx2 == hash_nums(ctx1, hsh1) 34 | LOCAL hd2 == header(2, hsh1, ctx2, 0, 2) 35 | LOCAL hsh2 == hash(hd2) 36 | LOCAL ops2 == operations(hsh2, 0..1) 37 | LOCAL fit2 == 2 38 | LOCAL b2 == block(hd2, ops2) 39 | 40 | \* Good_nodes -> Headers 41 | Current_head[ n \in Good_nodes ] == hd2 42 | 43 | \* Good_nodes -> SUBSET Blocks 44 | Good_node_blocks == 45 | LET chain == <> IN 46 | [ n \in Good_nodes |-> chain ] 47 | 48 | All_good_node_blocks == UNION { ToSet(Good_node_blocks[n]) : n \in GOOD_NODES } 49 | 50 | Good_node_levels[ n \in Good_nodes ] == { b.header.level : b \in ToSet(Good_node_blocks[n]) } 51 | Good_node_max_level[ n \in Good_nodes ] == Max_set(Good_node_levels[n]) 52 | 53 | \* BLOCKS[n]: b0 <- b1 <- b2 <- ... 54 | 55 | node_blocks_at_level(n, l) == { b \in ToSet(Good_node_blocks[n]) : b.header.level = l } 56 | 57 | Block_hashes[ n \in Good_nodes ] == UNION { node_blocks_at_level(n, l) : l \in Levels } 58 | 59 | block_hash_level[ n \in Good_nodes, l \in Levels ] == 60 | LET L == Max_set(Good_node_levels[n]) IN 61 | [ ll \in 1..L |-> 62 | LET b(_l) == 63 | LET blocks == node_blocks_at_level(n, _l) IN 64 | IF blocks = {} THEN genesis 65 | ELSE Pick(blocks) 66 | IN 67 | hash(b(ll).header) 68 | ] 69 | 70 | Validator == [ b \in Blocks |-> 71 | CASE b \in All_good_node_blocks -> "known_valid" 72 | [] hash(b) > Cardinality(BlockHashes) \div 2 -> "known_invalid" 73 | [] OTHER -> "unknown" ] 74 | 75 | Node_samples[ n \in Good_nodes, bn \in (Bad_bootstrapping \cup Good_bootstrapping) ] == 76 | LET length == Cardinality(BLOCKS[n]) 77 | levels == 78 | Pick({ s \in Seq(Good_node_levels) : 79 | \E L \in 1..length : 80 | /\ DOMAIN s = 1..L 81 | /\ Len(s) >= length \div 2 82 | /\ Len(s) <= length 83 | /\ \A i \in DOMAIN s \ {1} : s[i - 1] < s[i] }) 84 | IN 85 | Map(LAMBDA l : <>, levels) 86 | 87 | ============================ 88 | -------------------------------------------------------------------------------- /shell/bootstrapping/MC_safety.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_safety ---- 2 | 3 | EXTENDS Bootstrap, TLC 4 | 5 | Bad_nodes == 0..0 6 | 7 | Good_nodes == 1..1 8 | 9 | Bad_bootstrapping == 2..2 10 | 11 | Good_bootstrapping == 3..3 12 | 13 | Min_peers == 1 14 | 15 | Max_peers == 2 16 | 17 | Max_level == 2 18 | 19 | Max_ops == 2 20 | 21 | \* header(level, predecessor, context, fitness, ops_hash) 22 | LOCAL ctx1 == hash(<<0, 0>>) 23 | LOCAL hd1 == header(1, 0, ctx1, 0, 1) 24 | LOCAL hsh1 == hash(hd1) 25 | LOCAL ops1 == operations(hsh1, 0..0) 26 | LOCAL fit1 == 1 27 | LOCAL b1 == block(hd1, ops1) 28 | \* block 2 29 | LOCAL ctx2 == hash(<>) 30 | LOCAL hd2 == header(2, hsh1, ctx2, 0, 2) 31 | LOCAL hsh2 == hash(hd2) 32 | LOCAL ops2 == operations(hsh2, 0..1) 33 | LOCAL fit2 == 2 34 | LOCAL b2 == block(hd2, ops2) 35 | 36 | \* Good_nodes -> Headers 37 | Current_head == 1 :> hd2 38 | 39 | \* Good_nodes -> SUBSET Blocks 40 | Good_node_blocks == 1 :> <> 41 | 42 | All_good_node_blocks == UNION { ToSet(Good_node_blocks[n]) : n \in GOOD_NODES } 43 | 44 | Good_node_levels[ n \in Good_nodes ] == { b.header.level : b \in ToSet(Good_node_blocks[n]) } 45 | 46 | Good_node_max_level[ n \in Good_nodes ] == Max_set(Good_node_levels[n]) 47 | 48 | \* Merkle tree 49 | \* 50 | \* ... . 51 | \* / \ 52 | \* / \ 53 | \* level: 2 h20 . 54 | \* / \ / \ 55 | \* / \ / \ 56 | \* level: 1 h10 h11 . 57 | \* / \ / \ / \ 58 | \* / \ / \ / \ 59 | \* level: 0 h00 h01 h02 . 60 | \* | | | | 61 | \* BLOCKS[n] b0 <- b1 <- b2 <- ... 62 | 63 | MerkleTree == [ n \in Good_nodes |-> 64 | [ l \in Levels |-> 65 | LET h00 == hash(gen_header) 66 | h01 == hash(hd1) 67 | h02 == hash(hd2) 68 | h10 == hash(<>) 69 | h11 == hash(<>) 70 | h20 == hash(<>) 71 | IN 72 | CASE l = 2 -> <> 73 | [] l = 1 -> <> 74 | [] l = 0 -> <> 75 | ] 76 | ] 77 | 78 | Validator == [ b \in AllBlocks |-> "unknown" ] 79 | 80 | \* Node_samples == [ 81 | \* n \in Good_nodes |-> 82 | \* LET length == Cardinality(BLOCKS[n]) - 1 83 | \* levels == Pick({ s \in Seq(Good_node_levels) : 84 | \* /\ Len(s) >= length \div 2 85 | \* /\ Len(s) <= length 86 | \* /\ \A i \in DOMAIN s \ {1} : s[i - 1] < s[i] }) 87 | \* IN 88 | \* [ bn \in Bootstrapping_nodes |-> 89 | \* Map(LAMBDA l : MerkleTree[n][Good_node_max_level][l + 1], levels) 90 | \* ] 91 | \* ] 92 | 93 | ========================== 94 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/DB_Maintenance.tla: -------------------------------------------------------------------------------- 1 | -------------------------- MODULE DB_Maintenance --------------------------- 2 | 3 | EXTENDS DB_Defs 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (***********************) 8 | (* Maintenance actions *) 9 | (***********************) 10 | 11 | \* Block production 12 | Produce_block(chain, b, num_ops) == 13 | LET hgt == height[chain][b] + 1 \* next block height on branch 14 | header == Header(chain, b, hgt) 15 | block == Block(header, num_ops) 16 | IN \* add the new block to branch [b] on [chain] 17 | /\ blocks' = [ blocks EXCEPT ![chain][b] = Cons(block, @) ] \* add [block] to branch [b] 18 | /\ height' = [ height EXCEPT ![chain][b] = hgt ] \* increase height of branch [b] 19 | /\ UNCHANGED <> 20 | /\ UNCHANGED <> 21 | 22 | \* A block is produced on an existing branch of an existing chain 23 | New_block == 24 | \E chain \in activeChains : 25 | \E b \in activeBranches[chain] : 26 | LET num_ops == RandomElement(Op_nums) IN 27 | /\ height[chain][b] < sizeBound \* another block can be produced on branch [b] 28 | /\ Produce_block(chain, b, num_ops) \* create a new block on [chain] branch [b] 29 | 30 | \* Start a new branch on an existing [chain] with genesis block 31 | New_branch_on(chain) == 32 | LET b == branch[chain] + 1 33 | blk == Block(Header(chain, b, 0), 0) 34 | IN /\ blocks' = [ blocks EXCEPT ![chain][b] = <> ] 35 | /\ branch' = [ branch EXCEPT ![chain] = b ] 36 | /\ height' = [ height EXCEPT ![chain][b] = 0 ] 37 | /\ UNCHANGED chains 38 | /\ UNCHANGED <> 39 | 40 | \* A new branch is created on an existing chain 41 | New_branch == 42 | \E chain \in activeChains : 43 | /\ branch[chain] < sizeBound \* we have not reached the max branch [b] on [chain] 44 | /\ New_branch_on(chain) \* create a new branch on [chain] 45 | 46 | \* A new [chain] is created with branch 0 and genesis block and [sys] is active on [chain] 47 | New_chain == 48 | /\ chains < numChains \* another chain can be added 49 | /\ LET chain == chains + 1 50 | blk == Block(Header(chain, 0, 0), 0) 51 | IN /\ blocks' = [ blocks EXCEPT ![chain][0] = <> ] 52 | /\ branch' = [ branch EXCEPT ![chain] = 0 ] 53 | /\ chains' = chain 54 | /\ height' = [ height EXCEPT ![chain][0] = 0 ] 55 | /\ UNCHANGED <> 56 | 57 | ============================================================================= 58 | -------------------------------------------------------------------------------- /consensus/Tenderbake/README.md: -------------------------------------------------------------------------------- 1 | # Tenderbake specification 2 | 3 | For more information about Tenderbake and dynamic repeated consensus, see [Tenderbake](./Tenderbake.md) 4 | 5 | For the TLA+ spec, see [Tenderbake spec](./Tenderbake.tla) 6 | 7 | ## Spec design 8 | 9 | This specification follows the design of Tenderbake laid out in [Tendbake - A Solution to Dynamic Repeated Consenses for Blockchains](https://arxiv.org/abs/2001.11965). Liberal simplifications/abstractions are used to produce a tractable spec and will be explained below. As with all TLA+ specs, we specify the consensus protocol as an automaton (state machine). 10 | 11 | ### Possible actions of the state machine 12 | 13 | The spec contains both *correct* and *faulty* processes. Correct processes follow the protocol while faulty processes behave arbitrarily. We describe the actions allowed by correct processes. 14 | 15 | #### Propose 16 | 17 | At the beginning of each round, a designated committee member, called the *proposer*, can propagate a new block to be preendorsed, then endorsed by the committee. 18 | 19 | #### Preendorse 20 | 21 | After a value has been proposed, the committee members signal their intention to "lock" on this value by boradcasting preendorsement messages. 22 | 23 | #### Endorse 24 | 25 | If a member sees a quorum of preendorsement messages for a value, they broadcast an endorsement message for that value. If a member sees a quorum of endorsement messages for a value, they consider this value to be correct and add the block to their local chain. 26 | 27 | #### Observation 28 | 29 | Observation actions are only enabled for noncommittee processes, . The committee depends on the level, not all processes will be part of each committee. These observers simply handle the network messages and adjust any corresponding local information. 30 | 31 | #### Timeout 32 | 33 | At any point in the execution of the state machine, it is possible for a correct process to timeout. When this occurs, the process pulls chains from all other processes. 34 | 35 | ### Simplifications/assumptions 36 | 37 | - dynamic level comittees 38 | - committes depend only on the level 39 | - proposer depends on the round within the level 40 | - `n >= 3f + 1` where `n` is the number of bakers (correct + faulty processes) and `f` is the number of faulty bakers (processes) 41 | - all committee members have the ability to communicate with one another 42 | - bakers do not maintain or exchange mempools 43 | - chains are always pulled from all other processes (complete network topology) 44 | 45 | ## Run the code = verify the specification's properties 46 | 47 | The spec's properties can be found [here](./Tenderbake.tla#L1006). To verify these properties using TLC, 48 | 1. Clone the repo 49 | 2. From the Tenderbake directory (/consensus/Tenderbake), do `tlc MC_safety.tla` 50 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/DB_Maintenance.tla: -------------------------------------------------------------------------------- 1 | -------------------------- MODULE DB_Maintenance --------------------------- 2 | 3 | EXTENDS DB_Defs 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (***********************) 8 | (* Maintenance actions *) 9 | (***********************) 10 | 11 | \* Block production 12 | Produce_block(chain, b, num_ops) == 13 | LET hgt == height[chain][b] + 1 \* next block height on branch 14 | header == Header(chain, b, hgt) 15 | block == Block(header, num_ops) 16 | IN \* add the new block to branch [b] on [chain] 17 | /\ blocks' = [ blocks EXCEPT ![chain][b] = Cons(block, @) ] \* add [block] to branch [b] 18 | /\ height' = [ height EXCEPT ![chain][b] = hgt ] \* increase height of branch [b] 19 | /\ UNCHANGED <> 20 | /\ UNCHANGED <> 21 | 22 | \* A block is produced on an existing branch of an existing chain 23 | New_block == 24 | \E chain \in activeChains : 25 | \E b \in activeBranches[chain] : 26 | LET num_ops == RandomElement(Op_nums) IN 27 | /\ height[chain][b] < sizeBound \* another block can be produced on branch [b] 28 | /\ Produce_block(chain, b, num_ops) \* create a new block on [chain] branch [b] 29 | 30 | \* Start a new branch on an existing [chain] with genesis block 31 | New_branch_on(chain) == 32 | LET b == branch[chain] + 1 33 | blk == Block(Header(chain, b, 0), 0) 34 | IN /\ blocks' = [ blocks EXCEPT ![chain][b] = <> ] 35 | /\ branch' = [ branch EXCEPT ![chain] = b ] 36 | /\ height' = [ height EXCEPT ![chain][b] = 0 ] 37 | /\ UNCHANGED chains 38 | /\ UNCHANGED <> 39 | 40 | \* A new branch is created on an existing chain 41 | New_branch == 42 | \E chain \in activeChains : 43 | /\ branch[chain] < sizeBound \* we have not reached the max branch [b] on [chain] 44 | /\ New_branch_on(chain) \* create a new branch on [chain] 45 | 46 | \* A new [chain] is created with branch 0 and genesis block and [sys] is active on [chain] 47 | New_chain == 48 | /\ chains < numChains \* another chain can be added 49 | /\ LET chain == chains + 1 50 | blk == Block(Header(chain, 0, 0), 0) 51 | IN /\ blocks' = [ blocks EXCEPT ![chain][0] = <> ] 52 | /\ branch' = [ branch EXCEPT ![chain] = 0 ] 53 | /\ chains' = chain 54 | /\ height' = [ height EXCEPT ![chain][0] = 0 ] 55 | /\ UNCHANGED <> 56 | 57 | ============================================================================= 58 | -------------------------------------------------------------------------------- /shell/bootstrapping/apalache/MC_safety.tla: -------------------------------------------------------------------------------- 1 | ---- MODULE MC_safety ---- 2 | 3 | EXTENDS Bootstrap, TLC 4 | 5 | Bad_nodes == 0..0 6 | 7 | Good_nodes == 1..1 8 | 9 | Bad_bootstrapping == 2..2 10 | 11 | Good_bootstrapping == 3..3 12 | 13 | Min_peers == 1 14 | 15 | Max_peers == 2 16 | 17 | Max_level == 2 18 | 19 | Max_ops == 2 20 | 21 | \* header(level, predecessor, context, fitness, ops_hash) 22 | LOCAL ctx1 == hash(<<0, 0>>) 23 | LOCAL hd1 == header(1, 0, ctx1, 0, 1) 24 | LOCAL hsh1 == hash(hd1) 25 | LOCAL ops1 == operations(hsh1, 0..0) 26 | LOCAL fit1 == 1 27 | LOCAL b1 == block(hd1, ops1) 28 | \* block 2 29 | LOCAL ctx2 == hash(<>) 30 | LOCAL hd2 == header(2, hsh1, ctx2, 0, 2) 31 | LOCAL hsh2 == hash(hd2) 32 | LOCAL ops2 == operations(hsh2, 0..1) 33 | LOCAL fit2 == 2 34 | LOCAL b2 == block(hd2, ops2) 35 | 36 | \* Good_nodes -> Headers 37 | Current_head == 1 :> hd2 38 | 39 | \* Good_nodes -> SUBSET Blocks 40 | Good_node_blocks == 1 :> <> 41 | 42 | All_good_node_blocks == UNION { ToSet(Good_node_blocks[n]) : n \in GOOD_NODES } 43 | 44 | Good_node_levels[ n \in Good_nodes ] == { b.header.level : b \in ToSet(Good_node_blocks[n]) } 45 | 46 | Good_node_max_level[ n \in Good_nodes ] == Max_set(Good_node_levels[n]) 47 | 48 | \* Merkle tree 49 | \* 50 | \* ... . 51 | \* / \ 52 | \* / \ 53 | \* level: 2 h20 . 54 | \* / \ / \ 55 | \* / \ / \ 56 | \* level: 1 h10 h11 . 57 | \* / \ / \ / \ 58 | \* / \ / \ / \ 59 | \* level: 0 h00 h01 h02 . 60 | \* | | | | 61 | \* BLOCKS[n] b0 <- b1 <- b2 <- ... 62 | 63 | MerkleTree == [ n \in Good_nodes |-> 64 | [ l \in Levels |-> 65 | LET h00 == hash(gen_header) 66 | h01 == hash(hd1) 67 | h02 == hash(hd2) 68 | h10 == hash(<>) 69 | h11 == hash(<>) 70 | h20 == hash(<>) 71 | IN 72 | CASE l = 2 -> <> 73 | [] l = 1 -> <> 74 | [] l = 0 -> <> 75 | ] 76 | ] 77 | 78 | Validator == [ b \in Blocks |-> 79 | CASE b \in All_good_node_blocks -> "known_valid" 80 | [] hash(b) > Cardinality(BlockHashes) \div 2 -> "known_invalid" 81 | [] OTHER -> "unknown" ] 82 | 83 | Node_samples == [ 84 | n \in Good_nodes |-> 85 | LET length == Cardinality(BLOCKS[n]) - 1 86 | levels == Pick({ s \in Seq(Good_node_levels) : 87 | /\ Len(s) >= length \div 2 88 | /\ Len(s) <= length 89 | /\ \A i \in DOMAIN s \ {1} : s[i - 1] < s[i] }) 90 | IN 91 | [ bn \in Bootstrapping_nodes |-> 92 | Map(LAMBDA l : MerkleTree[n][Good_node_max_level][l + 1], levels) 93 | ] 94 | ] 95 | 96 | Merkle_hashes == [ n \in Good_nodes |-> 97 | [ l \in Good_node_levels[n] |-> Head(MerkleTree[n][l]) ] 98 | ] 99 | 100 | ========================== 101 | -------------------------------------------------------------------------------- /shell/distributed_db/DB_Maintenance.tla: -------------------------------------------------------------------------------- 1 | -------------------------- MODULE DB_Maintenance --------------------------- 2 | 3 | CONSTANTS numChains, numNodes, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, chains, mailbox, blocks, branch, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | LOCAL INSTANCE Utils 11 | 12 | ---------------------------------------------------------------------------- 13 | 14 | (***********************) 15 | (* Maintenance actions *) 16 | (***********************) 17 | 18 | \* Block production 19 | Produce_block(chain, b, num_ops) == 20 | LET hgt == height[chain][b] + 1 \* next block height on branch 21 | header == Header(chain, b, hgt) 22 | block == Block(header, num_ops) 23 | IN \* add the new block to branch [b] on [chain] 24 | /\ blocks' = [ blocks EXCEPT ![chain][b] = Cons(block, @) ] \* add [block] to branch [b] 25 | /\ height' = [ height EXCEPT ![chain][b] = hgt ] \* increase height of branch [b] 26 | /\ UNCHANGED <> 27 | /\ UNCHANGED <> 29 | 30 | \* A block is produced on an existing branch of an existing chain 31 | New_block == 32 | \E chain \in activeChains : 33 | \E b \in activeBranches[chain] : 34 | LET num_ops == RandomElement(Op_nums) 35 | IN /\ height[chain][b] < sizeBound \* another block can be produced on branch [b] 36 | /\ Produce_block(chain, b, num_ops) \* create a new block on [chain] branch [b] 37 | 38 | \* Start a new branch on an existing [chain] with genesis block 39 | New_branch_on(chain) == 40 | LET b == branch[chain] + 1 41 | blk == Block(Header(chain, b, 0), 0) 42 | IN /\ blocks' = [ blocks EXCEPT ![chain][b] = <> ] 43 | /\ branch' = [ branch EXCEPT ![chain] = b ] 44 | /\ height' = [ height EXCEPT ![chain][b] = 0 ] 45 | /\ UNCHANGED <> 46 | /\ UNCHANGED <> 48 | 49 | \* A new branch is created on an existing chain 50 | New_branch == 51 | \E chain \in activeChains : 52 | /\ branch[chain] < sizeBound \* we have not reached the max branch [b] on [chain] 53 | /\ New_branch_on(chain) \* create a new branch on [chain] 54 | 55 | \* A new [chain] is created with branch 0 and genesis block and [sys] is active on [chain] 56 | New_chain == 57 | /\ chains < numChains \* another chain can be added 58 | /\ LET chain == chains + 1 59 | blk == Block(Header(chain, 0, 0), 0) 60 | IN /\ active' = [ active EXCEPT ![chain] = {sys} ] 61 | /\ blocks' = [ blocks EXCEPT ![chain][0] = <> ] 62 | /\ branch' = [ branch EXCEPT ![chain] = 0 ] 63 | /\ chains' = chain 64 | /\ height' = [ height EXCEPT ![chain][0] = 0 ] 65 | /\ UNCHANGED <> 66 | /\ UNCHANGED <> 68 | 69 | ============================================================================= 70 | -------------------------------------------------------------------------------- /shell/distributed_db/DistributedDB.toolbox/Model_1/DB_Maintenance.tla: -------------------------------------------------------------------------------- 1 | -------------------------- MODULE DB_Maintenance --------------------------- 2 | 3 | CONSTANTS numChains, numNodes, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, chains, mailbox, blocks, branch, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | LOCAL INSTANCE Utils 11 | 12 | ---------------------------------------------------------------------------- 13 | 14 | (***********************) 15 | (* Maintenance actions *) 16 | (***********************) 17 | 18 | \* Block production 19 | Produce_block(chain, b, num_ops) == 20 | LET hgt == height[chain][b] + 1 \* next block height on branch 21 | header == Header(chain, b, hgt) 22 | block == Block(header, num_ops) 23 | IN \* add the new block to branch [b] on [chain] 24 | /\ blocks' = [ blocks EXCEPT ![chain][b] = Cons(block, @) ] \* add [block] to branch [b] 25 | /\ height' = [ height EXCEPT ![chain][b] = hgt ] \* increase height of branch [b] 26 | /\ UNCHANGED <> 27 | /\ UNCHANGED <> 29 | 30 | \* A block is produced on an existing branch of an existing chain 31 | New_block == 32 | \E chain \in activeChains : 33 | \E b \in activeBranches[chain] : 34 | LET num_ops == RandomElement(Op_nums) 35 | IN /\ height[chain][b] < sizeBound \* another block can be produced on branch [b] 36 | /\ Produce_block(chain, b, num_ops) \* create a new block on [chain] branch [b] 37 | 38 | \* Start a new branch on an existing [chain] with genesis block 39 | New_branch_on(chain) == 40 | LET b == branch[chain] + 1 41 | blk == Block(Header(chain, b, 0), 0) 42 | IN /\ blocks' = [ blocks EXCEPT ![chain][b] = <> ] 43 | /\ branch' = [ branch EXCEPT ![chain] = b ] 44 | /\ height' = [ height EXCEPT ![chain][b] = 0 ] 45 | /\ UNCHANGED <> 46 | /\ UNCHANGED <> 48 | 49 | \* A new branch is created on an existing chain 50 | New_branch == 51 | \E chain \in activeChains : 52 | /\ branch[chain] < sizeBound \* we have not reached the max branch [b] on [chain] 53 | /\ New_branch_on(chain) \* create a new branch on [chain] 54 | 55 | \* A new [chain] is created with branch 0 and genesis block and [sys] is active on [chain] 56 | New_chain == 57 | /\ chains < numChains \* another chain can be added 58 | /\ LET chain == chains + 1 59 | blk == Block(Header(chain, 0, 0), 0) 60 | IN /\ active' = [ active EXCEPT ![chain] = {sys} ] 61 | /\ blocks' = [ blocks EXCEPT ![chain][0] = <> ] 62 | /\ branch' = [ branch EXCEPT ![chain] = 0 ] 63 | /\ chains' = chain 64 | /\ height' = [ height EXCEPT ![chain][0] = 0 ] 65 | /\ UNCHANGED <> 66 | /\ UNCHANGED <> 68 | 69 | ============================================================================= 70 | -------------------------------------------------------------------------------- /shell/distributed_db/DB_Receive.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE DB_Receive ----------------------------- 2 | 3 | CONSTANTS numChains, numNodes, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, blocks, branch, chains, mailbox, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | LOCAL INSTANCE Utils 11 | 12 | ---------------------------------------------------------------------------- 13 | 14 | (*******************) 15 | (* Receive actions *) 16 | (*******************) 17 | 18 | (* Nodes can either receive or drop messages that are sent to them *) 19 | 20 | \* [node] receives a message on [chain] 21 | Receive_msg(node, chain) == 22 | LET msgs == mailbox[chain][node] 23 | in_q == node_incoming[node][chain] 24 | msg == Head(msgs) 25 | IN \* [msg] is added to [node]'s incoming messages 26 | /\ node_incoming' = [ node_incoming EXCEPT ![node][chain] = checkAppend(@, msg) ] 27 | \* [msg] is removed from [node]'s sent set 28 | /\ mailbox' = [ mailbox EXCEPT ![chain][node] = Tail(@) ] 29 | /\ UNCHANGED <> 30 | /\ UNCHANGED <> 32 | 33 | \* A node with messages on some chain and room in their queue, receives a message 34 | Receive_node == 35 | \E chain \in activeChains : 36 | \E node \in activeNodes[chain] : 37 | /\ mailbox[chain][node] /= <<>> \* there are [chain] messages for [node] 38 | /\ checkIncoming[node][chain] \* [node] has space for incoming [chain] messages 39 | /\ Receive_msg(node, chain) 40 | 41 | \* [sys] receives a message on [chain] 42 | Receive_sys_msg(chain) == 43 | LET msgs == mailbox[chain][sys] 44 | in_q == sysmsgs[chain] 45 | msg == Head(msgs) 46 | IN \* [msg] is removed from [sys]'s sent set 47 | /\ mailbox' = [ mailbox EXCEPT ![chain][sys] = Tail(@) ] 48 | /\ sysmsgs' = [ sysmsgs EXCEPT ![chain] = checkAppend(@, msg) ] 49 | /\ UNCHANGED <> 50 | /\ UNCHANGED <> 52 | 53 | \* [sys] receives a message on some chain 54 | Receive_sys == 55 | \A chain \in activeChains : 56 | /\ mailbox[chain][sys] /= <<>> \* [sys] has a message to receive on [chain] 57 | /\ checkSysMsgs[chain] \* [sys] has room to receive on [chain] 58 | /\ Receive_sys_msg(chain) \* [sys] receives a message on [chain] 59 | 60 | \* Receive a message 61 | Receive == Receive_node \/ Receive_sys 62 | 63 | \* [node] drops a [chain] message 64 | Drop_msg(node, chain) == 65 | /\ mailbox' = [ mailbox EXCEPT ![chain][node] = Tail(@) ] 66 | /\ UNCHANGED <> 67 | /\ UNCHANGED <> 69 | 70 | \* A node drops a message on some chain 71 | Drop == 72 | \E chain \in activeChains : 73 | \E node \in SysNodes : 74 | /\ mailbox[chain][node] /= <<>> \* [node] has a message to drop 75 | /\ Drop_msg(node, chain) \* [node] drops a message 76 | 77 | ============================================================================= 78 | -------------------------------------------------------------------------------- /shell/distributed_db/DistributedDB.toolbox/Model_1/DB_Receive.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE DB_Receive ----------------------------- 2 | 3 | CONSTANTS numChains, numNodes, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, blocks, branch, chains, mailbox, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | LOCAL INSTANCE Utils 11 | 12 | ---------------------------------------------------------------------------- 13 | 14 | (*******************) 15 | (* Receive actions *) 16 | (*******************) 17 | 18 | (* Nodes can either receive or drop messages that are sent to them *) 19 | 20 | \* [node] receives a message on [chain] 21 | Receive_msg(node, chain) == 22 | LET msgs == mailbox[chain][node] 23 | in_q == node_incoming[node][chain] 24 | msg == Head(msgs) 25 | IN \* [msg] is added to [node]'s incoming messages 26 | /\ node_incoming' = [ node_incoming EXCEPT ![node][chain] = checkAppend(@, msg) ] 27 | \* [msg] is removed from [node]'s sent set 28 | /\ mailbox' = [ mailbox EXCEPT ![chain][node] = Tail(@) ] 29 | /\ UNCHANGED <> 30 | /\ UNCHANGED <> 32 | 33 | \* A node with messages on some chain and room in their queue, receives a message 34 | Receive_node == 35 | \E chain \in activeChains : 36 | \E node \in activeNodes[chain] : 37 | /\ mailbox[chain][node] /= <<>> \* there are [chain] messages for [node] 38 | /\ checkIncoming[node][chain] \* [node] has space for incoming [chain] messages 39 | /\ Receive_msg(node, chain) 40 | 41 | \* [sys] receives a message on [chain] 42 | Receive_sys_msg(chain) == 43 | LET msgs == mailbox[chain][sys] 44 | in_q == sysmsgs[chain] 45 | msg == Head(msgs) 46 | IN \* [msg] is removed from [sys]'s sent set 47 | /\ mailbox' = [ mailbox EXCEPT ![chain][sys] = Tail(@) ] 48 | /\ sysmsgs' = [ sysmsgs EXCEPT ![chain] = checkAppend(@, msg) ] 49 | /\ UNCHANGED <> 50 | /\ UNCHANGED <> 52 | 53 | \* [sys] receives a message on some chain 54 | Receive_sys == 55 | \A chain \in activeChains : 56 | /\ mailbox[chain][sys] /= <<>> \* [sys] has a message to receive on [chain] 57 | /\ checkSysMsgs[chain] \* [sys] has room to receive on [chain] 58 | /\ Receive_sys_msg(chain) \* [sys] receives a message on [chain] 59 | 60 | \* Receive a message 61 | Receive == Receive_node \/ Receive_sys 62 | 63 | \* [node] drops a [chain] message 64 | Drop_msg(node, chain) == 65 | /\ mailbox' = [ mailbox EXCEPT ![chain][node] = Tail(@) ] 66 | /\ UNCHANGED <> 67 | /\ UNCHANGED <> 69 | 70 | \* A node drops a message on some chain 71 | Drop == 72 | \E chain \in activeChains : 73 | \E node \in SysNodes : 74 | /\ mailbox[chain][node] /= <<>> \* [node] has a message to drop 75 | /\ Drop_msg(node, chain) \* [node] drops a message 76 | 77 | ============================================================================= 78 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/DB_Request.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE DB_Request ----------------------------- 2 | 3 | (**********************************) 4 | (* Messages are implicitly passed *) 5 | (**********************************) 6 | 7 | EXTENDS DB_Defs 8 | 9 | (**********************) 10 | (* Get_current_branch *) 11 | (**********************) 12 | 13 | \* node learns about the current branch of [chain] 14 | get_current_branch(chain) == 15 | /\ node_branches' = [ node_branches EXCEPT ![chain] = insertBranch(branch[chain], @) ] 16 | /\ UNCHANGED <> 17 | /\ UNCHANGED <> 18 | 19 | Get_current_branch == 20 | \E chain \in activeChains : 21 | /\ active[chain] 22 | /\ Len(node_branches[chain]) < sizeBound 23 | /\ get_current_branch(chain) 24 | 25 | (********************) 26 | (* Get_current_head *) 27 | (********************) 28 | 29 | \* node learns about the current head of branch [b] on [chain] 30 | get_current_head(chain, b) == 31 | /\ node_height' = [ node_height EXCEPT ![chain][b] = height[chain][b] ] 32 | /\ UNCHANGED <> 33 | /\ UNCHANGED <> 34 | 35 | Get_current_head == 36 | \E chain \in activeChains : 37 | \E b \in activeBranches[chain] : 38 | /\ height[chain][b] >= 0 39 | /\ active[chain] 40 | /\ node_height[chain][b] /= height[chain][b] 41 | /\ get_current_head(chain, b) 42 | 43 | (********************) 44 | (* Get_block_header *) 45 | (********************) 46 | 47 | \* node learns about the header for the block at height [h] on branch [b] of [chain] 48 | get_block_header(chain, b, h) == 49 | /\ h \in { blk.header.height : blk \in ToSet(blocks[chain][b]) } 50 | /\ LET hdr == blockAtHeight(chain, b, h).header IN 51 | /\ node_headers' = [ node_headers EXCEPT ![chain] = insertHeader(hdr, @) ] 52 | /\ UNCHANGED <> 53 | /\ UNCHANGED <> 54 | 55 | \* node retrieves a block header on some branch at some height on some chain 56 | Get_block_header == 57 | \E chain \in activeChains : 58 | /\ active[chain] 59 | /\ \E b \in branchSet[chain] : 60 | \* there are blocks which node has not seen 61 | /\ currentHeights(chain, b) \ heightSet[chain, b] /= {} 62 | /\ LET h == min_set(currentHeights(chain, b) \ heightSet[chain, b]) IN 63 | /\ h <= node_height[chain][b] 64 | /\ get_block_header(chain, b, h) 65 | 66 | (******************) 67 | (* Get_operations *) 68 | (******************) 69 | 70 | \* node has a block header with height [h] on branch [b] of [chain] 71 | get_operations(chain, hdr) == 72 | LET b == hdr.branch 73 | ops == blockAtHeight(chain, b, hdr.height).ops 74 | blk == Block(hdr, ops) 75 | IN 76 | /\ node_headers' = [ node_headers EXCEPT ![chain] = Tail(@) ] 77 | /\ node_blocks' = [ node_blocks EXCEPT ![chain][b] = insertBlock(blk, @) ] 78 | /\ UNCHANGED <> 79 | /\ UNCHANGED <> 80 | 81 | \* node retrieves the operations of a block for which they have a header 82 | Get_operations == 83 | \E chain \in activeChains : 84 | LET headers == node_headers[chain] IN 85 | /\ headers /= <<>> 86 | /\ get_operations(chain, Head(headers)) 87 | 88 | ============================================================================= 89 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/DB_Request.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE DB_Request ----------------------------- 2 | 3 | (**********************************) 4 | (* Messages are implicitly passed *) 5 | (**********************************) 6 | 7 | EXTENDS DB_Defs 8 | 9 | (**********************) 10 | (* Get_current_branch *) 11 | (**********************) 12 | 13 | \* node learns about the current branch of [chain] 14 | get_current_branch(chain) == 15 | /\ node_branches' = [ node_branches EXCEPT ![chain] = insertBranch(branch[chain], @) ] 16 | /\ UNCHANGED <> 17 | /\ UNCHANGED <> 18 | 19 | Get_current_branch == 20 | \E chain \in activeChains : 21 | /\ active[chain] 22 | /\ Len(node_branches[chain]) < sizeBound 23 | /\ get_current_branch(chain) 24 | 25 | (********************) 26 | (* Get_current_head *) 27 | (********************) 28 | 29 | \* node learns about the current head of branch [b] on [chain] 30 | get_current_head(chain, b) == 31 | /\ node_height' = [ node_height EXCEPT ![chain][b] = height[chain][b] ] 32 | /\ UNCHANGED <> 33 | /\ UNCHANGED <> 34 | 35 | Get_current_head == 36 | \E chain \in activeChains : 37 | \E b \in activeBranches[chain] : 38 | /\ height[chain][b] >= 0 39 | /\ active[chain] 40 | /\ node_height[chain][b] /= height[chain][b] 41 | /\ get_current_head(chain, b) 42 | 43 | (********************) 44 | (* Get_block_header *) 45 | (********************) 46 | 47 | \* node learns about the header for the block at height [h] on branch [b] of [chain] 48 | get_block_header(chain, b, h) == 49 | /\ h \in { blk.header.height : blk \in ToSet(blocks[chain][b]) } 50 | /\ LET hdr == blockAtHeight(chain, b, h).header IN 51 | /\ node_headers' = [ node_headers EXCEPT ![chain] = insertHeader(hdr, @) ] 52 | /\ UNCHANGED <> 53 | /\ UNCHANGED <> 54 | 55 | \* node retrieves a block header on some branch at some height on some chain 56 | Get_block_header == 57 | \E chain \in activeChains : 58 | /\ active[chain] 59 | /\ \E b \in branchSet[chain] : 60 | \* there are blocks which node has not seen 61 | /\ currentHeights(chain, b) \ heightSet[chain, b] /= {} 62 | /\ LET h == min_set(currentHeights(chain, b) \ heightSet[chain, b]) IN 63 | /\ h <= node_height[chain][b] 64 | /\ get_block_header(chain, b, h) 65 | 66 | (******************) 67 | (* Get_operations *) 68 | (******************) 69 | 70 | \* node has a block header with height [h] on branch [b] of [chain] 71 | get_operations(chain, hdr) == 72 | LET b == hdr.branch 73 | ops == blockAtHeight(chain, b, hdr.height).ops 74 | blk == Block(hdr, ops) 75 | IN 76 | /\ node_headers' = [ node_headers EXCEPT ![chain] = Tail(@) ] 77 | /\ node_blocks' = [ node_blocks EXCEPT ![chain][b] = insertBlock(blk, @) ] 78 | /\ UNCHANGED <> 79 | /\ UNCHANGED <> 80 | 81 | \* node retrieves the operations of a block for which they have a header 82 | Get_operations == 83 | \E chain \in activeChains : 84 | LET headers == node_headers[chain] IN 85 | /\ headers /= <<>> 86 | /\ get_operations(chain, Head(headers)) 87 | 88 | ============================================================================= 89 | -------------------------------------------------------------------------------- /shell/distributed_db/DB_Invariants.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE DB_Invariants ----------------------------- 2 | 3 | CONSTANTS numNodes, numChains, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, blocks, branch, chains, mailbox, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | 11 | (**************) 12 | (* Properties *) 13 | (**************) 14 | 15 | \* Active nodes are eventually sent messages 16 | ActiveNodesAreSentMessages == 17 | \A chain \in Chains : 18 | \A node \in Nodes : 19 | node \in activeNodes[chain] ~> mailbox[chain][node] /= <<>> 20 | 21 | \* A sent message is eventually received by the intended recipient, as long as they remain active 22 | \* A [msg] sent to a [node] eventually ends up in node_incoming[node][chain] 23 | SentMessagesAreReceivedByActives == 24 | \A chain \in Chains : 25 | \A node \in Nodes : 26 | node \in activeNodes[chain] ~> 27 | LET sent == mailbox[chain][node] 28 | IN /\ sent /= <<>> 29 | /\ LET msg == Head(sent) 30 | msgs == node_incoming[node][chain] 31 | IN /\ msgs /= <<>> 32 | /\ msg \in ToSet(msgs) 33 | 34 | \* TODO 35 | \* Received messages are eventually handled by active nodes 36 | ReceivedMessagesAreEventuallyHandled == 37 | \A chain \in Chains : 38 | \A node \in Nodes : 39 | LET msgs == node_incoming[node][chain] 40 | IN /\ msgs /= <<>> 41 | /\ LET msg == Head(msgs) 42 | IN CASE isValidReqMsg(msg) -> FALSE 43 | [] isValidAdvMsg(msg) -> FALSE 44 | [] isValidAckMsg(msg) -> FALSE 45 | [] isValidErrMsg(msg) -> FALSE 46 | 47 | \* bootstrapping progress is made 48 | \* active nodes are either synced with network or making progress towards that goal 49 | 50 | \* If a node remains active on [chain], then eventually they will learn about all [chain] branches 51 | ActiveNodesEventuallyGetBranches == 52 | \A chain \in Chains : 53 | \A node \in Nodes : 54 | node \in activeNodes[chain] ~> 55 | max_set(branchSet[node, chain]) = branch[chain] 56 | 57 | \* If a node remains active on [chain], then eventually they will learn about all the blocks 58 | \* on all the branches of [chain] 59 | ActiveNodesEventuallySync == 60 | \A chain \in Chains : 61 | \A node \in Nodes : 62 | node \in activeNodes[chain] ~> 63 | \A b \in branchSet[node, chain] : 64 | node_blocks[node][chain][b] = blocks[chain][b] 65 | 66 | -------------------------------------------------------------------------------- 67 | 68 | (**************) 69 | (* Invariants *) 70 | (**************) 71 | 72 | \* network_info & node_info are in agreement 73 | ActiveAgreement == 74 | \A chain \in activeChains : 75 | \A node \in activeNodes[chain] : 76 | \* actives 77 | /\ chain \in node_active[node] 78 | \* branches 79 | /\ node_branches[node][chain] /= <<>> => 80 | current_branch[node, chain] <= branch[chain] 81 | \* blocks 82 | /\ \A b \in branchSet[node, chain] : 83 | isSubSeq(node_blocks[node][chain][b], blocks[chain][b]) 84 | \* height 85 | /\ \A b \in branchSet[node, chain] : 86 | node_height[node][chain][b] <= height[chain][b] 87 | 88 | ================================================================================ 89 | -------------------------------------------------------------------------------- /shell/distributed_db/DistributedDB.toolbox/Model_1/DB_Invariants.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE DB_Invariants ----------------------------- 2 | 3 | CONSTANTS numNodes, numChains, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, blocks, branch, chains, mailbox, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | 11 | (**************) 12 | (* Properties *) 13 | (**************) 14 | 15 | \* Active nodes are eventually sent messages 16 | ActiveNodesAreSentMessages == 17 | \A chain \in Chains : 18 | \A node \in Nodes : 19 | node \in activeNodes[chain] ~> mailbox[chain][node] /= <<>> 20 | 21 | \* A sent message is eventually received by the intended recipient, as long as they remain active 22 | \* A [msg] sent to a [node] eventually ends up in node_incoming[node][chain] 23 | SentMessagesAreReceivedByActives == 24 | \A chain \in Chains : 25 | \A node \in Nodes : 26 | node \in activeNodes[chain] ~> 27 | LET sent == mailbox[chain][node] 28 | IN /\ sent /= <<>> 29 | /\ LET msg == Head(sent) 30 | msgs == node_incoming[node][chain] 31 | IN /\ msgs /= <<>> 32 | /\ msg \in ToSet(msgs) 33 | 34 | \* TODO 35 | \* Received messages are eventually handled by active nodes 36 | ReceivedMessagesAreEventuallyHandled == 37 | \A chain \in Chains : 38 | \A node \in Nodes : 39 | LET msgs == node_incoming[node][chain] 40 | IN /\ msgs /= <<>> 41 | /\ LET msg == Head(msgs) 42 | IN CASE isValidReqMsg(msg) -> FALSE 43 | [] isValidAdvMsg(msg) -> FALSE 44 | [] isValidAckMsg(msg) -> FALSE 45 | [] isValidErrMsg(msg) -> FALSE 46 | 47 | \* bootstrapping progress is made 48 | \* active nodes are either synced with network or making progress towards that goal 49 | 50 | \* If a node remains active on [chain], then eventually they will learn about all [chain] branches 51 | ActiveNodesEventuallyGetBranches == 52 | \A chain \in Chains : 53 | \A node \in Nodes : 54 | node \in activeNodes[chain] ~> 55 | max_set(branchSet[node, chain]) = branch[chain] 56 | 57 | \* If a node remains active on [chain], then eventually they will learn about all the blocks 58 | \* on all the branches of [chain] 59 | ActiveNodesEventuallySync == 60 | \A chain \in Chains : 61 | \A node \in Nodes : 62 | node \in activeNodes[chain] ~> 63 | \A b \in branchSet[node, chain] : 64 | node_blocks[node][chain][b] = blocks[chain][b] 65 | 66 | -------------------------------------------------------------------------------- 67 | 68 | (**************) 69 | (* Invariants *) 70 | (**************) 71 | 72 | \* network_info & node_info are in agreement 73 | ActiveAgreement == 74 | \A chain \in activeChains : 75 | \A node \in activeNodes[chain] : 76 | \* actives 77 | /\ chain \in node_active[node] 78 | \* branches 79 | /\ node_branches[node][chain] /= <<>> => 80 | current_branch[node, chain] <= branch[chain] 81 | \* blocks 82 | /\ \A b \in branchSet[node, chain] : 83 | isSubSeq(node_blocks[node][chain][b], blocks[chain][b]) 84 | \* height 85 | /\ \A b \in branchSet[node, chain] : 86 | node_height[node][chain][b] <= height[chain][b] 87 | 88 | ================================================================================ 89 | -------------------------------------------------------------------------------- /consensus/Tenderbake/Tenderbake.md: -------------------------------------------------------------------------------- 1 | # Tenderbake 2 | 3 | Tenderbake is an instance of a general solution to the *dynamic repeated consensus* problem for blockchains. The system model is taken to be partially synchronous with byzantine failures. 4 | 5 | In this environment, committees responsible for deciding values at different levels can change, hence *dynamic*, and we want to be able to continue choosing committee members and coming to consensus on a value at each level, hence *repeated consensus*. 6 | 7 | The committee for a given level is chosen based only on the value decided at the previous level. COmmittee members are called *bakers*. 8 | 9 | ## Quourm certificates 10 | 11 | In a setting with byzantine failures, when we speak of quorums, we will always mean a *byzantine quorum*, i.e. if a committee has `n` members, of which `f` are faulty, and `n >= 3f + 1`, then `2f + 1` members constitute a quorum. In this way, any two quorums necessarily share at least one correct baker. 12 | 13 | A *preendorsement quorum certificate* (QC) is a set of legitimate committee members who have preendorsed the same *value* to be added on top of the same *block*, in the same *round*, at the same *level*. 14 | 15 | An *endorsement quorum certificate* (QC) is a set of legitimate committee members who have endorsed the same *value* to be added on top of the same *block*, in the same *round*, at the same *level*. 16 | 17 | In the spec, we represent QCs as a 5-tuple: `<>` 18 | 19 | ## Rounds 20 | 21 | In general, there are arbitrarily many rounds at each level with increasing durations to facilitate message delivery and ultimately, decision making. In the asynchronous period before GST, there is no guarantee on message delivery or transmission delays. Once we are past the GST, it is assumed that we have loosely synchronized clocks and not too delayed message transmissions. Then we will be able to decide a value within `f + 2` rounds. 22 | 23 | Each round has one proposer who is the only process which can propose a value in that round's `PROPOSE` phase. 24 | 25 | ## Phases 26 | 27 | Each round consists of *three* phases: 28 | 29 | - `PROPOSE` phase 30 | - a value is proposed by the round's designated proposer 31 | - `Propose` messages are broadcast to active committee members, including self 32 | - non-proposing bakers wait for a proposal message 33 | 34 | - `PREENDORSE` phase 35 | - if a baker is not locked on a value or is locked on a value from a previous round, they preendorse the current (valid) proposal 36 | - `Preendorse` messages are broadcast to committee members, including self, to signal this intention 37 | - if a baker is locked on a value at a higher round or locked and the proposal is newly generated (`eR = 0` and `pQC = {}`), they do not preendorse the proposal 38 | - `Preendorsements` messages containing the corresponding preendorsement quorum certificate are broadcast to the committee members 39 | 40 | - `ENDORSE` 41 | - if a baker has a preendorsement quorum for a value `v`, they endorse `v` 42 | - `Endorse` messages are broadcast to committee members along with the pQC justifying the endorsement 43 | - if a baker has an endorsement quorum for value `v`, they decide `v` 44 | 45 | ## Messages 46 | 47 | There is a message type and corresponding payload for each phase. The message types and corresponding payloads are: 48 | 49 | | Type | Payload | 50 | |------|---------| 51 | | Propose | 4-tuple of endorsement quorum certificate, endorsable value, endorsable round, and preendorsement quorum certificate | 52 | | Preendorse | value | 53 | | Preendorsements | preendorsement quorum certificate | 54 | | Endorse | endorsed value | 55 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Seq(t)) => Set(t); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | \* Nonempty subsets of S 17 | NESubsets(S) == SUBSET S \ {{}} 18 | 19 | \* Subsets of size <= n 20 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 21 | 22 | ---------------------------------------------------------------------------- 23 | 24 | (* Common functions/operators *) 25 | 26 | \* minimum 27 | min[m, n \in Int] == IF m > n THEN n ELSE m 28 | 29 | \* maximum 30 | max[m, n \in Int] == IF m > n THEN m ELSE n 31 | 32 | \* maximum element of a nonempty finite set of naturals 33 | max_set(set) == 34 | LET RECURSIVE _max_set(_, _) 35 | _max_set(S, curr) == 36 | CASE S = {} -> curr 37 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 38 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 39 | [] OTHER -> -1 40 | 41 | \* minimum element of a nonempty finite set of naturals 42 | min_set(set) == 43 | LET RECURSIVE _min_set(_, _) 44 | _min_set(S, curr) == 45 | CASE S = {} -> curr 46 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 47 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 48 | [] OTHER -> -1 49 | 50 | ---------------------------------------------------------------------------- 51 | 52 | (* Functions/Sequences *) 53 | 54 | \* Enumerable set of sequences of elements from S with length = n 55 | SeqOfLen(S, n) == 56 | CASE n < 0 -> {} 57 | [] OTHER -> [ 1..n -> S ] 58 | 59 | \* Enumerable set of sequences of elements from S with length <= n 60 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 61 | 62 | \* Enumerable set of nonempty sequences of length <= n 63 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 64 | 65 | \* Enumerable set of pairs of elements from sets S1 and S2 66 | \* @type: (Set(a), Set(b)) => Set(<>); 67 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 68 | 69 | \* Nonempty sequences of elements from set S 70 | NESeq(S) == Seq(S) \ {<<>>} 71 | 72 | \* remove (all occurrences of) an element from a sequence 73 | Remove(seq, elem) == 74 | LET RECURSIVE remove(_, _, _) 75 | remove(s, e, acc) == 76 | CASE s = <<>> -> acc 77 | [] e /= Head(s) -> remove(Tail(s), e, Append(acc, Head(s))) 78 | [] OTHER -> remove(Tail(s), e, acc) 79 | IN remove(seq, elem, <<>>) 80 | 81 | \* (finite) subsequence predicate 82 | RECURSIVE isSubSeq(_, _) 83 | isSubSeq(s1, s2) == 84 | \/ s1 = <<>> 85 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 86 | [] OTHER -> 87 | LET n == max_set(DOMAIN s2) 88 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 89 | s == [ j \in (i + 1)..n |-> s2[j] ] 90 | IN isSubSeq(Tail(s1), s) 91 | 92 | \* Selects the first element that satisfies the predicate 93 | \* if no element satisfies the predicate, then return <<>> 94 | Select(seq, test(_)) == 95 | LET RECURSIVE select(_) 96 | select(s) == 97 | CASE s = <<>> -> <<>> 98 | [] test(Head(s)) -> Head(s) 99 | [] OTHER -> select(Tail(s)) 100 | IN select(seq) 101 | 102 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 103 | Forall(seq, test(_)) == 104 | LET RECURSIVE forall(_, _) 105 | forall(s, acc) == 106 | IF s = <<>> 107 | THEN acc 108 | ELSE /\ acc 109 | /\ forall(Tail(s), acc /\ test(Head(s))) 110 | IN forall(seq, TRUE) 111 | 112 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 113 | Exists(seq, test(_)) == 114 | LET RECURSIVE exists(_, _) 115 | exists(s, acc) == 116 | IF s = <<>> 117 | THEN acc 118 | ELSE \/ acc 119 | \/ exists(Tail(s), acc \/ test(Head(s))) 120 | IN exists(seq, FALSE) 121 | 122 | Cons(elem, seq) == <> \o seq 123 | 124 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 125 | 126 | ============================================================================= 127 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Seq(t)) => Set(t); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | \* Nonempty subsets of S 17 | NESubsets(S) == SUBSET S \ {{}} 18 | 19 | \* Subsets of size <= n 20 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 21 | 22 | ---------------------------------------------------------------------------- 23 | 24 | (* Common functions/operators *) 25 | 26 | \* minimum 27 | min[m, n \in Int] == IF m > n THEN n ELSE m 28 | 29 | \* maximum 30 | max[m, n \in Int] == IF m > n THEN m ELSE n 31 | 32 | \* maximum element of a nonempty finite set of naturals 33 | max_set(set) == 34 | LET RECURSIVE _max_set(_, _) 35 | _max_set(S, curr) == 36 | CASE S = {} -> curr 37 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 38 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 39 | [] OTHER -> -1 40 | 41 | \* minimum element of a nonempty finite set of naturals 42 | min_set(set) == 43 | LET RECURSIVE _min_set(_, _) 44 | _min_set(S, curr) == 45 | CASE S = {} -> curr 46 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 47 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 48 | [] OTHER -> -1 49 | 50 | ---------------------------------------------------------------------------- 51 | 52 | (* Functions/Sequences *) 53 | 54 | \* Enumerable set of sequences of elements from S with length = n 55 | SeqOfLen(S, n) == 56 | CASE n < 0 -> {} 57 | [] OTHER -> [ 1..n -> S ] 58 | 59 | \* Enumerable set of sequences of elements from S with length <= n 60 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 61 | 62 | \* Enumerable set of nonempty sequences of length <= n 63 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 64 | 65 | \* Enumerable set of pairs of elements from sets S1 and S2 66 | \* @type: (Set(a), Set(b)) => Set(<>); 67 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 68 | 69 | \* Nonempty sequences of elements from set S 70 | NESeq(S) == Seq(S) \ {<<>>} 71 | 72 | \* remove (all occurrences of) an element from a sequence 73 | Remove(seq, elem) == 74 | LET RECURSIVE remove(_, _, _) 75 | remove(s, e, acc) == 76 | CASE s = <<>> -> acc 77 | [] e /= Head(s) -> remove(Tail(s), e, Append(acc, Head(s))) 78 | [] OTHER -> remove(Tail(s), e, acc) 79 | IN remove(seq, elem, <<>>) 80 | 81 | \* (finite) subsequence predicate 82 | RECURSIVE isSubSeq(_, _) 83 | isSubSeq(s1, s2) == 84 | \/ s1 = <<>> 85 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 86 | [] OTHER -> 87 | LET n == max_set(DOMAIN s2) 88 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 89 | s == [ j \in (i + 1)..n |-> s2[j] ] 90 | IN isSubSeq(Tail(s1), s) 91 | 92 | \* Selects the first element that satisfies the predicate 93 | \* if no element satisfies the predicate, then return <<>> 94 | Select(seq, test(_)) == 95 | LET RECURSIVE select(_) 96 | select(s) == 97 | CASE s = <<>> -> <<>> 98 | [] test(Head(s)) -> Head(s) 99 | [] OTHER -> select(Tail(s)) 100 | IN select(seq) 101 | 102 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 103 | Forall(seq, test(_)) == 104 | LET RECURSIVE forall(_, _) 105 | forall(s, acc) == 106 | IF s = <<>> 107 | THEN acc 108 | ELSE /\ acc 109 | /\ forall(Tail(s), acc /\ test(Head(s))) 110 | IN forall(seq, TRUE) 111 | 112 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 113 | Exists(seq, test(_)) == 114 | LET RECURSIVE exists(_, _) 115 | exists(s, acc) == 116 | IF s = <<>> 117 | THEN acc 118 | ELSE \/ acc 119 | \/ exists(Tail(s), acc \/ test(Head(s))) 120 | IN exists(seq, FALSE) 121 | 122 | Cons(elem, seq) == <> \o seq 123 | 124 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 125 | 126 | ============================================================================= 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tezedge-specification 2 | 3 | This project contains various formal specifications and models for different aspects of the Tezedge node's p2p overlay network, shell, and consensus. 4 | 5 | In the security-critical realm of blockchains, it is not enough to simply test our software. Since these systems contain sensitive financial information and business logic, we believe that it is absolutely necessary to formally verify the code we write. 6 | 7 | Part of the formal verification process focuses on the design we intend to implement in our code. This is the realm of formal specification and model checking. TLA+, our formal specification language of choice, is well-known, widely used, and particularly well-suited to reasoning about concurrent and distributed algorithms. 8 | 9 | Formal specification and model checking give us assurance and verification that our algorithms have the intended properties and no undesirable behavior. Formal specification is, of course, not a replacement for testing, but a necessary companion and counterpart. TLA+ gives one the ability to exhaustively check all possible behaviors of a system. 10 | 11 | See [project navigation](./README.md#project-navigation) for a brief description of each directory's contents. 12 | 13 | ## Quick start 14 | 15 | ### TLA+ 16 | 17 | Download and install the latest release of the [TLA+ toolbox](https://github.com/tlaplus/tlaplus/releases/tag/v1.7.1). 18 | 19 | [TLA+](https://lamport.azurewebsites.net/tla/tla.html) is our chosen specification language. It enables one to encode the specification of a state machine, as well as its safety and liveness properties, in the language of [temporal logic of actions](https://lamport.azurewebsites.net/pubs/lamport-actions.pdf). TLA+ comes with an explicit state model checker, [TLC](https://github.com/tlaplus/tlaplus), which exhaustively checks all behaviors of the specified state machine, verifies its properties, and provides counterexamples to violated properties. 20 | 21 | ### Apalache 22 | 23 | [Apalache](https://github.com/informalsystems/apalache) is a symbolic model checker for TLA+; Apalache translates TLA+ into the logic supported by SMT solvers such as Z3. 24 | 25 | We use Apalache extensively in this project to typecheck specifications and verify inductive (safety) invariants (see [Apalache docs](https://apalache.informal.systems/docs/apalache/index.html)). The easiest way to get and run Apalache is with [docker](https://apalache.informal.systems/docs/apalache/installation/docker.html): 26 | 27 | 1. Pull the `unstable` image (one may use the `latest` image, but `unstable` provides more features) 28 | 29 | ``` 30 | $ docker pull apalache/mc:unstable 31 | ``` 32 | 33 | 2. Set an alias for the `unstable` image (if you're using Linux or macOS) 34 | 35 | ``` 36 | $ alias apalache='docker run --rm -v $(pwd):/var/apalache apalache/mc:unstable' 37 | ``` 38 | 39 | 3. Verify that the setup works 40 | 41 | ``` 42 | $ apalache version 43 | ``` 44 | 45 | Note that this command will generate a `detailed.log` file in the directory in which it is run. 46 | 47 | Specific instructions to verify inductive invariants are provided in the corresponding spec's directory. 48 | 49 | ### TLA+ command line tool 50 | 51 | The default way to write TLA+ specs and run the model checker (TLC) is through the (graphical) toolbox. However, for the ease of running TLC on a remote server, one may be interested in also getting the TLA+ command line tool [tla-bin](https://github.com/pmer/tla-bin). Installation instructions are provided in that repo. 52 | 53 | ### TLA+ VSCode extension 54 | 55 | For those who prefer to work in VSCode, there is the extension [vscode-tlaplus](https://github.com/alygin/vscode-tlaplus) which is well-maintained and highly recommended. 56 | 57 | ## Project navigation 58 | 59 | There are three main objects of focus for our specifications, corresponding to the three layers in Tezos: `p2p`, `shell`, and `consensus` 60 | 61 | ### p2p 62 | 63 | This project contains specifications and models related to the p2p overlay network: 64 | 65 | - [hanshaking](./p2p/handshaking) 66 | - I/O resource management 67 | - counter 68 | - scheduler 69 | 70 | ### shell 71 | 72 | This project contains specifications and models related to the shell: 73 | 74 | - [bootstrapping](./shell/bootstrapping) 75 | - distributed_db 76 | - [mempool](./shell/mempool) 77 | 78 | ### consensus 79 | 80 | This project contains specifications and models related to consensus: 81 | 82 | - [Emmy/Emmy+/Emmy★](./consensus/Emmy) 83 | - [Tenderbake](./consensus/Tenderbake) 84 | 85 | ### utils 86 | 87 | This project contains TLA+ functions and operators used extensively in the other projects 88 | -------------------------------------------------------------------------------- /utils/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Int -> T) => Set(T); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | disjoint(S, T) == S \cap T = {} 17 | 18 | \* Nonempty subsets of S 19 | NESubsets(S) == SUBSET S \ {{}} 20 | 21 | \* Subsets of size <= n 22 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | (* Common functions/operators *) 27 | 28 | \* minimum 29 | min[m, n \in Int] == IF m > n THEN n ELSE m 30 | 31 | \* maximum 32 | max[m, n \in Int] == IF m > n THEN m ELSE n 33 | 34 | \* maximum element of a nonempty finite set of naturals 35 | max_set(set) == 36 | LET RECURSIVE _max_set(_, _) 37 | _max_set(S, curr) == 38 | CASE S = {} -> curr 39 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 40 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 41 | [] OTHER -> -1 42 | 43 | \* minimum element of a nonempty finite set of naturals 44 | min_set(set) == 45 | LET RECURSIVE _min_set(_, _) 46 | _min_set(S, curr) == 47 | CASE S = {} -> curr 48 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 49 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 50 | [] OTHER -> -1 51 | 52 | ---------------------------------------------------------------------------- 53 | 54 | (* Functions/Sequences *) 55 | 56 | \* Enumerable set of sequences of elements from S with length = n 57 | SeqOfLen(S, n) == 58 | CASE n < 0 -> {} 59 | [] OTHER -> [ 1..n -> S ] 60 | 61 | \* Enumerable set of sequences of elements from S with length <= n 62 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 63 | 64 | \* Enumerable set of nonempty sequences of length <= n 65 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 66 | 67 | \* Enumerable set of pairs of elements from sets S1 and S2 68 | \* @type: (Set(A), Set(B)) => Set(<>); 69 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 70 | 71 | \* Nonempty sequences of elements from set S 72 | NESeq(S) == Seq(S) \ {<<>>} 73 | 74 | \* remove (all occurrences of) an element from a sequence 75 | Remove(seq, elem) == 76 | LET RECURSIVE _remove(_, _, _) 77 | _remove(s, e, acc) == 78 | CASE s = <<>> -> acc 79 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 80 | [] OTHER -> _remove(Tail(s), e, acc) 81 | IN _remove(seq, elem, <<>>) 82 | 83 | \* (finite) subsequence predicate 84 | RECURSIVE isSubSeq(_, _) 85 | isSubSeq(s1, s2) == 86 | \/ s1 = <<>> 87 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 88 | [] OTHER -> 89 | LET n == max_set(DOMAIN s2) 90 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 91 | s == [ j \in (i + 1)..n |-> s2[j] ] 92 | IN isSubSeq(Tail(s1), s) 93 | 94 | \* Selects the first element that satisfies the predicate 95 | \* if no element satisfies the predicate, then return <<>> 96 | Select(seq, test(_)) == 97 | LET RECURSIVE select(_) 98 | select(s) == 99 | CASE s = <<>> -> <<>> 100 | [] test(Head(s)) -> Head(s) 101 | [] OTHER -> select(Tail(s)) 102 | IN select(seq) 103 | 104 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 105 | Forall(seq, test(_)) == 106 | LET RECURSIVE forall(_, _) 107 | forall(s, acc) == 108 | IF s = <<>> 109 | THEN acc 110 | ELSE /\ acc 111 | /\ forall(Tail(s), acc /\ test(Head(s))) 112 | IN forall(seq, TRUE) 113 | 114 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 115 | Exists(seq, test(_)) == 116 | LET RECURSIVE exists(_, _) 117 | exists(s, acc) == 118 | IF s = <<>> 119 | THEN acc 120 | ELSE \/ acc 121 | \/ exists(Tail(s), acc \/ test(Head(s))) 122 | IN exists(seq, FALSE) 123 | 124 | Cons(elem, seq) == <> \o seq 125 | 126 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 127 | 128 | ============================================================================= 129 | -------------------------------------------------------------------------------- /p2p/counter/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Int -> T) => Set(T); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | disjoint(S, T) == S \cap T = {} 17 | 18 | \* Nonempty subsets of S 19 | NESubsets(S) == SUBSET S \ {{}} 20 | 21 | \* Subsets of size <= n 22 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | (* Common functions/operators *) 27 | 28 | \* minimum 29 | min[m, n \in Int] == IF m > n THEN n ELSE m 30 | 31 | \* maximum 32 | max[m, n \in Int] == IF m > n THEN m ELSE n 33 | 34 | \* maximum element of a nonempty finite set of naturals 35 | max_set(set) == 36 | LET RECURSIVE _max_set(_, _) 37 | _max_set(S, curr) == 38 | CASE S = {} -> curr 39 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 40 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 41 | [] OTHER -> -1 42 | 43 | \* minimum element of a nonempty finite set of naturals 44 | min_set(set) == 45 | LET RECURSIVE _min_set(_, _) 46 | _min_set(S, curr) == 47 | CASE S = {} -> curr 48 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 49 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 50 | [] OTHER -> -1 51 | 52 | ---------------------------------------------------------------------------- 53 | 54 | (* Functions/Sequences *) 55 | 56 | \* Enumerable set of sequences of elements from S with length = n 57 | SeqOfLen(S, n) == 58 | CASE n < 0 -> {} 59 | [] OTHER -> [ 1..n -> S ] 60 | 61 | \* Enumerable set of sequences of elements from S with length <= n 62 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 63 | 64 | \* Enumerable set of nonempty sequences of length <= n 65 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 66 | 67 | \* Enumerable set of pairs of elements from sets S1 and S2 68 | \* @type: (Set(A), Set(B)) => Set(<>); 69 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 70 | 71 | \* Nonempty sequences of elements from set S 72 | NESeq(S) == Seq(S) \ {<<>>} 73 | 74 | \* remove (all occurrences of) an element from a sequence 75 | Remove(seq, elem) == 76 | LET RECURSIVE _remove(_, _, _) 77 | _remove(s, e, acc) == 78 | CASE s = <<>> -> acc 79 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 80 | [] OTHER -> _remove(Tail(s), e, acc) 81 | IN _remove(seq, elem, <<>>) 82 | 83 | \* (finite) subsequence predicate 84 | RECURSIVE isSubSeq(_, _) 85 | isSubSeq(s1, s2) == 86 | \/ s1 = <<>> 87 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 88 | [] OTHER -> 89 | LET n == max_set(DOMAIN s2) 90 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 91 | s == [ j \in (i + 1)..n |-> s2[j] ] 92 | IN isSubSeq(Tail(s1), s) 93 | 94 | \* Selects the first element that satisfies the predicate 95 | \* if no element satisfies the predicate, then return <<>> 96 | Select(seq, test(_)) == 97 | LET RECURSIVE select(_) 98 | select(s) == 99 | CASE s = <<>> -> <<>> 100 | [] test(Head(s)) -> Head(s) 101 | [] OTHER -> select(Tail(s)) 102 | IN select(seq) 103 | 104 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 105 | Forall(seq, test(_)) == 106 | LET RECURSIVE forall(_, _) 107 | forall(s, acc) == 108 | IF s = <<>> 109 | THEN acc 110 | ELSE /\ acc 111 | /\ forall(Tail(s), acc /\ test(Head(s))) 112 | IN forall(seq, TRUE) 113 | 114 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 115 | Exists(seq, test(_)) == 116 | LET RECURSIVE exists(_, _) 117 | exists(s, acc) == 118 | IF s = <<>> 119 | THEN acc 120 | ELSE \/ acc 121 | \/ exists(Tail(s), acc \/ test(Head(s))) 122 | IN exists(seq, FALSE) 123 | 124 | Cons(elem, seq) == <> \o seq 125 | 126 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 127 | 128 | ============================================================================= 129 | -------------------------------------------------------------------------------- /p2p/counter/Model/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Int -> T) => Set(T); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | disjoint(S, T) == S \cap T = {} 17 | 18 | \* Nonempty subsets of S 19 | NESubsets(S) == SUBSET S \ {{}} 20 | 21 | \* Subsets of size <= n 22 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | (* Common functions/operators *) 27 | 28 | \* minimum 29 | min[m, n \in Int] == IF m > n THEN n ELSE m 30 | 31 | \* maximum 32 | max[m, n \in Int] == IF m > n THEN m ELSE n 33 | 34 | \* maximum element of a nonempty finite set of naturals 35 | max_set(set) == 36 | LET RECURSIVE _max_set(_, _) 37 | _max_set(S, curr) == 38 | CASE S = {} -> curr 39 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 40 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 41 | [] OTHER -> -1 42 | 43 | \* minimum element of a nonempty finite set of naturals 44 | min_set(set) == 45 | LET RECURSIVE _min_set(_, _) 46 | _min_set(S, curr) == 47 | CASE S = {} -> curr 48 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 49 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 50 | [] OTHER -> -1 51 | 52 | ---------------------------------------------------------------------------- 53 | 54 | (* Functions/Sequences *) 55 | 56 | \* Enumerable set of sequences of elements from S with length = n 57 | SeqOfLen(S, n) == 58 | CASE n < 0 -> {} 59 | [] OTHER -> [ 1..n -> S ] 60 | 61 | \* Enumerable set of sequences of elements from S with length <= n 62 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 63 | 64 | \* Enumerable set of nonempty sequences of length <= n 65 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 66 | 67 | \* Enumerable set of pairs of elements from sets S1 and S2 68 | \* @type: (Set(A), Set(B)) => Set(<>); 69 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 70 | 71 | \* Nonempty sequences of elements from set S 72 | NESeq(S) == Seq(S) \ {<<>>} 73 | 74 | \* remove (all occurrences of) an element from a sequence 75 | Remove(seq, elem) == 76 | LET RECURSIVE _remove(_, _, _) 77 | _remove(s, e, acc) == 78 | CASE s = <<>> -> acc 79 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 80 | [] OTHER -> _remove(Tail(s), e, acc) 81 | IN _remove(seq, elem, <<>>) 82 | 83 | \* (finite) subsequence predicate 84 | RECURSIVE isSubSeq(_, _) 85 | isSubSeq(s1, s2) == 86 | \/ s1 = <<>> 87 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 88 | [] OTHER -> 89 | LET n == max_set(DOMAIN s2) 90 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 91 | s == [ j \in (i + 1)..n |-> s2[j] ] 92 | IN isSubSeq(Tail(s1), s) 93 | 94 | \* Selects the first element that satisfies the predicate 95 | \* if no element satisfies the predicate, then return <<>> 96 | Select(seq, test(_)) == 97 | LET RECURSIVE select(_) 98 | select(s) == 99 | CASE s = <<>> -> <<>> 100 | [] test(Head(s)) -> Head(s) 101 | [] OTHER -> select(Tail(s)) 102 | IN select(seq) 103 | 104 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 105 | Forall(seq, test(_)) == 106 | LET RECURSIVE forall(_, _) 107 | forall(s, acc) == 108 | IF s = <<>> 109 | THEN acc 110 | ELSE /\ acc 111 | /\ forall(Tail(s), acc /\ test(Head(s))) 112 | IN forall(seq, TRUE) 113 | 114 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 115 | Exists(seq, test(_)) == 116 | LET RECURSIVE exists(_, _) 117 | exists(s, acc) == 118 | IF s = <<>> 119 | THEN acc 120 | ELSE \/ acc 121 | \/ exists(Tail(s), acc \/ test(Head(s))) 122 | IN exists(seq, FALSE) 123 | 124 | Cons(elem, seq) == <> \o seq 125 | 126 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 127 | 128 | ============================================================================= 129 | -------------------------------------------------------------------------------- /p2p/scheduler_rw/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Int -> T) => Set(T); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | disjoint(S, T) == S \cap T = {} 17 | 18 | \* Nonempty subsets of S 19 | NESubsets(S) == SUBSET S \ {{}} 20 | 21 | \* Subsets of size <= n 22 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | (* Common functions/operators *) 27 | 28 | \* minimum 29 | min[m, n \in Int] == IF m > n THEN n ELSE m 30 | 31 | \* maximum 32 | max[m, n \in Int] == IF m > n THEN m ELSE n 33 | 34 | \* maximum element of a nonempty finite set of naturals 35 | max_set(set) == 36 | LET RECURSIVE _max_set(_, _) 37 | _max_set(S, curr) == 38 | CASE S = {} -> curr 39 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 40 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 41 | [] OTHER -> -1 42 | 43 | \* minimum element of a nonempty finite set of naturals 44 | min_set(set) == 45 | LET RECURSIVE _min_set(_, _) 46 | _min_set(S, curr) == 47 | CASE S = {} -> curr 48 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 49 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 50 | [] OTHER -> -1 51 | 52 | ---------------------------------------------------------------------------- 53 | 54 | (* Functions/Sequences *) 55 | 56 | \* Enumerable set of sequences of elements from S with length = n 57 | SeqOfLen(S, n) == 58 | CASE n < 0 -> {} 59 | [] OTHER -> [ 1..n -> S ] 60 | 61 | \* Enumerable set of sequences of elements from S with length <= n 62 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 63 | 64 | \* Enumerable set of nonempty sequences of length <= n 65 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 66 | 67 | \* Enumerable set of pairs of elements from sets S1 and S2 68 | \* @type: (Set(A), Set(B)) => Set(<>); 69 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 70 | 71 | \* Nonempty sequences of elements from set S 72 | NESeq(S) == Seq(S) \ {<<>>} 73 | 74 | \* remove (all occurrences of) an element from a sequence 75 | Remove(seq, elem) == 76 | LET RECURSIVE _remove(_, _, _) 77 | _remove(s, e, acc) == 78 | CASE s = <<>> -> acc 79 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 80 | [] OTHER -> _remove(Tail(s), e, acc) 81 | IN _remove(seq, elem, <<>>) 82 | 83 | \* (finite) subsequence predicate 84 | RECURSIVE isSubSeq(_, _) 85 | isSubSeq(s1, s2) == 86 | \/ s1 = <<>> 87 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 88 | [] OTHER -> 89 | LET n == max_set(DOMAIN s2) 90 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 91 | s == [ j \in (i + 1)..n |-> s2[j] ] 92 | IN isSubSeq(Tail(s1), s) 93 | 94 | \* Selects the first element that satisfies the predicate 95 | \* if no element satisfies the predicate, then return <<>> 96 | Select(seq, test(_)) == 97 | LET RECURSIVE select(_) 98 | select(s) == 99 | CASE s = <<>> -> <<>> 100 | [] test(Head(s)) -> Head(s) 101 | [] OTHER -> select(Tail(s)) 102 | IN select(seq) 103 | 104 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 105 | Forall(seq, test(_)) == 106 | LET RECURSIVE forall(_, _) 107 | forall(s, acc) == 108 | IF s = <<>> 109 | THEN acc 110 | ELSE /\ acc 111 | /\ forall(Tail(s), acc /\ test(Head(s))) 112 | IN forall(seq, TRUE) 113 | 114 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 115 | Exists(seq, test(_)) == 116 | LET RECURSIVE exists(_, _) 117 | exists(s, acc) == 118 | IF s = <<>> 119 | THEN acc 120 | ELSE \/ acc 121 | \/ exists(Tail(s), acc \/ test(Head(s))) 122 | IN exists(seq, FALSE) 123 | 124 | Cons(elem, seq) == <> \o seq 125 | 126 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 127 | 128 | ============================================================================= 129 | -------------------------------------------------------------------------------- /shell/high_level/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Seq(T)) => Set(T); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | disjoint(S, T) == S \cap T = {} 17 | 18 | \* Nonempty subsets of S 19 | NESubsets(S) == SUBSET S \ {{}} 20 | 21 | \* Subsets of size <= n 22 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | (* Common functions/operators *) 27 | 28 | \* minimum 29 | min[m, n \in Int] == IF m > n THEN n ELSE m 30 | 31 | \* maximum 32 | max[m, n \in Int] == IF m > n THEN m ELSE n 33 | 34 | \* maximum element of a nonempty finite set of naturals 35 | max_set(set) == 36 | LET RECURSIVE _max_set(_, _) 37 | _max_set(S, curr) == 38 | CASE S = {} -> curr 39 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 40 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 41 | [] OTHER -> -1 42 | 43 | \* minimum element of a nonempty finite set of naturals 44 | min_set(set) == 45 | LET RECURSIVE _min_set(_, _) 46 | _min_set(S, curr) == 47 | CASE S = {} -> curr 48 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 49 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 50 | [] OTHER -> -1 51 | 52 | ---------------------------------------------------------------------------- 53 | 54 | (* Functions/Sequences *) 55 | 56 | \* Enumerable set of sequences of elements from S with length = n 57 | SeqOfLen(S, n) == 58 | CASE n < 0 -> {} 59 | [] OTHER -> [ 1..n -> S ] 60 | 61 | \* Enumerable set of sequences of elements from S with length <= n 62 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 63 | 64 | \* Enumerable set of nonempty sequences of length <= n 65 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 66 | 67 | \* Enumerable set of pairs of elements from sets S1 and S2 68 | \* @type: (Set(A), Set(B)) => Set(<>); 69 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 70 | 71 | \* Nonempty sequences of elements from set S 72 | NESeq(S) == Seq(S) \ {<<>>} 73 | 74 | \* remove (all occurrences of) an element from a sequence 75 | Remove(seq, elem) == 76 | LET RECURSIVE _remove(_, _, _) 77 | _remove(s, e, acc) == 78 | CASE s = <<>> -> acc 79 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 80 | [] OTHER -> _remove(Tail(s), e, acc) 81 | IN _remove(seq, elem, <<>>) 82 | 83 | \* (finite) subsequence predicate 84 | RECURSIVE isSubSeq(_, _) 85 | isSubSeq(s1, s2) == 86 | \/ s1 = <<>> 87 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 88 | [] OTHER -> 89 | LET n == max_set(DOMAIN s2) 90 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 91 | s == [ j \in (i + 1)..n |-> s2[j] ] 92 | IN isSubSeq(Tail(s1), s) 93 | 94 | \* Selects the first element that satisfies the predicate 95 | \* if no element satisfies the predicate, then return <<>> 96 | Select(seq, test(_)) == 97 | LET RECURSIVE select(_) 98 | select(s) == 99 | CASE s = <<>> -> <<>> 100 | [] test(Head(s)) -> Head(s) 101 | [] OTHER -> select(Tail(s)) 102 | IN select(seq) 103 | 104 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 105 | Forall(seq, test(_)) == 106 | LET RECURSIVE forall(_, _) 107 | forall(s, acc) == 108 | IF s = <<>> 109 | THEN acc 110 | ELSE /\ acc 111 | /\ forall(Tail(s), acc /\ test(Head(s))) 112 | IN forall(seq, TRUE) 113 | 114 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 115 | Exists(seq, test(_)) == 116 | LET RECURSIVE exists(_, _) 117 | exists(s, acc) == 118 | IF s = <<>> 119 | THEN acc 120 | ELSE \/ acc 121 | \/ exists(Tail(s), acc \/ test(Head(s))) 122 | IN exists(seq, FALSE) 123 | 124 | Cons(elem, seq) == <> \o seq 125 | 126 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 127 | 128 | ============================================================================= 129 | -------------------------------------------------------------------------------- /p2p/scheduler_rw/Model/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Int -> T) => Set(T); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | disjoint(S, T) == S \cap T = {} 17 | 18 | \* Nonempty subsets of S 19 | NESubsets(S) == SUBSET S \ {{}} 20 | 21 | \* Subsets of size <= n 22 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | (* Common functions/operators *) 27 | 28 | \* minimum 29 | min[m, n \in Int] == IF m > n THEN n ELSE m 30 | 31 | \* maximum 32 | max[m, n \in Int] == IF m > n THEN m ELSE n 33 | 34 | \* maximum element of a nonempty finite set of naturals 35 | max_set(set) == 36 | LET RECURSIVE _max_set(_, _) 37 | _max_set(S, curr) == 38 | CASE S = {} -> curr 39 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 40 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 41 | [] OTHER -> -1 42 | 43 | \* minimum element of a nonempty finite set of naturals 44 | min_set(set) == 45 | LET RECURSIVE _min_set(_, _) 46 | _min_set(S, curr) == 47 | CASE S = {} -> curr 48 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 49 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 50 | [] OTHER -> -1 51 | 52 | ---------------------------------------------------------------------------- 53 | 54 | (* Functions/Sequences *) 55 | 56 | \* Enumerable set of sequences of elements from S with length = n 57 | SeqOfLen(S, n) == 58 | CASE n < 0 -> {} 59 | [] OTHER -> [ 1..n -> S ] 60 | 61 | \* Enumerable set of sequences of elements from S with length <= n 62 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 63 | 64 | \* Enumerable set of nonempty sequences of length <= n 65 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 66 | 67 | \* Enumerable set of pairs of elements from sets S1 and S2 68 | \* @type: (Set(A), Set(B)) => Set(<>); 69 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 70 | 71 | \* Nonempty sequences of elements from set S 72 | NESeq(S) == Seq(S) \ {<<>>} 73 | 74 | \* remove (all occurrences of) an element from a sequence 75 | Remove(seq, elem) == 76 | LET RECURSIVE _remove(_, _, _) 77 | _remove(s, e, acc) == 78 | CASE s = <<>> -> acc 79 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 80 | [] OTHER -> _remove(Tail(s), e, acc) 81 | IN _remove(seq, elem, <<>>) 82 | 83 | \* (finite) subsequence predicate 84 | RECURSIVE isSubSeq(_, _) 85 | isSubSeq(s1, s2) == 86 | \/ s1 = <<>> 87 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 88 | [] OTHER -> 89 | LET n == max_set(DOMAIN s2) 90 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 91 | s == [ j \in (i + 1)..n |-> s2[j] ] 92 | IN isSubSeq(Tail(s1), s) 93 | 94 | \* Selects the first element that satisfies the predicate 95 | \* if no element satisfies the predicate, then return <<>> 96 | Select(seq, test(_)) == 97 | LET RECURSIVE select(_) 98 | select(s) == 99 | CASE s = <<>> -> <<>> 100 | [] test(Head(s)) -> Head(s) 101 | [] OTHER -> select(Tail(s)) 102 | IN select(seq) 103 | 104 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 105 | Forall(seq, test(_)) == 106 | LET RECURSIVE forall(_, _) 107 | forall(s, acc) == 108 | IF s = <<>> 109 | THEN acc 110 | ELSE /\ acc 111 | /\ forall(Tail(s), acc /\ test(Head(s))) 112 | IN forall(seq, TRUE) 113 | 114 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 115 | Exists(seq, test(_)) == 116 | LET RECURSIVE exists(_, _) 117 | exists(s, acc) == 118 | IF s = <<>> 119 | THEN acc 120 | ELSE \/ acc 121 | \/ exists(Tail(s), acc \/ test(Head(s))) 122 | IN exists(seq, FALSE) 123 | 124 | Cons(elem, seq) == <> \o seq 125 | 126 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 127 | 128 | ============================================================================= 129 | -------------------------------------------------------------------------------- /shell/high_level/Model_simple/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Seq(T)) => Set(T); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | disjoint(S, T) == S \cap T = {} 17 | 18 | \* Nonempty subsets of S 19 | NESubsets(S) == SUBSET S \ {{}} 20 | 21 | \* Subsets of size <= n 22 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | (* Common functions/operators *) 27 | 28 | \* minimum 29 | min[m, n \in Int] == IF m > n THEN n ELSE m 30 | 31 | \* maximum 32 | max[m, n \in Int] == IF m > n THEN m ELSE n 33 | 34 | \* maximum element of a nonempty finite set of naturals 35 | max_set(set) == 36 | LET RECURSIVE _max_set(_, _) 37 | _max_set(S, curr) == 38 | CASE S = {} -> curr 39 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 40 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 41 | [] OTHER -> -1 42 | 43 | \* minimum element of a nonempty finite set of naturals 44 | min_set(set) == 45 | LET RECURSIVE _min_set(_, _) 46 | _min_set(S, curr) == 47 | CASE S = {} -> curr 48 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 49 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 50 | [] OTHER -> -1 51 | 52 | ---------------------------------------------------------------------------- 53 | 54 | (* Functions/Sequences *) 55 | 56 | \* Enumerable set of sequences of elements from S with length = n 57 | SeqOfLen(S, n) == 58 | CASE n < 0 -> {} 59 | [] OTHER -> [ 1..n -> S ] 60 | 61 | \* Enumerable set of sequences of elements from S with length <= n 62 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 63 | 64 | \* Enumerable set of nonempty sequences of length <= n 65 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 66 | 67 | \* Enumerable set of pairs of elements from sets S1 and S2 68 | \* @type: (Set(A), Set(B)) => Set(<>); 69 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 70 | 71 | \* Nonempty sequences of elements from set S 72 | NESeq(S) == Seq(S) \ {<<>>} 73 | 74 | \* remove (all occurrences of) an element from a sequence 75 | Remove(seq, elem) == 76 | LET RECURSIVE _remove(_, _, _) 77 | _remove(s, e, acc) == 78 | CASE s = <<>> -> acc 79 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 80 | [] OTHER -> _remove(Tail(s), e, acc) 81 | IN _remove(seq, elem, <<>>) 82 | 83 | \* (finite) subsequence predicate 84 | RECURSIVE isSubSeq(_, _) 85 | \* @type: (Seq(t), Seq(t)) => Bool; 86 | isSubSeq(s1, s2) == 87 | \/ s1 = <<>> 88 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 89 | [] OTHER -> 90 | LET n == Len(s2) 91 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 92 | s == [ j \in (i + 1)..n |-> s2[j] ] 93 | IN isSubSeq(Tail(s1), s) 94 | 95 | \* Selects the first element that satisfies the predicate 96 | \* if no element satisfies the predicate, then return <<>> 97 | Select(seq, test(_)) == 98 | LET RECURSIVE select(_) 99 | select(s) == 100 | CASE s = <<>> -> <<>> 101 | [] test(Head(s)) -> Head(s) 102 | [] OTHER -> select(Tail(s)) 103 | IN select(seq) 104 | 105 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 106 | Forall(seq, test(_)) == 107 | LET RECURSIVE forall(_, _) 108 | forall(s, acc) == 109 | IF s = <<>> 110 | THEN acc 111 | ELSE /\ acc 112 | /\ forall(Tail(s), acc /\ test(Head(s))) 113 | IN forall(seq, TRUE) 114 | 115 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 116 | Exists(seq, test(_)) == 117 | LET RECURSIVE exists(_, _) 118 | exists(s, acc) == 119 | IF s = <<>> 120 | THEN acc 121 | ELSE \/ acc 122 | \/ exists(Tail(s), acc \/ test(Head(s))) 123 | IN exists(seq, FALSE) 124 | 125 | Cons(elem, seq) == <> \o seq 126 | 127 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 128 | 129 | ============================================================================= 130 | -------------------------------------------------------------------------------- /shell/high_level/Model_more/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | \* @type: (Seq(T)) => Set(T); 14 | ToSet(f) == { f[i] : i \in DOMAIN f } 15 | 16 | disjoint(S, T) == S \cap T = {} 17 | 18 | \* Nonempty subsets of S 19 | NESubsets(S) == SUBSET S \ {{}} 20 | 21 | \* Subsets of size <= n 22 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | (* Common functions/operators *) 27 | 28 | \* minimum 29 | min[m, n \in Int] == IF m > n THEN n ELSE m 30 | 31 | \* maximum 32 | max[m, n \in Int] == IF m > n THEN m ELSE n 33 | 34 | \* maximum element of a nonempty finite set of naturals 35 | max_set(set) == 36 | LET RECURSIVE _max_set(_, _) 37 | _max_set(S, curr) == 38 | CASE S = {} -> curr 39 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 40 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 41 | [] OTHER -> -1 42 | 43 | \* minimum element of a nonempty finite set of naturals 44 | min_set(set) == 45 | LET RECURSIVE _min_set(_, _) 46 | _min_set(S, curr) == 47 | CASE S = {} -> curr 48 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 49 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 50 | [] OTHER -> -1 51 | 52 | ---------------------------------------------------------------------------- 53 | 54 | (* Functions/Sequences *) 55 | 56 | \* Enumerable set of sequences of elements from S with length = n 57 | SeqOfLen(S, n) == 58 | CASE n < 0 -> {} 59 | [] OTHER -> [ 1..n -> S ] 60 | 61 | \* Enumerable set of sequences of elements from S with length <= n 62 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 63 | 64 | \* Enumerable set of nonempty sequences of length <= n 65 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 66 | 67 | \* Enumerable set of pairs of elements from sets S1 and S2 68 | \* @type: (Set(A), Set(B)) => Set(<>); 69 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 70 | 71 | \* Nonempty sequences of elements from set S 72 | NESeq(S) == Seq(S) \ {<<>>} 73 | 74 | \* remove (all occurrences of) an element from a sequence 75 | Remove(seq, elem) == 76 | LET RECURSIVE _remove(_, _, _) 77 | _remove(s, e, acc) == 78 | CASE s = <<>> -> acc 79 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 80 | [] OTHER -> _remove(Tail(s), e, acc) 81 | IN _remove(seq, elem, <<>>) 82 | 83 | \* (finite) subsequence predicate 84 | RECURSIVE isSubSeq(_, _) 85 | \* @type: (Seq(t), Seq(t)) => Bool; 86 | isSubSeq(s1, s2) == 87 | \/ s1 = <<>> 88 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 89 | [] OTHER -> 90 | LET n == max_set(DOMAIN s2) 91 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 92 | s == [ j \in (i + 1)..n |-> s2[j] ] 93 | IN isSubSeq(Tail(s1), s) 94 | 95 | \* Selects the first element that satisfies the predicate 96 | \* if no element satisfies the predicate, then return <<>> 97 | Select(seq, test(_)) == 98 | LET RECURSIVE select(_) 99 | select(s) == 100 | CASE s = <<>> -> <<>> 101 | [] test(Head(s)) -> Head(s) 102 | [] OTHER -> select(Tail(s)) 103 | IN select(seq) 104 | 105 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 106 | Forall(seq, test(_)) == 107 | LET RECURSIVE forall(_, _) 108 | forall(s, acc) == 109 | IF s = <<>> 110 | THEN acc 111 | ELSE /\ acc 112 | /\ forall(Tail(s), acc /\ test(Head(s))) 113 | IN forall(seq, TRUE) 114 | 115 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 116 | Exists(seq, test(_)) == 117 | LET RECURSIVE exists(_, _) 118 | exists(s, acc) == 119 | IF s = <<>> 120 | THEN acc 121 | ELSE \/ acc 122 | \/ exists(Tail(s), acc \/ test(Head(s))) 123 | IN exists(seq, FALSE) 124 | 125 | Cons(elem, seq) == <> \o seq 126 | 127 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 128 | 129 | ============================================================================= 130 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/DB.tla: -------------------------------------------------------------------------------- 1 | -------------------------------- MODULE DB --------------------------------- 2 | 3 | EXTENDS DB_Defs 4 | 5 | \* CONSTANTS 6 | \* numChains, \* number of chains 7 | \* sizeBound \* bound on many things 8 | 9 | \* \* Node variables 10 | \* VARIABLES 11 | \* node_active, \* SUBSET Chains 12 | \* node_blocks, \* Chains -> Branches -> Seq(Blocks) 13 | \* node_branches, \* Chains -> Seq(Branches) 14 | \* node_headers, \* Chains -> Branches -> Seq(Headers) 15 | \* node_height \* Chains -> Branches -> Heights \cup {-1} 16 | 17 | \* \* Network variables 18 | \* VARIABLES 19 | \* blocks, \* Chains -> Branches -> Seq(Blocks) 20 | \* branch, \* Chains -> Branches 21 | \* chains, \* Chains 22 | \* height \* Chains -> Branches -> Heights \cup {-1} 23 | 24 | network_vars == <> 25 | node_vars == <> 26 | vars == <> 27 | 28 | ---------------------------------------------------------------------------- 29 | 30 | Activation == INSTANCE DB_Activation \* Activation and Deactivation actions 31 | Defs == INSTANCE DB_Defs \* ubiquitous definitions 32 | Maintenance == INSTANCE DB_Maintenance \* Block production, new chain, new branch actions 33 | Request == INSTANCE DB_Request \* Request actions 34 | Initialize == INSTANCE DB_Init \* initial states 35 | TypeOK == INSTANCE DB_TypeOK \* type invariants 36 | Invariants == INSTANCE DB_Invariants \* other invariants and properties 37 | 38 | ---------------------------------------------------------------------------- 39 | 40 | (*********************) 41 | (* Initial predicate *) 42 | (*********************) 43 | 44 | \* Simple "empty" initial 45 | \*Init == DB_Init!Init_empty 46 | 47 | \* Various initial states representing different "checkpoints" in the evolution of the model 48 | Init == \E n \in Initialize!Init_options : Initialize!Initialize(n) 49 | 50 | ---------------------------------------------------------------------------- 51 | 52 | (**************************************************************) 53 | (* Next actions *) 54 | (* - Activation: an inactive node becomes active on a chain *) 55 | (* - Deactivation: an active node becomes inactive on a chain *) 56 | (* - Handle_msg: a node reacts to a message *) 57 | (* - New_block: a new block is produced *) 58 | (* - New_branch: a new branch is created *) 59 | (* - New_chain: a new chain is created *) 60 | (* - Get_current_branch: node retrieves the current branch *) 61 | (* - Get_current_head: node retrieves the current head *) 62 | (* - Get_block_header: node retrieves a block header *) 63 | (* - Get_operations: node retrieves a block's operations *) 64 | (**************************************************************) 65 | 66 | Next == 67 | \* Activation actions 68 | \/ Activation!Activation 69 | \/ Activation!Deactivation 70 | \* Maintenance actions 71 | \/ Maintenance!New_block 72 | \/ Maintenance!New_chain 73 | \/ Maintenance!New_branch 74 | \* Request actions 75 | \/ Request!Get_current_branch 76 | \/ Request!Get_current_head 77 | \/ Request!Get_block_header 78 | \/ Request!Get_operations 79 | 80 | (***********************) 81 | (* Fairness conditions *) 82 | (***********************) 83 | 84 | Fairness == 85 | /\ WF_vars(Maintenance!New_block) 86 | /\ WF_vars(Maintenance!New_branch) 87 | /\ WF_vars(Maintenance!New_chain) 88 | /\ SF_vars(Activation!Activation) 89 | /\ SF_vars(Request!Get_current_branch) 90 | /\ SF_vars(Request!Get_current_head) 91 | /\ SF_vars(Request!Get_block_header) 92 | /\ SF_vars(Request!Get_operations) 93 | 94 | ---------------------------------------------------------------------------- 95 | 96 | (*****************) 97 | (* Specification *) 98 | (*****************) 99 | 100 | Spec == Init /\ [][Next]_vars 101 | 102 | FairSpec == Spec /\ Fairness 103 | 104 | ---------------------------------------------------------------------------- 105 | 106 | \* Temporal property 107 | ActiveNodeEventuallySyncs == \A chain \in Chains : 108 | /\ []<>(active[chain]) 109 | /\ []<><>_<> 110 | => Invariants!EventuallySyncs(chain) 111 | 112 | THEOREM Safe == Spec => []TypeOK!TypeOK 113 | 114 | THEOREM Consistent == Spec => []Invariants!Agreement 115 | 116 | THEOREM EventuallySynced == FairSpec => ActiveNodeEventuallySyncs 117 | 118 | ============================================================================= 119 | -------------------------------------------------------------------------------- /shell/distributed_db/DB_Advertise.tla: -------------------------------------------------------------------------------- 1 | --------------------------- MODULE DB_Advertise ---------------------------- 2 | 3 | CONSTANTS numChains, numNodes, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, blocks, branch, chains, mailbox, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | LOCAL INSTANCE Utils 11 | 12 | ---------------------------------------------------------------------------- 13 | 14 | (*********************) 15 | (* Advertise actions *) 16 | (*********************) 17 | 18 | (* Advertise messages are explicitly passed between nodes *) 19 | 20 | \* Advertise messages can serve as responses to specific requests, i.e. one recipient, 21 | \* or they can be broadcast to all active nodes on a chain 22 | 23 | \* [node] advertises their current branch of [chain] 24 | Ad_current_branch(node, chain) == 25 | LET b == Head(node_branches[node][chain]) 26 | msg == PartialMsg("Current_branch", [ branch |-> b ]) 27 | IN /\ mailbox' = [ mailbox EXCEPT ![chain] = BroadcastNodes(@, node, chain, msg) ] 28 | /\ UNCHANGED <> 29 | /\ UNCHANGED <> 31 | 32 | \* An active node on some chain advertises their current branch 33 | Ad_node_branch == 34 | \E chain \in activeChains : 35 | \E from \in activeNodes[chain] : 36 | /\ branchSet[from, chain] /= {} \* [from] knows about a branch on [chain] 37 | /\ activeNodes[chain] \ {from} /= {} \* there are other active nodes on [chain] besides [sys] 38 | /\ Ad_current_branch(from, chain) \* [from] advertises their current branch 39 | 40 | \* [sys] advertises the current branch [b] of [chain] 41 | Ad_sys_current_branch(chain) == 42 | LET b == branch[chain] 43 | msg == PartialMsg("Current_branch", [ branch |-> b ]) 44 | IN /\ mailbox' = [ mailbox EXCEPT ![chain] = Broadcast(@, sys, chain, msg) ] 45 | /\ UNCHANGED <> 46 | /\ UNCHANGED <> 48 | 49 | \* [sys] advertises the current branch of some chain 50 | Ad_sys_branch == 51 | \E chain \in activeChains : 52 | /\ activeNodes[chain] /= {} \* there are active nodes on [chain] 53 | /\ Ad_sys_current_branch(chain) \* [sys] advertises current branch 54 | 55 | Advertise_branch == Ad_node_branch \/ Ad_sys_branch 56 | 57 | \* [node] advertises their current head of branch [b] on [chain] 58 | Ad_current_head(node, chain, b) == 59 | LET h == Head(node_blocks[node][chain][b]).header.height 60 | msg == PartialMsg("Current_head", [ branch |-> b, height |-> h ]) 61 | IN /\ mailbox' = [ mailbox EXCEPT ![chain] = BroadcastNodes(@, node, chain, msg) ] 62 | /\ UNCHANGED <> 63 | /\ UNCHANGED <> 65 | 66 | \* An active node on some chain advertises their current head 67 | Ad_node_head == 68 | \E chain \in activeChains : 69 | \E b \in activeBranches[chain], 70 | from \in activeNodes[chain] : 71 | /\ current_height[from, chain, b] >= 0 \* [node] knows about a block on branch [b] of [chain] 72 | /\ activeNodes[chain] \ {from} /= {} \* there are other active nodes on [chain] 73 | /\ Ad_current_head(from, chain, b) \* [node] advertises their current head 74 | 75 | \* [sys] advertises the current [head] of branch [b] on [chain] 76 | Ad_sys_current_head(chain, b) == 77 | LET h == height[chain][b] 78 | msg == PartialMsg("Current_head", [ branch |-> b, height |-> h ]) 79 | IN /\ mailbox' = [ mailbox EXCEPT ![chain] = Broadcast(@, sys, chain, msg) ] 80 | /\ UNCHANGED <> 81 | /\ UNCHANGED <> 83 | 84 | \* [sys] advertises the current head of some branch on some chain 85 | Ad_sys_head == 86 | \E chain \in activeChains : 87 | \E b \in activeBranches[chain] : 88 | /\ height[chain][b] >= 0 \* there is a block on branch [b] of [chain] 89 | /\ activeNodes[chain] /= {} \* there are active nodes on [chain] 90 | /\ Ad_sys_current_head(chain, b) \* [sys] advertises current head 91 | 92 | Advertise_head == Ad_node_head \/ Ad_sys_head 93 | 94 | ============================================================================= 95 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/DB.tla: -------------------------------------------------------------------------------- 1 | -------------------------------- MODULE DB --------------------------------- 2 | 3 | EXTENDS DB_Defs 4 | 5 | \* CONSTANTS 6 | \* numChains, \* number of chains 7 | \* sizeBound \* bound on many things 8 | 9 | \* \* Node variables 10 | \* VARIABLES 11 | \* node_active, \* SUBSET Chains 12 | \* node_blocks, \* Chains -> Branches -> Seq(Blocks) 13 | \* node_branches, \* Chains -> Seq(Branches) 14 | \* node_headers, \* Chains -> Branches -> Seq(Headers) 15 | \* node_height \* Chains -> Branches -> Heights \cup {-1} 16 | 17 | \* \* Network variables 18 | \* VARIABLES 19 | \* blocks, \* Chains -> Branches -> Seq(Blocks) 20 | \* branch, \* Chains -> Branches 21 | \* chains, \* Chains 22 | \* height \* Chains -> Branches -> Heights \cup {-1} 23 | 24 | network_vars == <> 25 | node_vars == <> 26 | vars == <> 27 | 28 | ---------------------------------------------------------------------------- 29 | 30 | Activation == INSTANCE DB_Activation \* Activation and Deactivation actions 31 | Defs == INSTANCE DB_Defs \* ubiquitous definitions 32 | Maintenance == INSTANCE DB_Maintenance \* Block production, new chain, new branch actions 33 | Request == INSTANCE DB_Request \* Request actions 34 | Initialize == INSTANCE DB_Init \* initial states 35 | TypeOK == INSTANCE DB_TypeOK \* type invariants 36 | Invariants == INSTANCE DB_Invariants \* other invariants and properties 37 | 38 | ---------------------------------------------------------------------------- 39 | 40 | (*********************) 41 | (* Initial predicate *) 42 | (*********************) 43 | 44 | \* Simple "empty" initial 45 | \*Init == DB_Init!Init_empty 46 | 47 | \* Various initial states representing different "checkpoints" in the evolution of the model 48 | Init == \E n \in Initialize!Init_options : Initialize!Initialize(n) 49 | 50 | ---------------------------------------------------------------------------- 51 | 52 | (**************************************************************) 53 | (* Next actions *) 54 | (* - Activation: an inactive node becomes active on a chain *) 55 | (* - Deactivation: an active node becomes inactive on a chain *) 56 | (* - Handle_msg: a node reacts to a message *) 57 | (* - New_block: a new block is produced *) 58 | (* - New_branch: a new branch is created *) 59 | (* - New_chain: a new chain is created *) 60 | (* - Get_current_branch: node retrieves the current branch *) 61 | (* - Get_current_head: node retrieves the current head *) 62 | (* - Get_block_header: node retrieves a block header *) 63 | (* - Get_operations: node retrieves a block's operations *) 64 | (**************************************************************) 65 | 66 | Next == 67 | \* Activation actions 68 | \/ Activation!Activation 69 | \/ Activation!Deactivation 70 | \* Maintenance actions 71 | \/ Maintenance!New_block 72 | \/ Maintenance!New_chain 73 | \/ Maintenance!New_branch 74 | \* Request actions 75 | \/ Request!Get_current_branch 76 | \/ Request!Get_current_head 77 | \/ Request!Get_block_header 78 | \/ Request!Get_operations 79 | 80 | (***********************) 81 | (* Fairness conditions *) 82 | (***********************) 83 | 84 | Fairness == 85 | /\ WF_vars(Maintenance!New_block) 86 | /\ WF_vars(Maintenance!New_branch) 87 | /\ WF_vars(Maintenance!New_chain) 88 | /\ SF_vars(Activation!Activation) 89 | /\ SF_vars(Request!Get_current_branch) 90 | /\ SF_vars(Request!Get_current_head) 91 | /\ SF_vars(Request!Get_block_header) 92 | /\ SF_vars(Request!Get_operations) 93 | 94 | ---------------------------------------------------------------------------- 95 | 96 | (*****************) 97 | (* Specification *) 98 | (*****************) 99 | 100 | Spec == Init /\ [][Next]_vars 101 | 102 | FairSpec == Spec /\ Fairness 103 | 104 | ---------------------------------------------------------------------------- 105 | 106 | \* Temporal property 107 | ActiveNodeEventuallySyncs == \A chain \in Chains : 108 | /\ []<>(active[chain]) 109 | /\ []<><>_<> 110 | => Invariants!EventuallySyncs(chain) 111 | 112 | THEOREM Safe == Spec => []TypeOK!TypeOK 113 | 114 | THEOREM Consistent == Spec => []Invariants!Agreement 115 | 116 | THEOREM EventuallySynced == FairSpec => ActiveNodeEventuallySyncs 117 | 118 | ============================================================================= 119 | -------------------------------------------------------------------------------- /shell/distributed_db/DistributedDB.toolbox/Model_1/DB_Advertise.tla: -------------------------------------------------------------------------------- 1 | --------------------------- MODULE DB_Advertise ---------------------------- 2 | 3 | CONSTANTS numChains, numNodes, sizeBound 4 | 5 | VARIABLES node_active, node_blocks, node_branches, node_headers, node_height, node_incoming, node_sent, 6 | active, blocks, branch, chains, mailbox, height, sysmsgs 7 | 8 | LOCAL INSTANCE DB_Defs 9 | LOCAL INSTANCE DB_Messages 10 | LOCAL INSTANCE Utils 11 | 12 | ---------------------------------------------------------------------------- 13 | 14 | (*********************) 15 | (* Advertise actions *) 16 | (*********************) 17 | 18 | (* Advertise messages are explicitly passed between nodes *) 19 | 20 | \* Advertise messages can serve as responses to specific requests, i.e. one recipient, 21 | \* or they can be broadcast to all active nodes on a chain 22 | 23 | \* [node] advertises their current branch of [chain] 24 | Ad_current_branch(node, chain) == 25 | LET b == Head(node_branches[node][chain]) 26 | msg == PartialMsg("Current_branch", [ branch |-> b ]) 27 | IN /\ mailbox' = [ mailbox EXCEPT ![chain] = BroadcastNodes(@, node, chain, msg) ] 28 | /\ UNCHANGED <> 29 | /\ UNCHANGED <> 31 | 32 | \* An active node on some chain advertises their current branch 33 | Ad_node_branch == 34 | \E chain \in activeChains : 35 | \E from \in activeNodes[chain] : 36 | /\ branchSet[from, chain] /= {} \* [from] knows about a branch on [chain] 37 | /\ activeNodes[chain] \ {from} /= {} \* there are other active nodes on [chain] besides [sys] 38 | /\ Ad_current_branch(from, chain) \* [from] advertises their current branch 39 | 40 | \* [sys] advertises the current branch [b] of [chain] 41 | Ad_sys_current_branch(chain) == 42 | LET b == branch[chain] 43 | msg == PartialMsg("Current_branch", [ branch |-> b ]) 44 | IN /\ mailbox' = [ mailbox EXCEPT ![chain] = Broadcast(@, sys, chain, msg) ] 45 | /\ UNCHANGED <> 46 | /\ UNCHANGED <> 48 | 49 | \* [sys] advertises the current branch of some chain 50 | Ad_sys_branch == 51 | \E chain \in activeChains : 52 | /\ activeNodes[chain] /= {} \* there are active nodes on [chain] 53 | /\ Ad_sys_current_branch(chain) \* [sys] advertises current branch 54 | 55 | Advertise_branch == Ad_node_branch \/ Ad_sys_branch 56 | 57 | \* [node] advertises their current head of branch [b] on [chain] 58 | Ad_current_head(node, chain, b) == 59 | LET h == Head(node_blocks[node][chain][b]).header.height 60 | msg == PartialMsg("Current_head", [ branch |-> b, height |-> h ]) 61 | IN /\ mailbox' = [ mailbox EXCEPT ![chain] = BroadcastNodes(@, node, chain, msg) ] 62 | /\ UNCHANGED <> 63 | /\ UNCHANGED <> 65 | 66 | \* An active node on some chain advertises their current head 67 | Ad_node_head == 68 | \E chain \in activeChains : 69 | \E b \in activeBranches[chain], 70 | from \in activeNodes[chain] : 71 | /\ current_height[from, chain, b] >= 0 \* [node] knows about a block on branch [b] of [chain] 72 | /\ activeNodes[chain] \ {from} /= {} \* there are other active nodes on [chain] 73 | /\ Ad_current_head(from, chain, b) \* [node] advertises their current head 74 | 75 | \* [sys] advertises the current [head] of branch [b] on [chain] 76 | Ad_sys_current_head(chain, b) == 77 | LET h == height[chain][b] 78 | msg == PartialMsg("Current_head", [ branch |-> b, height |-> h ]) 79 | IN /\ mailbox' = [ mailbox EXCEPT ![chain] = Broadcast(@, sys, chain, msg) ] 80 | /\ UNCHANGED <> 81 | /\ UNCHANGED <> 83 | 84 | \* [sys] advertises the current head of some branch on some chain 85 | Ad_sys_head == 86 | \E chain \in activeChains : 87 | \E b \in activeBranches[chain] : 88 | /\ height[chain][b] >= 0 \* there is a block on branch [b] of [chain] 89 | /\ activeNodes[chain] /= {} \* there are active nodes on [chain] 90 | /\ Ad_sys_current_head(chain, b) \* [sys] advertises current head 91 | 92 | Advertise_head == Ad_node_head \/ Ad_sys_head 93 | 94 | ============================================================================= 95 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/DB_TypeOK.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE DB_TypeOK ------------------------------- 2 | 3 | (******************************) 4 | (* Enumerable type invariants *) 5 | (******************************) 6 | 7 | EXTENDS DB_Defs 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | \* Avoid silliness 12 | (*********************************************************) 13 | (* Network variables *) 14 | (* branch : Chains -> Branches *) 15 | (* blocks : Chains -> Branches -> BoundedSeq(Blocks) *) 16 | (* chains : Chains *) 17 | (* height : Chains -> Branches -> Heights \cup {-1} *) 18 | (*********************************************************) 19 | 20 | \* branch 21 | BranchOK == 22 | \A chain \in Chains : 23 | /\ DOMAIN branch = Chains 24 | /\ branch[chain] \in Branches \cup {-1} 25 | /\ chain \in activeChains => branch[chain] >= 0 26 | 27 | \* blocks 28 | BlocksOK == 29 | \A chain \in Chains : 30 | \A b \in Branches : 31 | LET blks == blocks[chain][b] 32 | IN /\ DOMAIN blocks = Chains 33 | /\ DOMAIN blocks[chain] = Branches 34 | /\ Len(blks) <= sizeBound + 1 \* height of each branch <= sizeBound 35 | /\ Forall(blks, isBlock) \* all blocks are valid 36 | /\ b \in activeBranches[chain] => blks /= <<>> \* active branches have blocks 37 | 38 | \* chains 39 | ChainsOK == chains \in Chains 40 | 41 | \* height 42 | HeightOK == 43 | \A chain \in Chains : 44 | \A b \in Branches : 45 | /\ DOMAIN height = Chains 46 | /\ DOMAIN height[chain] = Branches 47 | /\ height[chain][b] \in Heights \cup {-1} 48 | /\ b \in activeBranches[chain] => height[chain][b] >= 0 49 | 50 | \* check all fields of network_info 51 | NetworkOK == 52 | /\ BranchOK 53 | /\ BlocksOK 54 | /\ ChainsOK 55 | /\ HeightOK 56 | 57 | -------------------------------------------------------------------------------- 58 | 59 | (*********************************************************************) 60 | (* Node variables *) 61 | (* node_active : Nodes -> SUBSET Chains *) 62 | (* node_blocks : Nodes -> Chains -> Branches -> BoundedSeq(Blocks) *) 63 | (* node_branches : Nodes -> Chains -> BoundedSeq(Branches) *) 64 | (* node_headers : Nodes -> Chains -> BoundedSeq(Headers) *) 65 | (* node_height : Nodes -> Chains -> Branches -> Heights \cup {-1} *) 66 | (*********************************************************************) 67 | 68 | \* node_active 69 | NodeActiveOK == node_active \subseteq Chains 70 | 71 | \* node_blocks 72 | NodeBlocksOK == 73 | \A chain \in Chains : 74 | \A b \in Branches : 75 | LET blks == node_blocks[chain][b] IN 76 | /\ DOMAIN node_blocks = Chains 77 | /\ DOMAIN node_blocks[chain] = Branches 78 | /\ Len(blks) <= sizeBound + 1 \* height of each block <= sizeBound 79 | /\ Forall(blks, isBlock) \* all blocks are valid 80 | 81 | \* node_branches 82 | NodeBranchesOK == 83 | \A chain \in Chains : 84 | LET branches == node_branches[chain] IN 85 | /\ DOMAIN node_branches = Chains 86 | /\ current_branch[chain] <= sizeBound \* branches <= sizeBound 87 | /\ checkBranches(branches, chain) \* check that all branches are valid 88 | 89 | \* node_headers 90 | NodeHeadersOK == 91 | \A chain \in Chains : 92 | LET headers == node_headers[chain] IN 93 | /\ DOMAIN node_headers = Chains 94 | /\ Len(headers) <= sizeBound * (sizeBound + 1) \* bounded list of headers 95 | /\ Forall(headers, isHeader) \* all headers are valid headers 96 | 97 | \* node_height 98 | NodeHeightsOK == 99 | \A chain \in Chains : 100 | \A b \in Branches : 101 | LET hgt == node_height[chain][b] IN 102 | /\ DOMAIN node_height = Chains 103 | /\ DOMAIN node_height[chain] = Branches 104 | /\ hgt >= -1 105 | /\ hgt <= height[chain][b] \* node heights do not exceed system heights 106 | 107 | \* check all fields of node_info 108 | NodeOK == 109 | /\ NodeActiveOK 110 | /\ NodeBlocksOK 111 | /\ NodeBranchesOK 112 | /\ NodeHeadersOK 113 | /\ NodeHeightsOK 114 | 115 | -------------------------------------------------------------------------------- 116 | 117 | \* Type invariant 118 | TypeOK == 119 | /\ NetworkOK 120 | /\ NodeOK 121 | 122 | ================================================================================ 123 | -------------------------------------------------------------------------------- /shell/distributed_db/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | ToSet(f) == { f[i] : i \in DOMAIN f } 14 | 15 | \* Nonempty subsets of S 16 | NESubsets(S) == SUBSET S \ {{}} 17 | 18 | \* Subsets of size <= n 19 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 20 | 21 | ---------------------------------------------------------------------------- 22 | 23 | (* Common functions/operators *) 24 | 25 | \* minimum 26 | min[m, n \in Int] == IF m > n THEN n ELSE m 27 | 28 | \* maximum 29 | max[m, n \in Int] == IF m > n THEN m ELSE n 30 | 31 | \* integer division 32 | divide[a, b \in Nat] == 33 | LET _divide[n, m \in Nat, p \in Nat] == 34 | IF n < m 35 | THEN IF m <= 2 * n 36 | THEN p + 1 37 | ELSE p 38 | ELSE _divide[n - m, m, p + 1] 39 | IN 40 | _divide[a, b, 0] 41 | 42 | \* maximum element of a nonempty finite set of naturals 43 | max_set(set) == 44 | LET RECURSIVE _max_set(_, _) 45 | _max_set(S, curr) == 46 | CASE S = {} -> curr 47 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 48 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 49 | [] OTHER -> -1 50 | 51 | \* minimum element of a nonempty finite set of naturals 52 | min_set(set) == 53 | LET RECURSIVE _min_set(_, _) 54 | _min_set(S, curr) == 55 | CASE S = {} -> curr 56 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 57 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 58 | [] OTHER -> -1 59 | 60 | ---------------------------------------------------------------------------- 61 | 62 | (* Functions/Sequences *) 63 | 64 | \* Enumerable set of sequences of elements from S with length = n 65 | SeqOfLen(S, n) == 66 | CASE n < 0 -> {} 67 | [] OTHER -> [ 1..n -> S ] 68 | 69 | \* Enumerable set of sequences of elements from S with length <= n 70 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 71 | 72 | \* Enumerable set of nonempty sequences of length <= n 73 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 74 | 75 | \* Enumerable set of pairs of elements from sets S1 and S2 76 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 77 | 78 | \* Nonempty sequences of elements from set S 79 | NESeq(S) == Seq(S) \ {<<>>} 80 | 81 | \* remove (all occurrences of) an element from a sequence 82 | Remove(seq, elem) == 83 | LET RECURSIVE _remove(_, _, _) 84 | _remove(s, e, acc) == 85 | CASE s = <<>> -> acc 86 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 87 | [] OTHER -> _remove(Tail(s), e, acc) 88 | IN _remove(seq, elem, <<>>) 89 | 90 | \* (finite) subsequence predicate 91 | RECURSIVE isSubSeq(_, _) 92 | isSubSeq(s1, s2) == 93 | \/ s1 = <<>> 94 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 95 | [] OTHER -> 96 | LET n == max_set(DOMAIN s2) 97 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 98 | s == [ j \in (i + 1)..n |-> s2[j] ] 99 | IN 100 | isSubSeq(Tail(s1), s) 101 | 102 | \* Selects the first element that satisfies the predicate 103 | \* if no element satisfies the predicate, then return <<>> 104 | Select(seq, test(_)) == 105 | LET RECURSIVE select(_, _) 106 | select(t(_), s) == 107 | CASE s = <<>> -> <<>> 108 | [] t(Head(s)) -> Head(s) 109 | [] OTHER -> select(t, Tail(s)) 110 | IN select(test, seq) 111 | 112 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 113 | Forall(seq, test(_)) == 114 | LET RECURSIVE forall(_, _, _) 115 | forall(s, t(_), acc) == 116 | IF s = <<>> 117 | THEN acc 118 | ELSE /\ acc 119 | /\ forall(Tail(s), t, acc /\ t(Head(s))) 120 | IN forall(seq, test, TRUE) 121 | 122 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 123 | Exists(seq, test(_)) == 124 | LET RECURSIVE exists(_, _, _) 125 | exists(s, t(_), acc) == 126 | IF s = <<>> 127 | THEN acc 128 | ELSE \/ acc 129 | \/ exists(Tail(s), t, acc \/ t(Head(s))) 130 | IN exists(seq, test, FALSE) 131 | 132 | Cons(elem, seq) == <> \o seq 133 | 134 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 135 | 136 | ============================================================================= 137 | -------------------------------------------------------------------------------- /shell/distributed_db_abstract/Model_1/DB_TypeOK.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE DB_TypeOK ------------------------------- 2 | 3 | (******************************) 4 | (* Enumerable type invariants *) 5 | (******************************) 6 | 7 | EXTENDS DB_Defs 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | \* Avoid silliness 12 | (*********************************************************) 13 | (* Network variables *) 14 | (* branch : Chains -> Branches *) 15 | (* blocks : Chains -> Branches -> BoundedSeq(Blocks) *) 16 | (* chains : Chains *) 17 | (* height : Chains -> Branches -> Heights \cup {-1} *) 18 | (*********************************************************) 19 | 20 | \* branch 21 | BranchOK == 22 | \A chain \in Chains : 23 | /\ DOMAIN branch = Chains 24 | /\ branch[chain] \in Branches \cup {-1} 25 | /\ chain \in activeChains => branch[chain] >= 0 26 | 27 | \* blocks 28 | BlocksOK == 29 | \A chain \in Chains : 30 | \A b \in Branches : 31 | LET blks == blocks[chain][b] 32 | IN /\ DOMAIN blocks = Chains 33 | /\ DOMAIN blocks[chain] = Branches 34 | /\ Len(blks) <= sizeBound + 1 \* height of each branch <= sizeBound 35 | /\ Forall(blks, isBlock) \* all blocks are valid 36 | /\ b \in activeBranches[chain] => blks /= <<>> \* active branches have blocks 37 | 38 | \* chains 39 | ChainsOK == chains \in Chains 40 | 41 | \* height 42 | HeightOK == 43 | \A chain \in Chains : 44 | \A b \in Branches : 45 | /\ DOMAIN height = Chains 46 | /\ DOMAIN height[chain] = Branches 47 | /\ height[chain][b] \in Heights \cup {-1} 48 | /\ b \in activeBranches[chain] => height[chain][b] >= 0 49 | 50 | \* check all fields of network_info 51 | NetworkOK == 52 | /\ BranchOK 53 | /\ BlocksOK 54 | /\ ChainsOK 55 | /\ HeightOK 56 | 57 | -------------------------------------------------------------------------------- 58 | 59 | (*********************************************************************) 60 | (* Node variables *) 61 | (* node_active : Nodes -> SUBSET Chains *) 62 | (* node_blocks : Nodes -> Chains -> Branches -> BoundedSeq(Blocks) *) 63 | (* node_branches : Nodes -> Chains -> BoundedSeq(Branches) *) 64 | (* node_headers : Nodes -> Chains -> BoundedSeq(Headers) *) 65 | (* node_height : Nodes -> Chains -> Branches -> Heights \cup {-1} *) 66 | (*********************************************************************) 67 | 68 | \* node_active 69 | NodeActiveOK == node_active \subseteq Chains 70 | 71 | \* node_blocks 72 | NodeBlocksOK == 73 | \A chain \in Chains : 74 | \A b \in Branches : 75 | LET blks == node_blocks[chain][b] IN 76 | /\ DOMAIN node_blocks = Chains 77 | /\ DOMAIN node_blocks[chain] = Branches 78 | /\ Len(blks) <= sizeBound + 1 \* height of each block <= sizeBound 79 | /\ Forall(blks, isBlock) \* all blocks are valid 80 | 81 | \* node_branches 82 | NodeBranchesOK == 83 | \A chain \in Chains : 84 | LET branches == node_branches[chain] IN 85 | /\ DOMAIN node_branches = Chains 86 | /\ current_branch[chain] <= sizeBound \* branches <= sizeBound 87 | /\ checkBranches(branches, chain) \* check that all branches are valid 88 | 89 | \* node_headers 90 | NodeHeadersOK == 91 | \A chain \in Chains : 92 | LET headers == node_headers[chain] IN 93 | /\ DOMAIN node_headers = Chains 94 | /\ Len(headers) <= sizeBound * (sizeBound + 1) \* bounded list of headers 95 | /\ Forall(headers, isHeader) \* all headers are valid headers 96 | 97 | \* node_height 98 | NodeHeightsOK == 99 | \A chain \in Chains : 100 | \A b \in Branches : 101 | LET hgt == node_height[chain][b] IN 102 | /\ DOMAIN node_height = Chains 103 | /\ DOMAIN node_height[chain] = Branches 104 | /\ hgt >= -1 105 | /\ hgt <= height[chain][b] \* node heights do not exceed system heights 106 | 107 | \* check all fields of node_info 108 | NodeOK == 109 | /\ NodeActiveOK 110 | /\ NodeBlocksOK 111 | /\ NodeBranchesOK 112 | /\ NodeHeadersOK 113 | /\ NodeHeightsOK 114 | 115 | -------------------------------------------------------------------------------- 116 | 117 | \* Type invariant 118 | TypeOK == 119 | /\ NetworkOK 120 | /\ NodeOK 121 | 122 | ================================================================================ 123 | -------------------------------------------------------------------------------- /shell/distributed_db/DistributedDB.toolbox/Model_1/Utils.tla: -------------------------------------------------------------------------------- 1 | ------------------------------- MODULE Utils ------------------------------- 2 | 3 | EXTENDS FiniteSets, Integers, Naturals, Sequences, TLC 4 | 5 | ---------------------------------------------------------------------------- 6 | 7 | (* Sets *) 8 | 9 | \* Pick an "arbitrary" element from set S 10 | Pick(S) == CHOOSE x \in S : TRUE 11 | 12 | \* Turn a function/sequence into a set 13 | ToSet(f) == { f[i] : i \in DOMAIN f } 14 | 15 | \* Nonempty subsets of S 16 | NESubsets(S) == SUBSET S \ {{}} 17 | 18 | \* Subsets of size <= n 19 | Subsets_n(S, n) == { s \in SUBSET S : Cardinality(s) <= n } 20 | 21 | ---------------------------------------------------------------------------- 22 | 23 | (* Common functions/operators *) 24 | 25 | \* minimum 26 | min[m, n \in Int] == IF m > n THEN n ELSE m 27 | 28 | \* maximum 29 | max[m, n \in Int] == IF m > n THEN m ELSE n 30 | 31 | \* integer division 32 | divide[a, b \in Nat] == 33 | LET _divide[n, m \in Nat, p \in Nat] == 34 | IF n < m 35 | THEN IF m <= 2 * n 36 | THEN p + 1 37 | ELSE p 38 | ELSE _divide[n - m, m, p + 1] 39 | IN 40 | _divide[a, b, 0] 41 | 42 | \* maximum element of a nonempty finite set of naturals 43 | max_set(set) == 44 | LET RECURSIVE _max_set(_, _) 45 | _max_set(S, curr) == 46 | CASE S = {} -> curr 47 | [] OTHER -> LET x == Pick(S) IN _max_set(S \ {x}, max[x, curr]) 48 | IN CASE set /= {} -> LET x == Pick(set) IN _max_set(set \ {x}, x) 49 | [] OTHER -> -1 50 | 51 | \* minimum element of a nonempty finite set of naturals 52 | min_set(set) == 53 | LET RECURSIVE _min_set(_, _) 54 | _min_set(S, curr) == 55 | CASE S = {} -> curr 56 | [] OTHER -> LET x == Pick(S) IN _min_set(S \ {x}, min[x, curr]) 57 | IN CASE set /= {} -> LET x == Pick(set) IN _min_set(set\ {x}, x) 58 | [] OTHER -> -1 59 | 60 | ---------------------------------------------------------------------------- 61 | 62 | (* Functions/Sequences *) 63 | 64 | \* Enumerable set of sequences of elements from S with length = n 65 | SeqOfLen(S, n) == 66 | CASE n < 0 -> {} 67 | [] OTHER -> [ 1..n -> S ] 68 | 69 | \* Enumerable set of sequences of elements from S with length <= n 70 | Seq_n(S, n) == UNION { SeqOfLen(S, l) : l \in 0..n } 71 | 72 | \* Enumerable set of nonempty sequences of length <= n 73 | NESeq_n(S, n) == { f \in Seq_n(S, n) : f /= <<>> } 74 | 75 | \* Enumerable set of pairs of elements from sets S1 and S2 76 | Pairs(S1, S2) == { <> : x1 \in S1, x2 \in S2 } 77 | 78 | \* Nonempty sequences of elements from set S 79 | NESeq(S) == Seq(S) \ {<<>>} 80 | 81 | \* remove (all occurrences of) an element from a sequence 82 | Remove(seq, elem) == 83 | LET RECURSIVE _remove(_, _, _) 84 | _remove(s, e, acc) == 85 | CASE s = <<>> -> acc 86 | [] e /= Head(s) -> _remove(Tail(s), e, Append(acc, Head(s))) 87 | [] OTHER -> _remove(Tail(s), e, acc) 88 | IN _remove(seq, elem, <<>>) 89 | 90 | \* (finite) subsequence predicate 91 | RECURSIVE isSubSeq(_, _) 92 | isSubSeq(s1, s2) == 93 | \/ s1 = <<>> 94 | \/ CASE { j \in DOMAIN s2 : s2[j] = Head(s1) } = {} -> FALSE 95 | [] OTHER -> 96 | LET n == max_set(DOMAIN s2) 97 | i == min_set({ j \in DOMAIN s2 : s2[j] = Head(s1) }) 98 | s == [ j \in (i + 1)..n |-> s2[j] ] 99 | IN 100 | isSubSeq(Tail(s1), s) 101 | 102 | \* Selects the first element that satisfies the predicate 103 | \* if no element satisfies the predicate, then return <<>> 104 | Select(seq, test(_)) == 105 | LET RECURSIVE select(_, _) 106 | select(t(_), s) == 107 | CASE s = <<>> -> <<>> 108 | [] t(Head(s)) -> Head(s) 109 | [] OTHER -> select(t, Tail(s)) 110 | IN select(test, seq) 111 | 112 | \* returns TRUE if all elements of [seq] satisfy [test], FALSE otherwise 113 | Forall(seq, test(_)) == 114 | LET RECURSIVE forall(_, _, _) 115 | forall(s, t(_), acc) == 116 | IF s = <<>> 117 | THEN acc 118 | ELSE /\ acc 119 | /\ forall(Tail(s), t, acc /\ t(Head(s))) 120 | IN forall(seq, test, TRUE) 121 | 122 | \* returns TRUE if any elements of [seq] satisfy [test], FALSE otherwise 123 | Exists(seq, test(_)) == 124 | LET RECURSIVE exists(_, _, _) 125 | exists(s, t(_), acc) == 126 | IF s = <<>> 127 | THEN acc 128 | ELSE \/ acc 129 | \/ exists(Tail(s), t, acc \/ t(Head(s))) 130 | IN exists(seq, test, FALSE) 131 | 132 | Cons(elem, seq) == <> \o seq 133 | 134 | Filter(seq, pred(_)) == SelectSeq(seq, pred) 135 | 136 | ============================================================================= 137 | -------------------------------------------------------------------------------- /p2p/counter/Model/Counter.tla: -------------------------------------------------------------------------------- 1 | ------------------------------ MODULE Counter ------------------------------ 2 | 3 | EXTENDS Utils 4 | 5 | CONSTANTS 6 | \* average parameter 7 | \* @type: Int; 8 | alpha, 9 | 10 | \* id for counter manager 11 | \* @type: Int; 12 | id, 13 | 14 | \* bound on size of each counter (to keep model finite) 15 | \* @type: Int; 16 | sizeBound, 17 | 18 | \* max number of counters that can be managed 19 | \* @type: Int; 20 | NumCounters, 21 | 22 | \* null value 23 | \* @type: Int; 24 | None 25 | 26 | VARIABLES 27 | \* function from counter id to its state 28 | \* @type: Int => [ avg : Int, current : Int, total : Int ]; 29 | state, 30 | 31 | \* set of registered counters 32 | \* @type: Set(Int); 33 | registered 34 | 35 | vars == <> 36 | 37 | ASSUME alpha \in 1..1000 38 | ASSUME id \in Nat 39 | ASSUME NumCounters \in Nat 40 | ASSUME sizeBound \in Nat /\ sizeBound > alpha 41 | 42 | ---------------------------------------------------------------------------- 43 | 44 | PossibleCounters == 1..NumCounters 45 | 46 | PossibleCounterValues == 0..sizeBound 47 | 48 | Optional == PossibleCounterValues \cup {None} 49 | 50 | \* value of an unregistered counter's state 51 | null == [ avg |-> None, current |-> None, total |-> None ] 52 | 53 | \* value of a newly registered counter's state 54 | fresh == [ avg |-> 0, current |-> 0, total |-> 0 ] 55 | 56 | ---------------------------------------------------------------------------- 57 | 58 | (***********) 59 | (* Actions *) 60 | (***********) 61 | 62 | \* Register a previously unregistered counter with this manager 63 | Include(c) == 64 | /\ state' = [ state EXCEPT ![c] = fresh ] 65 | /\ registered' = registered \cup {c} 66 | 67 | Include_one == 68 | \E c \in PossibleCounters : 69 | /\ c \notin registered 70 | /\ Include(c) 71 | 72 | \* Add x to a registered counter 73 | add(c, x) == 74 | /\ state' = [ state EXCEPT ![c].total = @ + x, ![c].current = @ + x ] 75 | /\ UNCHANGED registered 76 | 77 | \* Add x if doing so will not cause either total or avg to exceed sizeBound 78 | Add == 79 | \E c \in registered, x \in 1..sizeBound : 80 | LET curr == state[c].current 81 | IN /\ state[c].total <= sizeBound - x 82 | /\ state[c].avg <= sizeBound - alpha * (curr + x) 83 | /\ add(c, x) 84 | 85 | \* Reset a registered counter 86 | reset(c) == 87 | /\ state' = [ state EXCEPT ![c] = fresh ] 88 | /\ UNCHANGED registered 89 | 90 | \* Reset a registered counter that has reached its maximum value 91 | Reset == 92 | \E c \in registered : 93 | /\ state[c].total = sizeBound 94 | /\ reset(c) 95 | 96 | \* Destroy a registered counter 97 | destroy(c) == 98 | /\ state' = [ state EXCEPT ![c] = null ] 99 | /\ registered' = registered \ {c} 100 | 101 | Destroy == \E c \in registered : destroy(c) 102 | 103 | \* Enabled by having all registered counters with average < alpha 104 | Work == 105 | /\ registered /= {} 106 | /\ \A c \in registered : state[c].avg < alpha 107 | /\ state' = 108 | [ c \in PossibleCounters |-> 109 | CASE c \in registered -> 110 | LET curr == state[c].current IN 111 | [ state[c] EXCEPT 112 | !.avg = alpha * curr + ((1000 - alpha) * @) \div 1000, 113 | !.current = 0 ] 114 | [] OTHER -> state[c] ] 115 | /\ UNCHANGED registered 116 | 117 | ---------------------------------------------------------------------------- 118 | 119 | (*********************) 120 | (* Initial predicate *) 121 | (*********************) 122 | 123 | Init == 124 | /\ state = [ x \in PossibleCounters |-> null ] 125 | /\ registered = {} 126 | 127 | (****************) 128 | (* Next actions *) 129 | (****************) 130 | 131 | Next == 132 | \/ Include_one 133 | \/ Add 134 | \/ Reset 135 | \/ Destroy 136 | \/ Work 137 | 138 | (*****************) 139 | (* Specification *) 140 | (*****************) 141 | 142 | Spec == Init /\ [][Next]_vars 143 | 144 | ---------------------------------------------------------------------------- 145 | 146 | (**************) 147 | (* Invariants *) 148 | (**************) 149 | 150 | StateOK == 151 | /\ DOMAIN state = PossibleCounters 152 | /\ \A c \in PossibleCounters : 153 | state[c] \in [ avg : Optional, current : Optional, total : Optional ] 154 | 155 | RegisteredOK == registered \subseteq PossibleCounters 156 | 157 | TypeOK == 158 | /\ StateOK 159 | /\ RegisteredOK 160 | 161 | OnlyUnregisteredNullState == 162 | \A c \in PossibleCounters : state[c] = null <=> c \notin registered 163 | 164 | (**************) 165 | (* Properties *) 166 | (**************) 167 | 168 | \* TODO 169 | \* Characterize fairness of scheduling as a liveness property 170 | 171 | ============================================================================= 172 | -------------------------------------------------------------------------------- /p2p/scheduler_rw/Model/MC.out: -------------------------------------------------------------------------------- 1 | TLC2 Version 2.15 of Day Month 20?? (rev: eb3ff99) 2 | Running breadth-first search Model-Checking with fp 41 and seed -7379494827048490468 with 4096 workers on 64 cores with 27305MB heap and 64MB offheap memory [pid: 45720] (Linux 5.3.0-26-generic amd64, Ubuntu 11.0.7 x86_64, MSBDiskFPSet, DiskStateQueue). 3 | Parsing file /home/tla/models/scheduler_rw/Model/MC.tla 4 | Parsing file /home/tla/models/scheduler_rw/Model/RWScheduler.tla 5 | Parsing file /tmp/TLC.tla 6 | Parsing file /home/tla/models/scheduler_rw/Model/Utils.tla 7 | Parsing file /tmp/FiniteSets.tla 8 | Parsing file /tmp/Integers.tla 9 | Parsing file /tmp/Naturals.tla 10 | Parsing file /tmp/Sequences.tla 11 | Semantic processing of module Naturals 12 | Semantic processing of module Sequences 13 | Semantic processing of module FiniteSets 14 | Semantic processing of module Integers 15 | Semantic processing of module TLC 16 | Semantic processing of module Utils 17 | Semantic processing of module RWScheduler 18 | Semantic processing of module MC 19 | Starting... (2021-02-26 01:07:48) 20 | Computing initial states... 21 | Computed 2 initial states... 22 | Computed 4 initial states... 23 | Computed 8 initial states... 24 | Computed 16 initial states... 25 | Computed 32 initial states... 26 | Computed 64 initial states... 27 | Computed 128 initial states... 28 | Computed 256 initial states... 29 | Computed 512 initial states... 30 | Computed 1024 initial states... 31 | Computed 2048 initial states... 32 | Computed 4096 initial states... 33 | Computed 8192 initial states... 34 | Computed 16384 initial states... 35 | Computed 32768 initial states... 36 | Computed 65536 initial states... 37 | Computed 131072 initial states... 38 | Computed 262144 initial states... 39 | Computed 524288 initial states... 40 | Computed 1048576 initial states... 41 | Computed 2097152 initial states... 42 | Computed 4194304 initial states... 43 | Computed 8388608 initial states... 44 | Computed 16777216 initial states... 45 | Computed 33554432 initial states... 46 | Computed 67108864 initial states... 47 | Computed 134217728 initial states... 48 | Computed 268435456 initial states... 49 | Finished computing initial states: 475891200 distinct states generated at 2021-02-26 01:57:06. 50 | Checkpointing of run states/21-02-26-01-07-48 51 | Checkpointing completed at (2021-02-26 01:57:12) 52 | Progress(1) at 2021-02-26 01:57:12: 482,281,246 states generated (482,281,246 s/min), 475,891,200 distinct states found (475,891,200 ds/min), 473,134,693 states left on queue. 53 | Progress(1) at 2021-02-26 01:58:12: 578,315,170 states generated (96,033,924 s/min), 475,891,200 distinct states found (0 ds/min), 432,299,886 states left on queue. 54 | Progress(1) at 2021-02-26 01:59:12: 673,315,204 states generated (95,000,034 s/min), 475,891,200 distinct states found (0 ds/min), 392,488,448 states left on queue. 55 | Progress(1) at 2021-02-26 02:00:12: 769,448,507 states generated (96,133,303 s/min), 475,891,200 distinct states found (0 ds/min), 352,438,941 states left on queue. 56 | Progress(1) at 2021-02-26 02:01:12: 865,536,703 states generated (96,088,196 s/min), 475,891,200 distinct states found (0 ds/min), 312,338,637 states left on queue. 57 | Progress(1) at 2021-02-26 02:02:12: 960,628,549 states generated (95,091,846 s/min), 475,891,200 distinct states found (0 ds/min), 272,856,797 states left on queue. 58 | Progress(1) at 2021-02-26 02:03:12: 1,055,681,907 states generated (95,053,358 s/min), 475,891,200 distinct states found (0 ds/min), 233,774,280 states left on queue. 59 | Progress(1) at 2021-02-26 02:04:12: 1,150,892,998 states generated (95,211,091 s/min), 475,891,200 distinct states found (0 ds/min), 194,904,760 states left on queue. 60 | Progress(1) at 2021-02-26 02:05:12: 1,246,123,390 states generated (95,230,392 s/min), 475,891,200 distinct states found (0 ds/min), 156,349,920 states left on queue. 61 | Progress(1) at 2021-02-26 02:06:12: 1,341,201,614 states generated (95,078,224 s/min), 475,891,200 distinct states found (0 ds/min), 116,635,546 states left on queue. 62 | Progress(1) at 2021-02-26 02:07:12: 1,435,944,237 states generated (94,742,623 s/min), 475,891,200 distinct states found (0 ds/min), 77,560,808 states left on queue. 63 | Progress(1) at 2021-02-26 02:08:12: 1,530,859,853 states generated (94,915,616 s/min), 475,891,200 distinct states found (0 ds/min), 38,664,930 states left on queue. 64 | Progress(1) at 2021-02-26 02:09:12: 1,626,030,720 states generated (95,170,867 s/min), 475,891,200 distinct states found (0 ds/min), 0 states left on queue. 65 | Model checking completed. No error has been found. 66 | Estimates of the probability that TLC did not check all reachable states 67 | because two distinct states had the same fingerprint: 68 | calculated (optimistic): val = .030 69 | based on the actual fingerprints: val = .001 70 | 1626030720 states generated, 475891200 distinct states found, 0 states left on queue. 71 | The depth of the complete state graph search is 1. 72 | The average outdegree of the complete state graph is 0 (minimum is 0, the maximum 0 and the 95th percentile is 0). 73 | Finished in 01h 01min at (2021-02-26 02:09:30) 74 | --------------------------------------------------------------------------------