diff --git a/spec/README.md b/spec/README.md index 7ec9387c2..a0a67f7b5 100644 --- a/spec/README.md +++ b/spec/README.md @@ -1,4 +1,12 @@ -# Overview +--- +order: 1 +title: Overview +parent: + title: Tendermint Spec + order: 7 +--- + +# Tendermint Spec This is a markdown specification of the Tendermint blockchain. It defines the base data structures, how they are validated, @@ -27,18 +35,18 @@ please submit them to our [bug bounty](https://tendermint.com/security)! ### P2P and Network Protocols -- [The Base P2P Layer](./p2p/): multiplex the protocols ("reactors") on authenticated and encrypted TCP connections -- [Peer Exchange (PEX)](./reactors/pex/): gossip known peer addresses so peers can find each other -- [Block Sync](./reactors/block_sync/): gossip blocks so peers can catch up quickly -- [Consensus](./reactors/consensus/): gossip votes and block parts so new blocks can be committed -- [Mempool](./reactors/mempool/): gossip transactions so they get included in blocks -- [Evidence](./reactors/evidence/): sending invalid evidence will stop the peer +- [The Base P2P Layer](./p2p/node.md): multiplex the protocols ("reactors") on authenticated and encrypted TCP connections +- [Peer Exchange (PEX)](./reactors/pex/reactor.md): gossip known peer addresses so peers can find each other +- [Block Sync](./reactors/block_sync/reactor.md): gossip blocks so peers can catch up quickly +- [Consensus](./reactors/consensus/consensus.md): gossip votes and block parts so new blocks can be committed +- [Mempool](./reactors/mempool/reactor.md): gossip transactions so they get included in blocks +- [Evidence](./reactors/evidence/reactor.md): sending invalid evidence will stop the peer ### Software -- [ABCI](./software/abci.md): Details about interactions between the +- [ABCI](./abci/README.md): Details about interactions between the application and consensus engine over ABCI -- [Write-Ahead Log](./software/wal.md): Details about how the consensus +- [Write-Ahead Log](./consensus/wal.md): Details about how the consensus engine preserves data and recovers from crash failures ## Overview diff --git a/spec/abci/README.md b/spec/abci/README.md index 56d5e8aaf..a8293e4bb 100644 --- a/spec/abci/README.md +++ b/spec/abci/README.md @@ -1,4 +1,8 @@ -# Overview +--- +cards: true +--- + +# ABCI ABCI is the interface between Tendermint (a state-machine replication engine) and your application (the actual state machine). It consists of a set of diff --git a/spec/abci/abci.md b/spec/abci/abci.md index 275c4dcd8..e48b711b3 100644 --- a/spec/abci/abci.md +++ b/spec/abci/abci.md @@ -54,7 +54,7 @@ Each event has a `type` which is meant to categorize the event for a particular `Response*` or tx. A `Response*` or tx may contain multiple events with duplicate `type` values, where each distinct entry is meant to categorize attributes for a particular event. Every key and value in an event's attributes must be UTF-8 -encoded strings along with the even type itself. +encoded strings along with the event type itself. Example: @@ -393,9 +393,6 @@ Commit are included in the header of the next block. For heights > 1, it's the weighted median of the timestamps of the valid votes in the block.LastCommit. For height == 1, it's genesis time. - - `NumTxs (int32)`: Number of transactions in the block - - `TotalTxs (int64)`: Total number of transactions in the blockchain until - now - `LastBlockID (BlockID)`: Hash of the previous (parent) block - `LastCommitHash ([]byte)`: Hash of the previous block's commit - `ValidatorsHash ([]byte)`: Hash of the validator set for this block diff --git a/spec/blockchain/blockchain.md b/spec/blockchain/blockchain.md index f4ddcd75f..39802bcd5 100644 --- a/spec/blockchain/blockchain.md +++ b/spec/blockchain/blockchain.md @@ -29,7 +29,7 @@ type Block struct { } ``` -Note the `LastCommit` is the set of votes that committed the last block. +Note the `LastCommit` is the set of signatures of validators that committed the last block. ## Header @@ -43,8 +43,6 @@ type Header struct { ChainID string Height int64 Time Time - NumTxs int64 - TotalTxs int64 // prev block info LastBlockID BlockID @@ -123,18 +121,47 @@ type Data struct { ## Commit -Commit is a simple wrapper for a list of votes, with one vote for each -validator. It also contains the relevant BlockID: +Commit is a simple wrapper for a list of signatures, with one for each +validator. It also contains the relevant BlockID, height and round: -``` +```go type Commit struct { - BlockID BlockID - Precommits []Vote + Height int64 + Round int + BlockID BlockID + Signatures []CommitSig +} +``` + +## CommitSig + +`CommitSig` represents a signature of a validator, who has voted either for nil, +a particular `BlockID` or was absent. It's a part of the `Commit` and can be used +to reconstruct the vote set given the validator set. + +```go +type BlockIDFlag byte + +const ( + // BlockIDFlagAbsent - no vote was received from a validator. + BlockIDFlagAbsent BlockIDFlag = 0x01 + // BlockIDFlagCommit - voted for the Commit.BlockID. + BlockIDFlagCommit = 0x02 + // BlockIDFlagNil - voted for nil. + BlockIDFlagNil = 0x03 +) + +type CommitSig struct { + BlockIDFlag BlockIDFlag + ValidatorAddress Address + Timestamp time.Time + Signature []byte } ``` -NOTE: this will likely change to reduce the commit size by eliminating redundant -information - see [issue #1648](https://github.com/tendermint/tendermint/issues/1648). +NOTE: `ValidatorAddress` and `Timestamp` fields may be removed in the future +(see +[ADR-25](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-025-commit.md)). ## Vote @@ -168,7 +195,7 @@ See the [signature spec](./encoding.md#key-types) for more. EvidenceData is a simple wrapper for a list of evidence: -```go +``` type EvidenceData struct { Evidence []Evidence } @@ -189,6 +216,8 @@ type DuplicateVoteEvidence struct { } ``` +Votes are lexicographically sorted on `BlockID`. + See the [pubkey spec](./encoding.md#key-types) for more. ## Validation @@ -248,7 +277,7 @@ block.Header.Timestamp == MedianTime(block.LastCommit, state.LastValidators) ``` The block timestamp must be monotonic. -It must equal the weighted median of the timestamps of the valid votes in the block.LastCommit. +It must equal the weighted median of the timestamps of the valid signatures in the block.LastCommit. Note: the timestamp of a vote must be greater by at least one millisecond than that of the block being voted on. @@ -264,24 +293,6 @@ if block.Header.Height == 1 { See the section on [BFT time](../consensus/bft-time.md) for more details. -### NumTxs - -```go -block.Header.NumTxs == len(block.Txs.Txs) -``` - -Number of transactions included in the block. - -### TotalTxs - -```go -block.Header.TotalTxs == prevBlock.Header.TotalTxs + block.Header.NumTxs -``` - -The cumulative sum of all transactions included in this blockchain. - -The first block has `block.Header.TotalTxs = block.Header.NumberTxs`. - ### LastBlockID LastBlockID is the previous block's BlockID: @@ -302,11 +313,12 @@ The first block has `block.Header.LastBlockID == BlockID{}`. ### LastCommitHash ```go -block.Header.LastCommitHash == MerkleRoot(block.LastCommit.Precommits) +block.Header.LastCommitHash == MerkleRoot(block.LastCommit.Signatures) ``` -MerkleRoot of the votes included in the block. -These are the votes that committed the previous block. +MerkleRoot of the signatures included in the block. +These are the commit signatures of the validators that committed the previous +block. The first block has `block.Header.LastCommitHash == []byte{}` @@ -394,11 +406,11 @@ Arbitrary length array of arbitrary length byte-arrays. ## LastCommit -The first height is an exception - it requires the LastCommit to be empty: +The first height is an exception - it requires the `LastCommit` to be empty: ```go if block.Header.Height == 1 { - len(b.LastCommit) == 0 + len(b.LastCommit) == 0 } ``` @@ -406,33 +418,32 @@ Otherwise, we require: ```go len(block.LastCommit) == len(state.LastValidators) + talliedVotingPower := 0 -for i, vote := range block.LastCommit{ - if vote == nil{ - continue - } - vote.Type == 2 - vote.Height == block.LastCommit.Height() - vote.Round == block.LastCommit.Round() - vote.BlockID == block.LastBlockID +for i, commitSig := range block.LastCommit.Signatures { + if commitSig.Absent() { + continue + } + + vote.BlockID == block.LastBlockID - val := state.LastValidators[i] - vote.Verify(block.ChainID, val.PubKey) == true + val := state.LastValidators[i] + vote.Verify(block.ChainID, val.PubKey) == true - talliedVotingPower += val.VotingPower + talliedVotingPower += val.VotingPower } -talliedVotingPower > (2/3) * TotalVotingPower(state.LastValidators) +talliedVotingPower > (2/3)*TotalVotingPower(state.LastValidators) ``` -Includes one (possibly nil) vote for every current validator. -Non-nil votes must be Precommits. -All votes must be for the same height and round. -All votes must be for the previous block. +Includes one vote for every current validator. +All votes must either be for the previous block, nil or absent. All votes must have a valid signature from the corresponding validator. The sum total of the voting power of the validators that voted must be greater than 2/3 of the total voting power of the complete validator set. +The number of votes in a commit is limited to 10000 (see `types.MaxVotesCount`). + ### Vote A vote is a signed message broadcast in the consensus for a particular block at a particular height and round. diff --git a/spec/blockchain/encoding.md b/spec/blockchain/encoding.md index 170e91605..31b9c0625 100644 --- a/spec/blockchain/encoding.md +++ b/spec/blockchain/encoding.md @@ -62,8 +62,10 @@ You can simply use below table and concatenate Prefix || Length (of raw bytes) | | Type | Name | Prefix | Length | Notes | | ----------------------- | ---------------------------------- | ---------- | -------- | ----- | | PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE64 | 0x20 | | +| PubKeySr25519 | tendermint/PubKeySr25519 | 0x0DFB1005 | 0x20 | | | PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE987 | 0x21 | | | PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288910 | 0x40 | | +| PrivKeySr25519 | tendermint/PrivKeySr25519 | 0x2F82D78B | 0x20 | | | PrivKeySecp256k1 | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | 0x20 | | | PubKeyMultisigThreshold | tendermint/PubKeyMultisigThreshold | 0x22C1F7E2 | variable | | @@ -90,6 +92,18 @@ address = SHA256(pubkey)[:20] The signature is the raw 64-byte ED25519 signature. +#### Sr25519 + +TODO: pubkey + +The address is the first 20-bytes of the SHA256 hash of the raw 32-byte public key: + +``` +address = SHA256(pubkey)[:20] +``` + +The signature is the raw 64-byte ED25519 signature. + #### Secp256k1 TODO: pubkey @@ -155,7 +169,9 @@ See details of SimpleProof, below. ### MakeParts Encode an object using Amino and slice it into parts. -Tendermint uses a part size of 65536 bytes. +Tendermint uses a part size of 65536 bytes, and allows a maximum of 1601 parts +(see `types.MaxBlockPartsCount`). This corresponds to the hard-coded block size +limit of 100MB. ```go func MakeParts(block Block) []Part @@ -288,9 +304,13 @@ func computeHashFromAunts(index, total int, leafHash []byte, innerHashes [][]byt } ``` +The number of aunts is limited to 100 (`MaxAunts`) to protect the node against DOS attacks. +This limits the tree size to 2^100 leaves, which should be sufficient for any +conceivable purpose. + ### IAVL+ Tree -Because Tendermint only uses a Simple Merkle Tree, application developers are expect to use their own Merkle tree in their applications. For example, the IAVL+ Tree - an immutable self-balancing binary tree for persisting application state is used by the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/blob/master/docs/clients/lite/specification.md) +Because Tendermint only uses a Simple Merkle Tree, application developers are expect to use their own Merkle tree in their applications. For example, the IAVL+ Tree - an immutable self-balancing binary tree for persisting application state is used by the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/blob/ae77f0080a724b159233bd9b289b2e91c0de21b5/docs/interfaces/lite/specification.md) ## JSON diff --git a/spec/blockchain/readme.md b/spec/blockchain/readme.md new file mode 100644 index 000000000..bd9b7e4f4 --- /dev/null +++ b/spec/blockchain/readme.md @@ -0,0 +1,5 @@ +--- +cards: true +--- + +# Blockchain diff --git a/spec/blockchain/state.md b/spec/blockchain/state.md index 15fc37761..0430819fa 100644 --- a/spec/blockchain/state.md +++ b/spec/blockchain/state.md @@ -27,6 +27,9 @@ type State struct { } ``` +Note there is a hard-coded limit of 10000 validators. This is inherited from the +limit on the number of votes in a commit. + ### Result ```go diff --git a/spec/consensus/consensus-paper/definitions.tex b/spec/consensus/consensus-paper/definitions.tex index f73d316e8..454dd445d 100644 --- a/spec/consensus/consensus-paper/definitions.tex +++ b/spec/consensus/consensus-paper/definitions.tex @@ -4,7 +4,7 @@ We consider a system of processes that communicate by exchanging messages. Processes can be correct or faulty, where a faulty process can behave in an -arbitrary way, i.e., Byzantine faults. We assume that each process +arbitrary way, i.e., we consider Byzantine faults. We assume that each process has some amount of voting power (voting power of a process can be $0$). Processes in our model are not part of a single administrative domain; therefore we cannot enforce a direct network connectivity between all @@ -13,19 +13,30 @@ processes called peers, such that there is an indirect communication channel between all correct processes. Communication between processes is established using a gossip protocol \cite{Dem1987:gossip}. -Formally, we model the network communication using the \emph{partially +Formally, we model the network communication using a variant of the \emph{partially synchronous system model}~\cite{DLS88:jacm}: in all executions of the system there is a bound $\Delta$ and an instant GST (Global Stabilization Time) such that all communication among correct processes after GST is reliable and $\Delta$-timely, i.e., if a correct process $p$ sends message $m$ at time $t -\ge GST$ to correct process $q$, then $q$ will receive $m$ before $t + +\ge GST$ to a correct process $q$, then $q$ will receive $m$ before $t + \Delta$\footnote{Note that as we do not assume direct communication channels among all correct processes, this implies that before the message $m$ reaches $q$, it might pass through a number of correct processes that will -forward the message $m$ using gossip protocol towards $q$.}. Messages among -correct processes can be delayed, dropped or duplicated before GST. -Spoofing/impersonation attacks are assumed to be impossible at all times due to -the use of public-key cryptography. The bound $\Delta$ and GST are system +forward the message $m$ using gossip protocol towards $q$.}. +In addition to the standard \emph{partially + synchronous system model}~\cite{DLS88:jacm}, we assume an auxiliary property +that captures gossip-based nature of communication\footnote{The details of the Tendermint gossip protocol will be discussed in a separate + technical report. }: + + +\begin{itemize} \item \emph{Gossip communication:} If a correct process $p$ + sends some message $m$ at time $t$, all correct processes will receive + $m$ before $max\{t, GST\} + \Delta$. Furthermore, if a correct process $p$ + receives some message $m$ at time $t$, all correct processes will receive + $m$ before $max\{t, GST\} + \Delta$. \end{itemize} + + +The bound $\Delta$ and GST are system parameters whose values are not required to be known for the safety of our algorithm. Termination of the algorithm is guaranteed within a bounded duration after GST. In practice, the algorithm will work correctly in the slightly @@ -37,18 +48,16 @@ lost), but consideration of the GST model simplifies the discussion. We assume that process steps (which might include sending and receiving messages) take zero time. Processes are equipped with clocks so they can -measure local timeouts. All protocol messages are signed, i.e., when a correct +measure local timeouts. +Spoofing/impersonation attacks are assumed to be impossible at all times due to +the use of public-key cryptography, i.e., we assume that all protocol messages contains a digital signature. +Therefore, when a correct process $q$ receives a signed message $m$ from its peer, the process $q$ can -verify who was the original sender of the message $m$. +verify who was the original sender of the message $m$ and if the message signature is valid. +We do not explicitly state a signature verification step in the pseudo-code of the algorithm to improve readability; +we assume that only messages with the valid signature are considered at that level (and messages with invalid signatures +are dropped). -The details of the Tendermint gossip protocol will be discussed in a separate -technical report. For the sake of this paper it is sufficient to assume that -messages are being gossiped between processes and the following property holds -(in addition to the partial synchrony network assumptions): - -\begin{itemize} \item \emph{Gossip communication:} If a correct process $p$ - receives some message $m$ at time $t$, all correct processes will receive - $m$ before $max\{t, GST\} + \Delta$. \end{itemize} %Messages that are being gossiped are created by the consensus layer. We can diff --git a/spec/consensus/fork-accountability.md b/spec/consensus/fork-accountability.md index a6af8a1ba..2eb662aef 100644 --- a/spec/consensus/fork-accountability.md +++ b/spec/consensus/fork-accountability.md @@ -187,7 +187,7 @@ Validators: Execution: * for the main chain F behaves nicely * F coordinates to sign a block B that is different from the one on the main chain. -* the lite clients obtains B and trusts at as it is signed by more and 2/3 of the voting power. +* the lite clients obtains B and trusts at as it is signed by more than 2/3 of the voting power. Consequences: @@ -251,11 +251,11 @@ Consequences: Only in case they signed something which conflicts with the application this can be used against them. Otherwise they do not do anything incorrect. * This case is not covered by the report https://docs.google.com/document/d/11ZhMsCj3y7zIZz4udO9l25xqb0kl7gmWqNpGVRzOeyY/edit?usp=sharing as it only assumes at most 2/3 of faulty validators. -**Q:** do we need to define a special kind of attack for the case where a validator sign arbitrarily state? It seems that detecting such attack requires different mechanism that would require as an evidence a sequence of blocks that lead to that state. This might be very tricky to implement. +**Q:** do we need to define a special kind of attack for the case where a validator sign arbitrarily state? It seems that detecting such attack requires a different mechanism that would require as an evidence a sequence of blocks that led to that state. This might be very tricky to implement. ### Back to the past -In this kind of attacks faulty validators take advantage of the fact that they did not sign messages in some of the past rounds. Due to the asynchronous network in which Tendermint operates, we cannot easily differentiate between such an attack and delayed message. This kind of attack can be used at both full nodes and lite clients. +In this kind of attack, faulty validators take advantage of the fact that they did not sign messages in some of the past rounds. Due to the asynchronous network in which Tendermint operates, we cannot easily differentiate between such an attack and delayed message. This kind of attack can be used at both full nodes and lite clients. #### Scenario 5: @@ -271,7 +271,7 @@ Validators: Execution: * in a round *r* of height *h* we have C1 precommitting a value A, -* C2 precommits nil, +* C2 precommits nil, * F does not send any message * *q* precommits nil. * In some round *r' > r*, F and *q* and C2 commit some other value B different from A. @@ -283,7 +283,7 @@ Consequences: * Only a single faulty validator that previously precommited nil did equivocation, while the other 1/3 of faulty validators actually executed an attack that has exactly the same sequence of messages as part of amnesia attack. Detecting this kind of attack boil down to mechanisms for equivocation and amnesia. -**Q:** should we keep this as a separate kind of attack? It seems that equivocation, amnesia and phantom validators are the only kind of attack we need to support and this gives us security also in other cases. This would not be surprising as equivocation and amnesia are attacks that followed from the protocol and phantom attack is not really an attack to Tendermint but more to the Proof of stake module. +**Q:** should we keep this as a separate kind of attack? It seems that equivocation, amnesia and phantom validators are the only kind of attack we need to support and this gives us security also in other cases. This would not be surprising as equivocation and amnesia are attacks that followed from the protocol and phantom attack is not really an attack to Tendermint but more to the Proof of Stake module. ### Phantom validators @@ -296,19 +296,19 @@ Validators: Execution: -* There is a fork, and there exists two different headers for height *h + k*, with different validator sets: +* There is a fork, and there exist two different headers for height *h + k*, with different validator sets: - VS2 on the main chain - forged header VS2', signed by F (and others) * a lite client has a trust in a header for height *h* (and the corresponding validator set VS1). -* As part of bisection header verification, it verifies header at height *h + k* with new validator set VS2'. +* As part of bisection header verification, it verifies the header at height *h + k* with new validator set VS2'. Consequences: * To detect this, a node needs to see both, the forged header and the canonical header from the chain. * If this is the case, detecting these kind of attacks is easy as it just requires verifying if processes are signing messages in heights in which they are not part of the validator set. -**Remark.** We can have phantom-validator-based attacks as a follow up of equivocation or amnesia based attack where forked state contains validators that are not part of the validator set at the main chain. In this case, they keep signing messages contributed to a forked chain (the wrong branch) although they are not part of the validator set on the main chain. This attack can also be used to attack full node during a period of time he is eclipsed. +**Remark.** We can have phantom-validator-based attacks as a follow up of equivocation or amnesia based attack where forked state contains validators that are not part of the validator set at the main chain. In this case, they keep signing messages contributed to a forked chain (the wrong branch) although they are not part of the validator set on the main chain. This attack can also be used to attack full node during a period of time it is eclipsed. ### Lunatic validator @@ -316,4 +316,4 @@ Lunatic validator agrees to sign commit messages for arbitrary application state Note that detecting this behavior require application knowledge. Detecting this behavior can probably be done by referring to the block before the one in which height happen. -**Q:** can we say that in this case a validator ignore to check if proposed value is valid before voting for it? +**Q:** can we say that in this case a validator declines to check if a proposed value is valid before voting for it? diff --git a/spec/consensus/readme.md b/spec/consensus/readme.md new file mode 100644 index 000000000..0ffc4b0bf --- /dev/null +++ b/spec/consensus/readme.md @@ -0,0 +1,5 @@ +--- +cards: true +--- + +# Consensus diff --git a/spec/consensus/wal.md b/spec/consensus/wal.md index 92bbfc4b2..95d1bad12 100644 --- a/spec/consensus/wal.md +++ b/spec/consensus/wal.md @@ -28,5 +28,5 @@ WAL. Then it will go to precommit, and that time it will work because the private validator contains the `LastSignBytes` and then we’ll replay the precommit from the WAL. -Make sure to read about [WAL corruption](https://github.com/tendermint/tendermint/blob/master/docs/tendermint-core/running-in-production.md#wal-corruptionn) +Make sure to read about [WAL corruption](https://github.com/tendermint/tendermint/blob/master/docs/tendermint-core/running-in-production.md#wal-corruption) and recovery strategies. diff --git a/spec/p2p/config.md b/spec/p2p/config.md index 7ff2b5e8d..bddda4a4b 100644 --- a/spec/p2p/config.md +++ b/spec/p2p/config.md @@ -26,6 +26,10 @@ These are intended to be trusted persistent peers that can help anchor us in the p2p network. The auto-redial uses exponential backoff and will give up after a day of trying to connect. +But If `persistent_peers_max_dial_period` is set greater than zero, +pause between each dial to each persistent peer will not exceed `persistent_peers_max_dial_period` +during exponential backoff and we keep trying again without giving up + **Note:** If `seeds` and `persistent_peers` intersect, the user will be warned that seeds may auto-close connections and that the node may not be able to keep the connection persistent. @@ -36,3 +40,11 @@ and that the node may not be able to keep the connection persistent. These are IDs of the peers that we do not add to the address book or gossip to other peers. They stay private to us. + + +## Unconditional Peers + +`--p2p.unconditional_peer_ids “id100000000000000000000000000000000,id200000000000000000000000000000000”` + +These are IDs of the peers which are allowed to be connected by both inbound or outbound regardless of +`max_num_inbound_peers` or `max_num_outbound_peers` of user's node reached or not. diff --git a/spec/p2p/readme.md b/spec/p2p/readme.md new file mode 100644 index 000000000..4d85d382c --- /dev/null +++ b/spec/p2p/readme.md @@ -0,0 +1,5 @@ +--- +cards: true +--- + +# P2P diff --git a/spec/reactors/consensus/consensus-reactor.md b/spec/reactors/consensus/consensus-reactor.md index 47c6949a7..7ac9d20b0 100644 --- a/spec/reactors/consensus/consensus-reactor.md +++ b/spec/reactors/consensus/consensus-reactor.md @@ -40,7 +40,7 @@ RoundState defines the internal consensus state. It contains height, round, roun a proposal and proposal block for the current round, locked round and block (if some block is being locked), set of received votes and last commit and last validators set. -```golang +```go type RoundState struct { Height int64 Round int @@ -96,11 +96,13 @@ type PeerRoundState struct { ## Receive method of Consensus reactor -The entry point of the Consensus reactor is a receive method. When a message is received from a peer p, -normally the peer round state is updated correspondingly, and some messages -are passed for further processing, for example to ConsensusState service. We now specify the processing of messages -in the receive method of Consensus reactor for each message type. In the following message handler, `rs` and `prs` denote -`RoundState` and `PeerRoundState`, respectively. +The entry point of the Consensus reactor is a receive method. When a message is +received from a peer p, normally the peer round state is updated +correspondingly, and some messages are passed for further processing, for +example to ConsensusState service. We now specify the processing of messages in +the receive method of Consensus reactor for each message type. In the following +message handler, `rs` and `prs` denote `RoundState` and `PeerRoundState`, +respectively. ### NewRoundStepMessage handler @@ -134,13 +136,16 @@ handleMessage(msg): ``` handleMessage(msg): if prs.Height != msg.Height then return - + if prs.Round != msg.Round && !msg.IsCommit then return - + prs.ProposalBlockPartsHeader = msg.BlockPartsHeader prs.ProposalBlockParts = msg.BlockParts ``` +The number of block parts is limited to 1601 (`types.MaxBlockPartsCount`) to +protect the node against DOS attacks. + ### HasVoteMessage handler ``` @@ -179,6 +184,9 @@ handleMessage(msg): prs.ProposalPOL = msg.ProposalPOL ``` +The number of votes is limited to 10000 (`types.MaxVotesCount`) to protect the +node against DOS attacks. + ### BlockPartMessage handler ``` @@ -203,6 +211,9 @@ handleMessage(msg): Update prs for the bit-array of votes peer claims to have for the msg.BlockID ``` +The number of votes is limited to 10000 (`types.MaxVotesCount`) to protect the +node against DOS attacks. + ## Gossip Data Routine It is used to send the following messages to the peer: `BlockPartMessage`, `ProposalMessage` and @@ -329,7 +340,7 @@ BlockID has seen +2/3 votes. This routine is based on the local RoundState (`rs` 1d) if prs.CatchupCommitRound != -1 and 0 < prs.Height and prs.Height <= blockStore.Height() then Commit = LoadCommit(prs.Height) - m = VoteSetMaj23Message(prs.Height,Commit.Round,Precommit,Commit.blockId) + m = VoteSetMaj23Message(prs.Height,Commit.Round,Precommit,Commit.BlockID) Send m to peer Sleep PeerQueryMaj23SleepDuration @@ -338,7 +349,7 @@ BlockID has seen +2/3 votes. This routine is based on the local RoundState (`rs` ## Broadcast routine -The Broadcast routine subscribes to an internal event bus to receive new round steps and votes messages, and broadcasts messages to peers upon receiving those +The Broadcast routine subscribes to an internal event bus to receive new round steps and votes messages, and broadcasts messages to peers upon receiving those events. It broadcasts `NewRoundStepMessage` or `CommitStepMessage` upon new round state event. Note that broadcasting these messages does not depend on the PeerRoundState; it is sent on the StateChannel. diff --git a/spec/reactors/mempool/config.md b/spec/reactors/mempool/config.md index 4fb756fa4..77deded42 100644 --- a/spec/reactors/mempool/config.md +++ b/spec/reactors/mempool/config.md @@ -51,4 +51,4 @@ If the directory passed in is an absolute path, the wal file is created there. If the directory is a relative path, the path is appended to home directory of the tendermint process to generate an absolute path to the wal directory -(default `$HOME/.tendermint` or set via `TM_HOME` or `--home``) +(default `$HOME/.tendermint` or set via `TM_HOME` or `--home`) diff --git a/spec/reactors/pex/pex.md b/spec/reactors/pex/pex.md index 268b4a318..68a50c51b 100644 --- a/spec/reactors/pex/pex.md +++ b/spec/reactors/pex/pex.md @@ -31,7 +31,12 @@ On startup, we will also immediately dial the given list of `persistent_peers`, and will attempt to maintain persistent connections with them. If the connections die, or we fail to dial, we will redial every 5s for a few minutes, then switch to an exponential backoff schedule, and after about a day of -trying, stop dialing the peer. +trying, stop dialing the peer. This behavior is when `persistent_peers_max_dial_period` is configured to zero. + +But If `persistent_peers_max_dial_period` is set greater than zero, terms between each dial to each persistent peer +will not exceed `persistent_peers_max_dial_period` during exponential backoff. +Therefore, `dial_period` = min(`persistent_peers_max_dial_period`, `exponential_backoff_dial_period`) +and we keep trying again regardless of `maxAttemptsToDial` As long as we have less than `MaxNumOutboundPeers`, we periodically request additional peers from each of our own and try seeds. @@ -93,7 +98,8 @@ the selection process happens every `ensurePeersPeriod`, we might not end up dialing a peer for much longer than the backoff duration. If we fail to connect to the peer after 16 tries (with exponential backoff), we -remove from address book completely. +remove from address book completely. But for persistent peers, we indefinitely try to +dial all persistent peers unless `persistent_peers_max_dial_period` is configured to zero ## Select Peers to Exchange diff --git a/spec/reactors/readme.md b/spec/reactors/readme.md new file mode 100644 index 000000000..82a19485b --- /dev/null +++ b/spec/reactors/readme.md @@ -0,0 +1,5 @@ +--- +cards: true +--- + +# Reactors