From e3585a6eb01369a2fd59e3d8168baeec0cebccaa Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 22:18:23 -0500 Subject: [PATCH] wip: tendermint specification --- docs/specification/new-spec/spec-notes.md | 3 + docs/specification/new-spec/spec.md | 303 ++++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 docs/specification/new-spec/spec-notes.md create mode 100644 docs/specification/new-spec/spec.md diff --git a/docs/specification/new-spec/spec-notes.md b/docs/specification/new-spec/spec-notes.md new file mode 100644 index 000000000..fbffac741 --- /dev/null +++ b/docs/specification/new-spec/spec-notes.md @@ -0,0 +1,3 @@ +- Remove BlockID from Commit +- Actually validate the ValidatorsHash +- Move blockHeight=1 exception for LastCommit to ValidateBasic diff --git a/docs/specification/new-spec/spec.md b/docs/specification/new-spec/spec.md new file mode 100644 index 000000000..1569abeb2 --- /dev/null +++ b/docs/specification/new-spec/spec.md @@ -0,0 +1,303 @@ +# Tendermint Blockchain + +Here we describe the data structures in the Tendermint blockchain and the rules for validating them. + +# Data Structures + +The Tendermint blockchains consists of a short list of basic data types: +blocks, headers, votes, block ids, and signatures. + +## Block + +A block consists of a header, a list of transactions, and a list of votes (the commit). + +``` +type Block struct { + Header Header + Txs [][]byte + LastCommit []Vote + Evidence []Evidence +} +``` + +## Header + +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: + +``` +type Header struct { + // block metadata + Version string // Version string + ChainID string // ID of the chain + Height int64 // current block height + Time int64 // UNIX time, in millisconds + + // current block + NumTxs int64 // Number of txs in this block + TxHash []byte // SimpleMerkle of the block.Txs + LastCommitHash []byte // SimpleMerkle of the block.LastCommit + + // previous block + TotalTxs int64 // prevBlock.TotalTxs + block.NumTxs + LastBlockID BlockID // BlockID of prevBlock + + // application + ResultsHash []byte // SimpleMerkle of []abci.Result from prevBlock + AppHash []byte // Arbitrary state digest + ValidatorsHash []byte // SimpleMerkle of the ValidatorSet + ConsensusParamsHash []byte // SimpleMerkle of the ConsensusParams + + // consensus + Proposer []byte // Address of the block proposer + EvidenceHash []byte // SimpleMerkle of []Evidence +} +``` + +## BlockID + +The `BlockID` contains two distinct Merkle roots of the block. +The first, used as the block's main hash, is the Merkle root +of all the fields in the header. The second, used for secure gossipping of +the block during consensus, is the Merkle root of the complete serialized block +cut into pieces. The `BlockID` includes these two hashes, as well as the number of +pieces. + +``` +type BlockID struct { + HeaderHash []byte + NumParts int32 + PartsHash []byte +} +``` + +## Vote + +A vote is a signed message from a validator for a particular block. +The vote includes information about the validator signing it. +There are two types of votes, but they have identical structure: + +``` +type Vote struct { + Timestamp int64 + Address []byte + Index int + Height int64 + Round int + Type int8 + BlockID BlockID + Signature Signature +} +``` + +## Signature + +Tendermint allows for multiple signature schemes to be used by prepending a single type-byte +to the signature bytes. Different signatures may also come in different lengths, but this length +is not made explicit. Currently, Tendermint supports Ed25519 and Secp256k1 + +``` +// Implements Signature +type Ed25519Signature struct { + Type int8 = 0x1 + Signature [64]byte +} + +// Implements Signature +type Secp256k1Signature struct { + Type int8 = 0x2 + Signature []byte +} +``` + +# Validation + +Here we go through every element of a block and describe the rules for validation. +Blocks which do not satisfy these rules are considered invalid. + +In the following, `block` refers to the block under consideration, +`prevBlock` refers to the `block` at the previous height, +`state` refers to an object that keeps track of the validator set +and the consensus parameters as they are updated by the application, +and `app` refers to the responses returned by the application during the +execution of the `prevBlock`. + +We abuse notation by using something that looks like Go, supplemented with English. + +## Header + +A Header is valid if its corresponding fields are valid. + +### Version + +Arbitrary string. + +### ChainID + +Arbitrary constant string. + +### Height + +``` +block.Header.Height > 0 +block.Header.Height == prevBlock.Header.Height + 1 +``` + +### Time + +The median of the timestamps of the valid votes in the block.LastCommit. +Corresponds to the number of milliseconds since January 1, 1970. +Increments with every new block. + +### NumTxs + +``` +block.Header.NumTxs == len(block.Txs) +``` + +Number of transactions included in the block. + +### TxHash + +``` +block.Header.TxHash == SimpleMerkleRoot(block.Txs) +``` + +Simple Merkle root of the transactions in the block. + +### LastCommitHash + +``` +block.Header.LastCommitHash == SimpleMerkleRoot(block.LastCommit) +``` + +Simple Merkle root of the votes included in the block. +These are the votes that committed the previous block. + +### TotalTxs + +``` +block.Header.TotalTxs == prevBlock.Header.TotalTxs + block.header.NumTxs +``` + +The cumulative sum of all transactions included in this blockchain. + +### LastBlockID + +``` +parts := MakeBlockParts(block, state.ConsensusParams.BlockGossip.BlockPartSize) +block.HeaderLastBlockID == BlockID{ + SimpleMerkleRoot(block.Header), + len(parts), + SimpleMerkleRoot(parts), +} +``` + +Previous block's BlockID. Note it depends on the ConsensusParams, +which are held in the `state` and may be updated by the application. + +### ResultsHash + +``` +block.ResultsHash == SimpleMerkleRoot(app.Results) +``` + +Simple Merkle root of the results of the transactions in the previous block. + +### AppHash + +``` +block.AppHash == app.AppHash +``` + +Arbitrary byte array returned by the application after executing and commiting the previous block. + +### ValidatorsHash + +``` +block.ValidatorsHash == SimpleMerkleRoot(state.Validators) +``` + +Simple Merkle root of the current validator set that is committing the block. +This can be used to validate the `LastCommit` included in the next block. +May be updated by the applicatoin. + +### ConsensusParamsHash + +``` +block.ValidatorsHash == SimpleMerkleRoot(state.ConsensusParams) +``` + +Simple Merkle root of the consensus parameters. +May be updated by the application. + +### Proposer + +Original proposer of the block. + +TODO + +### EvidenceHash + +``` +block.EvidenceHash == SimpleMerkleRoot(block.Evidence) +``` + +Simple Merkle root of the evidence of Byzantine behaviour included in this block. + +## Txs + +Arbitrary length array of arbitrary length byte-arrays. + +## LastCommit + +``` +if block.Header.Height == 1 { + len(b.LastCommit) == 0 +} +``` + +The first height is an exception - it requires the LastCommit to be empty. +Otherwise, we require: + +``` +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 + + pubkey, votingPower := state.LastValidators.Get(i) + VerifyVoteSignature(block.ChainID, vote, pubkey) + + talliedVotingPower += votingPower +} + +talliedVotingPower > state.LastValidators.TotalVotingPower() +``` + +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. +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 the total voting power of the complete validator set. + +## Evidence + + +``` + + +``` + +Every piece of evidence contains two conflicting votes from a single validator that +was active at the height indicated in the votes. +The votes must not be too old. +