mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-14 13:51:21 +00:00
Cleanup build and structure
This commit is contained in:
committed by
Ethan Buchman
parent
2ec425ae4b
commit
6366eb9d99
1
docs/.python-version
Normal file
1
docs/.python-version
Normal file
@ -0,0 +1 @@
|
||||
2.7.14
|
@ -12,6 +12,9 @@ BUILDDIR = _build
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
install:
|
||||
@pip install -r requirements.txt
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
Here we describe the data structures in the Tendermint blockchain and the rules for validating them.
|
||||
|
||||
# Data Structures
|
||||
## Data Structures
|
||||
|
||||
The Tendermint blockchains consists of a short list of basic data types:
|
||||
`Block`, `Header`, `Vote`, `BlockID`, `Signature`, and `Evidence`.
|
||||
@ -12,7 +12,7 @@ The Tendermint blockchains consists of a short list of basic data types:
|
||||
A block consists of a header, a list of transactions, a list of votes (the commit),
|
||||
and a list of evidence if malfeasance (ie. signing conflicting votes).
|
||||
|
||||
```
|
||||
```go
|
||||
type Block struct {
|
||||
Header Header
|
||||
Txs [][]byte
|
||||
@ -26,7 +26,7 @@ type Block struct {
|
||||
A block header contains metadata about the block and about the consensus, as well as commitments to
|
||||
the data in the current block, the previous block, and the results returned by the application:
|
||||
|
||||
```
|
||||
```go
|
||||
type Header struct {
|
||||
// block metadata
|
||||
Version string // Version string
|
||||
@ -66,7 +66,7 @@ the block during consensus, is the Merkle root of the complete serialized block
|
||||
cut into parts. The `BlockID` includes these two hashes, as well as the number of
|
||||
parts.
|
||||
|
||||
```
|
||||
```go
|
||||
type BlockID struct {
|
||||
Hash []byte
|
||||
Parts PartsHeader
|
||||
@ -83,7 +83,7 @@ type PartsHeader struct {
|
||||
A vote is a signed message from a validator for a particular block.
|
||||
The vote includes information about the validator signing it.
|
||||
|
||||
```
|
||||
```go
|
||||
type Vote struct {
|
||||
Timestamp int64
|
||||
Address []byte
|
||||
@ -96,7 +96,6 @@ type Vote struct {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
There are two types of votes:
|
||||
a prevote has `vote.Type == 1` and
|
||||
a precommit has `vote.Type == 2`.
|
||||
@ -111,7 +110,7 @@ Currently, Tendermint supports Ed25519 and Secp256k1.
|
||||
|
||||
An ED25519 signature has `Type == 0x1`. It looks like:
|
||||
|
||||
```
|
||||
```go
|
||||
// Implements Signature
|
||||
type Ed25519Signature struct {
|
||||
Type int8 = 0x1
|
||||
@ -125,7 +124,7 @@ where `Signature` is the 64 byte signature.
|
||||
|
||||
A `Secp256k1` signature has `Type == 0x2`. It looks like:
|
||||
|
||||
```
|
||||
```go
|
||||
// Implements Signature
|
||||
type Secp256k1Signature struct {
|
||||
Type int8 = 0x2
|
||||
@ -135,7 +134,7 @@ type Secp256k1Signature struct {
|
||||
|
||||
where `Signature` is the DER encoded signature, ie:
|
||||
|
||||
```
|
||||
```hex
|
||||
0x30 <length of whole message> <0x02> <length of R> <R> 0x2 <length of S> <S>.
|
||||
```
|
||||
|
||||
@ -143,7 +142,7 @@ where `Signature` is the DER encoded signature, ie:
|
||||
|
||||
TODO
|
||||
|
||||
# Validation
|
||||
## Validation
|
||||
|
||||
Here we describe the validation rules for every element in a block.
|
||||
Blocks which do not satisfy these rules are considered invalid.
|
||||
@ -159,7 +158,7 @@ and other results from the application.
|
||||
Elements of an object are accessed as expected,
|
||||
ie. `block.Header`. See [here](state.md) for the definition of `state`.
|
||||
|
||||
## Header
|
||||
### Header
|
||||
|
||||
A Header is valid if its corresponding fields are valid.
|
||||
|
||||
@ -173,7 +172,7 @@ Arbitrary constant string.
|
||||
|
||||
### Height
|
||||
|
||||
```
|
||||
```go
|
||||
block.Header.Height > 0
|
||||
block.Header.Height == prevBlock.Header.Height + 1
|
||||
```
|
||||
@ -190,7 +189,7 @@ block being voted on.
|
||||
|
||||
### NumTxs
|
||||
|
||||
```
|
||||
```go
|
||||
block.Header.NumTxs == len(block.Txs)
|
||||
```
|
||||
|
||||
@ -198,7 +197,7 @@ Number of transactions included in the block.
|
||||
|
||||
### TxHash
|
||||
|
||||
```
|
||||
```go
|
||||
block.Header.TxHash == SimpleMerkleRoot(block.Txs)
|
||||
```
|
||||
|
||||
@ -206,7 +205,7 @@ Simple Merkle root of the transactions in the block.
|
||||
|
||||
### LastCommitHash
|
||||
|
||||
```
|
||||
```go
|
||||
block.Header.LastCommitHash == SimpleMerkleRoot(block.LastCommit)
|
||||
```
|
||||
|
||||
@ -217,7 +216,7 @@ The first block has `block.Header.LastCommitHash == []byte{}`
|
||||
|
||||
### TotalTxs
|
||||
|
||||
```
|
||||
```go
|
||||
block.Header.TotalTxs == prevBlock.Header.TotalTxs + block.Header.NumTxs
|
||||
```
|
||||
|
||||
@ -227,7 +226,7 @@ The first block has `block.Header.TotalTxs = block.Header.NumberTxs`.
|
||||
|
||||
### LastBlockID
|
||||
|
||||
```
|
||||
```go
|
||||
prevBlockParts := MakeParts(prevBlock, state.LastConsensusParams.BlockGossip.BlockPartSize)
|
||||
block.Header.LastBlockID == BlockID {
|
||||
Hash: SimpleMerkleRoot(prevBlock.Header),
|
||||
@ -245,7 +244,7 @@ The first block has `block.Header.LastBlockID == BlockID{}`.
|
||||
|
||||
### ResultsHash
|
||||
|
||||
```
|
||||
```go
|
||||
block.ResultsHash == SimpleMerkleRoot(state.LastResults)
|
||||
```
|
||||
|
||||
@ -255,7 +254,7 @@ The first block has `block.Header.ResultsHash == []byte{}`.
|
||||
|
||||
### AppHash
|
||||
|
||||
```
|
||||
```go
|
||||
block.AppHash == state.AppHash
|
||||
```
|
||||
|
||||
@ -265,7 +264,7 @@ The first block has `block.Header.AppHash == []byte{}`.
|
||||
|
||||
### ValidatorsHash
|
||||
|
||||
```
|
||||
```go
|
||||
block.ValidatorsHash == SimpleMerkleRoot(state.Validators)
|
||||
```
|
||||
|
||||
@ -275,7 +274,7 @@ May be updated by the application.
|
||||
|
||||
### ConsensusParamsHash
|
||||
|
||||
```
|
||||
```go
|
||||
block.ConsensusParamsHash == SimpleMerkleRoot(state.ConsensusParams)
|
||||
```
|
||||
|
||||
@ -284,7 +283,7 @@ May be updated by the application.
|
||||
|
||||
### Proposer
|
||||
|
||||
```
|
||||
```go
|
||||
block.Header.Proposer in state.Validators
|
||||
```
|
||||
|
||||
@ -296,7 +295,7 @@ and we do not track the initial round the block was proposed.
|
||||
|
||||
### EvidenceHash
|
||||
|
||||
```
|
||||
```go
|
||||
block.EvidenceHash == SimpleMerkleRoot(block.Evidence)
|
||||
```
|
||||
|
||||
@ -310,7 +309,7 @@ Arbitrary length array of arbitrary length byte-arrays.
|
||||
|
||||
The first height is an exception - it requires the LastCommit to be empty:
|
||||
|
||||
```
|
||||
```go
|
||||
if block.Header.Height == 1 {
|
||||
len(b.LastCommit) == 0
|
||||
}
|
||||
@ -318,7 +317,7 @@ if block.Header.Height == 1 {
|
||||
|
||||
Otherwise, we require:
|
||||
|
||||
```
|
||||
```go
|
||||
len(block.LastCommit) == len(state.LastValidators)
|
||||
talliedVotingPower := 0
|
||||
for i, vote := range block.LastCommit{
|
||||
@ -356,7 +355,7 @@ For signing, votes are encoded in JSON, and the ChainID is included, in the form
|
||||
We define a method `Verify` that returns `true` if the signature verifies against the pubkey for the CanonicalSignBytes
|
||||
using the given ChainID:
|
||||
|
||||
```
|
||||
```go
|
||||
func (v Vote) Verify(chainID string, pubKey PubKey) bool {
|
||||
return pubKey.Verify(v.Signature, CanonicalSignBytes(chainID, v))
|
||||
}
|
||||
@ -384,7 +383,7 @@ Once a block is validated, it can be executed against the state.
|
||||
|
||||
The state follows the recursive equation:
|
||||
|
||||
```
|
||||
```go
|
||||
app = NewABCIApp
|
||||
state(1) = InitialState
|
||||
state(h+1) <- Execute(state(h), app, block(h))
|
||||
|
@ -1,197 +1,210 @@
|
||||
# Tendermint Consensus
|
||||
# Tendermint Consensus Reactor
|
||||
|
||||
Tendermint consensus is a distributed protocol executed by validator processes to agree on
|
||||
the next block to be added to the Tendermint blockchain. The protocol proceeds in rounds, where
|
||||
each round is a try to reach agreement on the next block. A round starts by having a dedicated
|
||||
process (called proposer) suggesting to other processes what should be the next block with
|
||||
Tendermint Consensus is a distributed protocol executed by validator processes to agree on
|
||||
the next block to be added to the Tendermint blockchain. The protocol proceeds in rounds, where
|
||||
each round is a try to reach agreement on the next block. A round starts by having a dedicated
|
||||
process (called proposer) suggesting to other processes what should be the next block with
|
||||
the `ProposalMessage`.
|
||||
The processes respond by voting for a block with `VoteMessage` (there are two kinds of vote messages, prevote
|
||||
and precommit votes). Note that a proposal message is just a suggestion what the next block should be; a
|
||||
validator might vote with a `VoteMessage` for a different block. If in some round, enough number
|
||||
of processes vote for the same block, then this block is committed and later added to the blockchain.
|
||||
The processes respond by voting for a block with `VoteMessage` (there are two kinds of vote messages, prevote
|
||||
and precommit votes). Note that a proposal message is just a suggestion what the next block should be; a
|
||||
validator might vote with a `VoteMessage` for a different block. If in some round, enough number
|
||||
of processes vote for the same block, then this block is committed and later added to the blockchain.
|
||||
`ProposalMessage` and `VoteMessage` are signed by the private key of the validator.
|
||||
The internals of the protocol and how it ensures safety and liveness properties are
|
||||
The internals of the protocol and how it ensures safety and liveness properties are
|
||||
explained [here](https://github.com/tendermint/spec).
|
||||
|
||||
For efficiency reasons, validators in Tendermint consensus protocol do not agree directly on the block
|
||||
as the block size is big, i.e., they don't embed the block inside `Proposal` and `VoteMessage`. Instead, they
|
||||
reach agreement on the `BlockID` (see `BlockID` definition in [Blockchain](blockchain.md) section)
|
||||
as the block size is big, i.e., they don't embed the block inside `Proposal` and `VoteMessage`. Instead, they
|
||||
reach agreement on the `BlockID` (see `BlockID` definition in [Blockchain](blockchain.md) section)
|
||||
that uniquely identifies each block. The block itself is disseminated to validator processes using
|
||||
peer-to-peer gossiping protocol. It starts by having a proposer first splitting a block into a
|
||||
number of block parts, that are then gossiped between processes using `BlockPartMessage`.
|
||||
peer-to-peer gossiping protocol. It starts by having a proposer first splitting a block into a
|
||||
number of block parts, that are then gossiped between processes using `BlockPartMessage`.
|
||||
|
||||
Validators in Tendermint communicate by peer-to-peer gossiping protocol. Each validator is connected
|
||||
only to a subset of processes called peers. By the gossiping protocol, a validator send to its peers
|
||||
all needed information (`ProposalMessage`, `VoteMessage` and `BlockPartMessage`) so they can
|
||||
Validators in Tendermint communicate by peer-to-peer gossiping protocol. Each validator is connected
|
||||
only to a subset of processes called peers. By the gossiping protocol, a validator send to its peers
|
||||
all needed information (`ProposalMessage`, `VoteMessage` and `BlockPartMessage`) so they can
|
||||
reach agreement on some block, and also obtain the content of the chosen block (block parts). As part of
|
||||
the gossiping protocol, processes also send auxiliary messages that inform peers about the
|
||||
executed steps of the core consensus algorithm (`NewRoundStepMessage` and `CommitStepMessage`), and
|
||||
the gossiping protocol, processes also send auxiliary messages that inform peers about the
|
||||
executed steps of the core consensus algorithm (`NewRoundStepMessage` and `CommitStepMessage`), and
|
||||
also messages that inform peers what votes the process has seen (`HasVoteMessage`,
|
||||
`VoteSetMaj23Message` and `VoteSetBitsMessage`). These messages are then used in the gossiping protocol
|
||||
to determine what messages a process should send to its peers.
|
||||
|
||||
to determine what messages a process should send to its peers.
|
||||
|
||||
We now describe the content of each message exchanged during Tendermint consensus protocol.
|
||||
|
||||
## ProposalMessage
|
||||
ProposalMessage is sent when a new block is proposed. It is a suggestion of what the
|
||||
|
||||
ProposalMessage is sent when a new block is proposed. It is a suggestion of what the
|
||||
next block in the blockchain should be.
|
||||
```
|
||||
|
||||
```go
|
||||
type ProposalMessage struct {
|
||||
Proposal Proposal
|
||||
Proposal Proposal
|
||||
}
|
||||
```
|
||||
|
||||
### Proposal
|
||||
|
||||
Proposal contains height and round for which this proposal is made, BlockID as a unique identifier of proposed
|
||||
block, timestamp, and two fields (POLRound and POLBlockID) that are needed for termination of the consensus.
|
||||
The message is signed by the validator private key.
|
||||
The message is signed by the validator private key.
|
||||
|
||||
```
|
||||
```go
|
||||
type Proposal struct {
|
||||
Height int64
|
||||
Round int
|
||||
Timestamp Time
|
||||
BlockID BlockID
|
||||
POLRound int
|
||||
POLBlockID BlockID
|
||||
Signature Signature
|
||||
Height int64
|
||||
Round int
|
||||
Timestamp Time
|
||||
BlockID BlockID
|
||||
POLRound int
|
||||
POLBlockID BlockID
|
||||
Signature Signature
|
||||
}
|
||||
```
|
||||
|
||||
NOTE: In the current version of the Tendermint, the consensus value in proposal is represented with
|
||||
PartSetHeader, and with BlockID in vote message. It should be aligned as suggested in this spec as
|
||||
BlockID contains PartSetHeader.
|
||||
PartSetHeader, and with BlockID in vote message. It should be aligned as suggested in this spec as
|
||||
BlockID contains PartSetHeader.
|
||||
|
||||
## VoteMessage
|
||||
|
||||
VoteMessage is sent to vote for some block (or to inform others that a process does not vote in the current round).
|
||||
Vote is defined in [Blockchain](blockchain.md) section and contains validator's information (validator address
|
||||
and index), height and round for which the vote is sent, vote type, blockID if process vote for some
|
||||
Vote is defined in [Blockchain](blockchain.md) section and contains validator's information (validator address
|
||||
and index), height and round for which the vote is sent, vote type, blockID if process vote for some
|
||||
block (`nil` otherwise) and a timestamp when the vote is sent. The message is signed by the validator private key.
|
||||
```
|
||||
|
||||
```go
|
||||
type VoteMessage struct {
|
||||
Vote Vote
|
||||
Vote Vote
|
||||
}
|
||||
```
|
||||
|
||||
## BlockPartMessage
|
||||
BlockPartMessage is sent when gossipping a piece of the proposed block. It contains height, round
|
||||
and the block part.
|
||||
|
||||
```
|
||||
BlockPartMessage is sent when gossipping a piece of the proposed block. It contains height, round
|
||||
and the block part.
|
||||
|
||||
```go
|
||||
type BlockPartMessage struct {
|
||||
Height int64
|
||||
Round int
|
||||
Part Part
|
||||
Height int64
|
||||
Round int
|
||||
Part Part
|
||||
}
|
||||
```
|
||||
|
||||
## ProposalHeartbeatMessage
|
||||
ProposalHeartbeatMessage is sent to signal that a node is alive and waiting for transactions
|
||||
## ProposalHeartbeatMessage
|
||||
|
||||
ProposalHeartbeatMessage is sent to signal that a node is alive and waiting for transactions
|
||||
to be able to create a next block proposal.
|
||||
|
||||
```
|
||||
```go
|
||||
type ProposalHeartbeatMessage struct {
|
||||
Heartbeat Heartbeat
|
||||
}
|
||||
```
|
||||
|
||||
### Heartbeat
|
||||
Heartbeat contains validator information (address and index),
|
||||
height, round and sequence number. It is signed by the private key of the validator.
|
||||
|
||||
```
|
||||
Heartbeat contains validator information (address and index),
|
||||
height, round and sequence number. It is signed by the private key of the validator.
|
||||
|
||||
```go
|
||||
type Heartbeat struct {
|
||||
ValidatorAddress []byte
|
||||
ValidatorIndex int
|
||||
Height int64
|
||||
Round int
|
||||
Sequence int
|
||||
Signature Signature
|
||||
ValidatorAddress []byte
|
||||
ValidatorIndex int
|
||||
Height int64
|
||||
Round int
|
||||
Sequence int
|
||||
Signature Signature
|
||||
}
|
||||
```
|
||||
|
||||
## NewRoundStepMessage
|
||||
NewRoundStepMessage is sent for every step transition during the core consensus algorithm execution. It is
|
||||
used in the gossip part of the Tendermint protocol to inform peers about a current height/round/step
|
||||
|
||||
NewRoundStepMessage is sent for every step transition during the core consensus algorithm execution. It is
|
||||
used in the gossip part of the Tendermint protocol to inform peers about a current height/round/step
|
||||
a process is in.
|
||||
|
||||
```
|
||||
```go
|
||||
type NewRoundStepMessage struct {
|
||||
Height int64
|
||||
Round int
|
||||
Step RoundStepType
|
||||
SecondsSinceStartTime int
|
||||
LastCommitRound int
|
||||
Height int64
|
||||
Round int
|
||||
Step RoundStepType
|
||||
SecondsSinceStartTime int
|
||||
LastCommitRound int
|
||||
}
|
||||
```
|
||||
|
||||
## CommitStepMessage
|
||||
|
||||
CommitStepMessage is sent when an agreement on some block is reached. It contains height for which agreement
|
||||
is reached, block parts header that describes the decided block and is used to obtain all block parts,
|
||||
and a bit array of the block parts a process currently has, so its peers can know what parts
|
||||
it is missing so they can send them.
|
||||
and a bit array of the block parts a process currently has, so its peers can know what parts
|
||||
it is missing so they can send them.
|
||||
|
||||
```
|
||||
```go
|
||||
type CommitStepMessage struct {
|
||||
Height int64
|
||||
BlockID BlockID
|
||||
BlockParts BitArray
|
||||
Height int64
|
||||
BlockID BlockID
|
||||
BlockParts BitArray
|
||||
}
|
||||
```
|
||||
|
||||
TODO: We use BlockID instead of BlockPartsHeader (in current implementation) for symmetry.
|
||||
TODO: We use BlockID instead of BlockPartsHeader (in current implementation) for symmetry.
|
||||
|
||||
## ProposalPOLMessage
|
||||
|
||||
ProposalPOLMessage is sent when a previous block is re-proposed.
|
||||
It is used to inform peers in what round the process learned for this block (ProposalPOLRound),
|
||||
and what prevotes for the re-proposed block the process has.
|
||||
|
||||
```
|
||||
and what prevotes for the re-proposed block the process has.
|
||||
|
||||
```go
|
||||
type ProposalPOLMessage struct {
|
||||
Height int64
|
||||
ProposalPOLRound int
|
||||
ProposalPOL BitArray
|
||||
Height int64
|
||||
ProposalPOLRound int
|
||||
ProposalPOL BitArray
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## HasVoteMessage
|
||||
HasVoteMessage is sent to indicate that a particular vote has been received. It contains height,
|
||||
round, vote type and the index of the validator that is the originator of the corresponding vote.
|
||||
|
||||
```
|
||||
HasVoteMessage is sent to indicate that a particular vote has been received. It contains height,
|
||||
round, vote type and the index of the validator that is the originator of the corresponding vote.
|
||||
|
||||
```go
|
||||
type HasVoteMessage struct {
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
Index int
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
Index int
|
||||
}
|
||||
```
|
||||
|
||||
## VoteSetMaj23Message
|
||||
VoteSetMaj23Message is sent to indicate that a process has seen +2/3 votes for some BlockID.
|
||||
It contains height, round, vote type and the BlockID.
|
||||
|
||||
```
|
||||
VoteSetMaj23Message is sent to indicate that a process has seen +2/3 votes for some BlockID.
|
||||
It contains height, round, vote type and the BlockID.
|
||||
|
||||
```go
|
||||
type VoteSetMaj23Message struct {
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
BlockID BlockID
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
BlockID BlockID
|
||||
}
|
||||
```
|
||||
|
||||
## VoteSetBitsMessage
|
||||
VoteSetBitsMessage is sent to communicate the bit-array of votes a process has seen for a given
|
||||
BlockID. It contains height, round, vote type, BlockID and a bit array of
|
||||
|
||||
VoteSetBitsMessage is sent to communicate the bit-array of votes a process has seen for a given
|
||||
BlockID. It contains height, round, vote type, BlockID and a bit array of
|
||||
the votes a process has.
|
||||
|
||||
```
|
||||
```go
|
||||
type VoteSetBitsMessage struct {
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
BlockID BlockID
|
||||
Votes BitArray
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
BlockID BlockID
|
||||
Votes BitArray
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
## Binary Serialization (TMBIN)
|
||||
|
||||
Tendermint aims to encode data structures in a manner similar to how the corresponding Go structs are laid out in memory.
|
||||
Tendermint aims to encode data structures in a manner similar to how the corresponding Go structs
|
||||
are laid out in memory.
|
||||
Variable length items are length-prefixed.
|
||||
While the encoding was inspired by Go, it is easily implemented in other languages as well given its intuitive design.
|
||||
While the encoding was inspired by Go, it is easily implemented in other languages as well given its
|
||||
intuitive design.
|
||||
|
||||
XXX: This is changing to use real varints and 4-byte-prefixes.
|
||||
See https://github.com/tendermint/go-wire/tree/sdk2.
|
||||
@ -19,7 +21,7 @@ Negative integers are encoded via twos-complement.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
```go
|
||||
encode(uint8(6)) == [0x06]
|
||||
encode(uint32(6)) == [0x00, 0x00, 0x00, 0x06]
|
||||
|
||||
@ -36,10 +38,9 @@ Negative integers are encoded by flipping the leading bit of the length-prefix t
|
||||
|
||||
Zero is encoded as `0x00`. It is not length-prefixed.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
```go
|
||||
encode(uint(6)) == [0x01, 0x06]
|
||||
encode(uint(70000)) == [0x03, 0x01, 0x11, 0x70]
|
||||
|
||||
@ -58,7 +59,7 @@ The empty string is encoded as `0x00`. It is not length-prefixed.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
```go
|
||||
encode("") == [0x00]
|
||||
encode("a") == [0x01, 0x01, 0x61]
|
||||
encode("hello") == [0x01, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F]
|
||||
@ -72,7 +73,7 @@ There is no length-prefix.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
```go
|
||||
encode([4]int8{1, 2, 3, 4}) == [0x01, 0x02, 0x03, 0x04]
|
||||
encode([4]int16{1, 2, 3, 4}) == [0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04]
|
||||
encode([4]int{1, 2, 3, 4}) == [0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04]
|
||||
@ -81,14 +82,15 @@ encode([2]string{"abc", "efg"}) == [0x01, 0x03, 0x61, 0x62, 0x63, 0x01, 0x03, 0x
|
||||
|
||||
### Slices (variable length)
|
||||
|
||||
An encoded variable-length array is a length prefix followed by the concatenation of the encoding of its elements.
|
||||
An encoded variable-length array is a length prefix followed by the concatenation of the encoding of
|
||||
its elements.
|
||||
The length-prefix is itself encoded as an `int`.
|
||||
|
||||
An empty slice is encoded as `0x00`. It is not length-prefixed.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
```go
|
||||
encode([]int8{}) == [0x00]
|
||||
encode([]int8{1, 2, 3, 4}) == [0x01, 0x04, 0x01, 0x02, 0x03, 0x04]
|
||||
encode([]int16{1, 2, 3, 4}) == [0x01, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04]
|
||||
@ -97,10 +99,11 @@ encode([]string{"abc", "efg"}) == [0x01, 0x02, 0x01, 0x03, 0x61, 0x62, 0x63, 0x
|
||||
```
|
||||
|
||||
### BitArray
|
||||
|
||||
BitArray is encoded as an `int` of the number of bits, and with an array of `uint64` to encode
|
||||
value of each array element.
|
||||
|
||||
```
|
||||
```go
|
||||
type BitArray struct {
|
||||
Bits int
|
||||
Elems []uint64
|
||||
@ -116,7 +119,7 @@ Times before then are invalid.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
```go
|
||||
encode(time.Time("Jan 1 00:00:00 UTC 1970")) == [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
||||
encode(time.Time("Jan 1 00:00:01 UTC 1970")) == [0x00, 0x00, 0x00, 0x00, 0x3B, 0x9A, 0xCA, 0x00] // 1,000,000,000 ns
|
||||
encode(time.Time("Mon Jan 2 15:04:05 -0700 MST 2006")) == [0x0F, 0xC4, 0xBB, 0xC1, 0x53, 0x03, 0x12, 0x00]
|
||||
@ -129,7 +132,7 @@ There is no length-prefix.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
```go
|
||||
type MyStruct struct{
|
||||
A int
|
||||
B string
|
||||
@ -139,7 +142,6 @@ encode(MyStruct{4, "hello", time.Time("Mon Jan 2 15:04:05 -0700 MST 2006")}) ==
|
||||
[0x01, 0x04, 0x01, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0F, 0xC4, 0xBB, 0xC1, 0x53, 0x03, 0x12, 0x00]
|
||||
```
|
||||
|
||||
|
||||
## Merkle Trees
|
||||
|
||||
Simple Merkle trees are used in numerous places in Tendermint to compute a cryptographic digest of a data structure.
|
||||
@ -148,23 +150,24 @@ RIPEMD160 is always used as the hashing function.
|
||||
|
||||
The function `SimpleMerkleRoot` is a simple recursive function defined as follows:
|
||||
|
||||
```
|
||||
```go
|
||||
func SimpleMerkleRoot(hashes [][]byte) []byte{
|
||||
switch len(hashes) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return hashes[0]
|
||||
default:
|
||||
left := SimpleMerkleRoot(hashes[:(len(hashes)+1)/2])
|
||||
right := SimpleMerkleRoot(hashes[(len(hashes)+1)/2:])
|
||||
return RIPEMD160(append(left, right))
|
||||
}
|
||||
switch len(hashes) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return hashes[0]
|
||||
default:
|
||||
left := SimpleMerkleRoot(hashes[:(len(hashes)+1)/2])
|
||||
right := SimpleMerkleRoot(hashes[(len(hashes)+1)/2:])
|
||||
return RIPEMD160(append(left, right))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note we abuse notion and call `SimpleMerkleRoot` with arguments of type `struct` or type `[]struct`.
|
||||
For `struct` arguments, we compute a `[][]byte` by sorting elements of the `struct` according to field name and then hashing them.
|
||||
For `struct` arguments, we compute a `[][]byte` by sorting elements of the `struct` according to
|
||||
field name and then hashing them.
|
||||
For `[]struct` arguments, we compute a `[][]byte` by hashing the individual `struct` elements.
|
||||
|
||||
## JSON (TMJSON)
|
||||
@ -172,10 +175,12 @@ For `[]struct` arguments, we compute a `[][]byte` by hashing the individual `str
|
||||
Signed messages (eg. votes, proposals) in the consensus are encoded in TMJSON, rather than TMBIN.
|
||||
TMJSON is JSON where `[]byte` are encoded as uppercase hex, rather than base64.
|
||||
|
||||
When signing, the elements of a message are sorted by key and the sorted message is embedded in an outer JSON that includes a `chain_id` field.
|
||||
We call this encoding the CanonicalSignBytes. For instance, CanonicalSignBytes for a vote would look like:
|
||||
When signing, the elements of a message are sorted by key and the sorted message is embedded in an
|
||||
outer JSON that includes a `chain_id` field.
|
||||
We call this encoding the CanonicalSignBytes. For instance, CanonicalSignBytes for a vote would look
|
||||
like:
|
||||
|
||||
```
|
||||
```json
|
||||
{"chain_id":"my-chain-id","vote":{"block_id":{"hash":DEADBEEF,"parts":{"hash":BEEFDEAD,"total":3}},"height":3,"round":2,"timestamp":1234567890, "type":2}
|
||||
```
|
||||
|
||||
@ -187,16 +192,16 @@ Note how the fields within each level are sorted.
|
||||
|
||||
TMBIN encode an object and slice it into parts.
|
||||
|
||||
```
|
||||
```go
|
||||
MakeParts(object, partSize)
|
||||
```
|
||||
|
||||
### Part
|
||||
|
||||
```
|
||||
```go
|
||||
type Part struct {
|
||||
Index int
|
||||
Bytes byte[]
|
||||
Proof byte[]
|
||||
Index int
|
||||
Bytes byte[]
|
||||
Proof byte[]
|
||||
}
|
||||
```
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
## State
|
||||
|
||||
The state contains information whose cryptographic digest is included in block headers,
|
||||
and thus is necessary for validating new blocks.
|
||||
For instance, the Merkle root of the results from executing the previous block, or the Merkle root of the current validators.
|
||||
While neither the results of transactions now the validators are ever included in the blockchain itself,
|
||||
the Merkle roots are, and hence we need a separate data structure to track them.
|
||||
The state contains information whose cryptographic digest is included in block headers, and thus is
|
||||
necessary for validating new blocks. For instance, the Merkle root of the results from executing the
|
||||
previous block, or the Merkle root of the current validators. While neither the results of
|
||||
transactions now the validators are ever included in the blockchain itself, the Merkle roots are,
|
||||
and hence we need a separate data structure to track them.
|
||||
|
||||
```
|
||||
```go
|
||||
type State struct {
|
||||
LastResults []Result
|
||||
AppHash []byte
|
||||
@ -22,7 +22,7 @@ type State struct {
|
||||
|
||||
### Result
|
||||
|
||||
```
|
||||
```go
|
||||
type Result struct {
|
||||
Code uint32
|
||||
Data []byte
|
||||
@ -46,7 +46,7 @@ represented in the tags.
|
||||
A validator is an active participant in the consensus with a public key and a voting power.
|
||||
Validator's also contain an address which is derived from the PubKey:
|
||||
|
||||
```
|
||||
```go
|
||||
type Validator struct {
|
||||
Address []byte
|
||||
PubKey PubKey
|
||||
@ -59,7 +59,7 @@ so that there is a canonical order for computing the SimpleMerkleRoot.
|
||||
|
||||
We also define a `TotalVotingPower` function, to return the total voting power:
|
||||
|
||||
```
|
||||
```go
|
||||
func TotalVotingPower(vals []Validators) int64{
|
||||
sum := 0
|
||||
for v := range vals{
|
||||
@ -82,7 +82,7 @@ TODO:
|
||||
We define an `Execute` function that takes a state and a block,
|
||||
executes the block against the application, and returns an updated state.
|
||||
|
||||
```
|
||||
```go
|
||||
Execute(s State, app ABCIApp, block Block) State {
|
||||
abciResponses := app.ApplyBlock(block)
|
||||
|
||||
|
Reference in New Issue
Block a user