From 84ee4249aea6740a1149cc8ca47b6e9f123305c1 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Tue, 20 Apr 2021 10:21:27 +0200 Subject: [PATCH] core: update a few sections (#284) --- spec/core/data_structures.md | 20 +++-- spec/core/readme.md | 1 + spec/core/state.md | 151 ++++++++++------------------------- 3 files changed, 57 insertions(+), 115 deletions(-) diff --git a/spec/core/data_structures.md b/spec/core/data_structures.md index e63b9529f..8288a0626 100644 --- a/spec/core/data_structures.md +++ b/spec/core/data_structures.md @@ -26,11 +26,13 @@ The Tendermint blockchains consists of a short list of data types: - [`Validator`](#validator) - [`ValidatorSet`](#validatorset) - [`Address`](#address) -- [`ConsensusParams](#consensusparams) +- [`ConsensusParams`](#consensusparams) +- [`BlockParams`](#blockparams) - [`EvidenceParams`](#evidenceparams) - [`ValidatorParams`](#validatorparams) - [`VersionParams`](#versionparams) + ## Block A block consists of a header, transactions, votes (the commit), @@ -110,7 +112,7 @@ the data in the current block, the previous block, and the results returned by t | Name | Type | Description | Validation | |-------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Version | [Version](#version) | Version defines the application and protocol verion being used. | Must adhere to the validation rules of [Version](#version) | +| Version | [Version](#version) | Version defines the application and protocol version being used. | Must adhere to the validation rules of [Version](#version) | | ChainID | String | ChainID is the ID of the chain. This must be unique to your chain. | ChainID must be less than 50 bytes. | | Height | uint64 | Height is the height for this header. | Must be > 0, >= initialHeight, and == previous Height+1 | | Time | [Time](#time) | The timestamp is equal to the weighted median of validators present in the last commit. Read more on time in the [BFT-time section](../consensus/bft-time.md). Note: the timestamp of a vote must be greater by at least one millisecond than that of the block being voted on. | Time must be >= previous header timestamp + consensus parameters TimeIotaMs. The timestamp of the first block must be equal to the genesis time (since there's no votes to compute the median). | @@ -127,6 +129,10 @@ the data in the current block, the previous block, and the results returned by t ## Version +NOTE: that this is more specifically the consensus version and doesn't include information like the +P2P Version. (TODO: we should write a comprehensive document about +versioning that this can refer to) + | Name | type | Description | Validation | |-------|--------|-----------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------| | Block | uint64 | This number represents the version of the block protocol and must be the same throughout an operational network | Must be equal to protocol version being used in a network (`block.Version.Block == state.Version.Consensus.Block`) | @@ -265,7 +271,7 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error { } ``` -### Proposal +## Proposal Proposal contains height and round for which this proposal is made, BlockID as a unique identifier of proposed block, timestamp, and POLRound (a so-called Proof-of-Lock (POL) round) that is needed for @@ -430,7 +436,7 @@ func SumTruncated(bz []byte) []byte { } ``` -### ConsensusParams +## ConsensusParams | Name | Type | Description | Field Number | |-----------|-------------------------------------|------------------------------------------------------------------------------|--------------| @@ -446,7 +452,7 @@ func SumTruncated(bz []byte) []byte { | max_bytes | int64 | Max size of a block, in bytes. | 1 | | max_gas | int64 | Max sum of `GasWanted` in a proposed block. NOTE: blocks that violate this may be committed if there are Byzantine proposers. It's the application's responsibility to handle this when processing a block! | 2 | -### EvidenceParams +## EvidenceParams | Name | Type | Description | Field Number | |--------------------|------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------| @@ -454,13 +460,13 @@ func SumTruncated(bz []byte) []byte { | max_age_duration | [google.protobuf.Duration](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Duration) | Max age of evidence, in time. It should correspond with an app's "unbonding period" or other similar mechanism for handling [Nothing-At-Stake attacks](https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed). | 2 | | max_bytes | int64 | maximum size in bytes of total evidence allowed to be entered into a block | 3 | -### ValidatorParams +## ValidatorParams | Name | Type | Description | Field Number | |---------------|-----------------|-----------------------------------------------------------------------|--------------| | pub_key_types | repeated string | List of accepted public key types. Uses same naming as `PubKey.Type`. | 1 | -### VersionParams +## VersionParams | Name | Type | Description | Field Number | |-------------|--------|-------------------------------|--------------| diff --git a/spec/core/readme.md b/spec/core/readme.md index 87eece472..46f95f1b7 100644 --- a/spec/core/readme.md +++ b/spec/core/readme.md @@ -9,4 +9,5 @@ This section describes the core types and functionality of the Tendermint protoc - [Core Data Structures](./data_structures.md) - [Encoding](./encoding.md) +- [Genesis](./genesis.md) - [State](./state.md) diff --git a/spec/core/state.md b/spec/core/state.md index eb020e489..3b8e1a22c 100644 --- a/spec/core/state.md +++ b/spec/core/state.md @@ -1,6 +1,5 @@ # State -## State The state contains information whose cryptographic digest is included in block headers, and thus is necessary for validating new blocks. For instance, the validators set and the results of @@ -18,13 +17,17 @@ type State struct { ChainID string InitialHeight int64 + LastBlockHeight int64 + LastBlockID types.BlockID + LastBlockTime time.Time + Version Version LastResults []Result AppHash []byte - LastValidators []Validator - Validators []Validator - NextValidators []Validator + LastValidators ValidatorSet + Validators ValidatorSet + NextValidators ValidatorSet ConsensusParams ConsensusParams } @@ -36,129 +39,61 @@ initial height will be `1` in the typical case, `0` is an invalid value. Note there is a hard-coded limit of 10000 validators. This is inherited from the limit on the number of votes in a commit. -### Version +Further information on [`Validator`'s](./data_structures.md#validator), +[`ValidatorSet`'s](./data_structures.md#validatorset) and +[`ConsensusParams`'s](./data_structures.md#consensusparams) can +be found in [data structures](./data_structures.md) -```go -type Version struct { - consensus Consensus - software string -} -``` +## Execution -The `Consensus` contains the protocol version for the blockchain and the -application as two `uint64` values: +State gets updated at the end of executing a block. Of specific interest is `ResponseEndBlock` and +`ResponseCommit` ```go -type Consensus struct { - Block uint64 - App uint64 -} -``` - -### ResponseDeliverTx - -```protobuf -message ResponseDeliverTx { - uint32 code = 1; - bytes data = 2; - string log = 3; // nondeterministic - string info = 4; // nondeterministic - int64 gas_wanted = 5; - int64 gas_used = 6; - repeated Event events = 7 - [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; - string codespace = 8; +type ResponseEndBlock struct { + ValidatorUpdates []ValidatorUpdate `protobuf:"bytes,1,rep,name=validator_updates,json=validatorUpdates,proto3" json:"validator_updates"` + ConsensusParamUpdates *types1.ConsensusParams `protobuf:"bytes,2,opt,name=consensus_param_updates,json=consensusParamUpdates,proto3" json:"consensus_param_updates,omitempty"` + Events []Event `protobuf:"bytes,3,rep,name=events,proto3" json:"events,omitempty"` } ``` -`ResponseDeliverTx` is the result of executing a transaction against the application. -It returns a result code (`uint32`), an arbitrary byte array (`[]byte`) (ie. a return value), Log (`string`), Info (`string`), GasWanted (`int64`), GasUsed (`int64`), Events (`[]Events`) and a Codespace (`string`). - -### Validator - -A validator is an active participant in the consensus with a public key and a voting power. -Validator's also contain an address field, which is a hash digest of the PubKey. +where ```go -type Validator struct { - Address []byte - PubKey PubKey - VotingPower int64 +type ValidatorUpdate struct { + PubKey crypto.PublicKey `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key"` + Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` } ``` -When hashing the Validator struct, the address is not included, -because it is redundant with the pubkey. - -The `state.Validators`, `state.LastValidators`, and `state.NextValidators`, -must always be sorted by voting power, so that there is a canonical order for -computing the MerkleRoot. - -We also define a `TotalVotingPower` function, to return the total voting power: +and ```go -func TotalVotingPower(vals []Validators) int64{ - sum := 0 - for v := range vals{ - sum += v.VotingPower - } - return sum +type ResponseCommit struct { + // reserve 1 + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + RetainHeight int64 `protobuf:"varint,3,opt,name=retain_height,json=retainHeight,proto3" json:"retain_height,omitempty"` } ``` -### ConsensusParams +`ValidatorUpdates` are used to add and remove validators to the current set as well as update +validator power. Setting validator power to 0 in `ValidatorUpdate` will cause the validator to be +removed. `ConsensusParams` are safely copied across (i.e. if a field is nil it gets ignored) and the +`Data` from the `ResponseCommit` is used as the `AppHash` -ConsensusParams define various limits for blockchain data structures. -Like validator sets, they are set during genesis and can be updated by the application through ABCI. -When hashed, only a subset of the params are included, to allow the params to -evolve without breaking the header. - -```protobuf -message ConsensusParams { - BlockParams block = 1; - EvidenceParams evidence = 2; - ValidatorParams validator = 3; - VersionParams version = 4; -} -``` +## Version ```go -type hashedParams struct { - BlockMaxBytes int64 - BlockMaxGas int64 -} - -func HashConsensusParams() []byte { - SHA256(hashedParams{ - BlockMaxBytes: params.Block.MaxBytes, - BlockMaxGas: params.Block.MaxGas, - }) +type Version struct { + consensus Consensus + software string } ``` -```protobuf -message BlockParams { - int64 max_bytes = 1; - int64 max_gas = 2; - int64 time_iota_ms = 3; // not exposed to the application -} - -message EvidenceParams { - int64 max_age_num_blocks = 1; - google.protobuf.Duration max_age_duration = 2; - uint32 max_num = 3; -} - -message ValidatorParams { - repeated string pub_key_types = 1; -} - -message VersionParams { - uint64 AppVersion = 1; -} -``` +[`Consensus`](./data_structures.md#version) contains the protocol version for the blockchain and the +application. -#### Block +## Block The total size of a block is limited in bytes by the `ConsensusParams.Block.MaxBytes`. Proposed blocks must be less than this size, and will be considered invalid @@ -167,10 +102,7 @@ otherwise. Blocks should additionally be limited by the amount of "gas" consumed by the transactions in the block, though this is not yet implemented. -The minimal time between consecutive blocks is controlled by the -`ConsensusParams.Block.TimeIotaMs`. - -#### Evidence +## Evidence For evidence in a block to be valid, it must satisfy: @@ -179,7 +111,10 @@ block.Header.Time-evidence.Time < ConsensusParams.Evidence.MaxAgeDuration && block.Header.Height-evidence.Height < ConsensusParams.Evidence.MaxAgeNumBlocks ``` -#### Validator +A block must not contain more than `ConsensusParams.Evidence.MaxBytes` of evidence. This is +implemented to mitigate spam attacks. + +## Validator Validators from genesis file and `ResponseEndBlock` must have pubkeys of type ∈ `ConsensusParams.Validator.PubKeyTypes`.