Files
tendermint/types/params.go
William Banfield 0aa3b0b6fc Proposer-Based Timestamps Merge (#7605)
This pull request merges in the changes for implementing Proposer-based timestamps into `master`. The power was primarily being done in the `wb/proposer-based-timestamps` branch, with changes being merged into that branch during development. This pull request represents an amalgamation of the changes made into that development branch. All of the changes that were placed into that branch have been cleanly rebased on top of the latest `master`. The changes compile and the tests pass insofar as our tests in general pass.

### Note To Reviewers
 These changes have been extensively reviewed during development. There is not much new here. In the interest of making effective use of time, I would recommend against trying to perform a complete audit of the changes presented and instead examine for mistakes that may have occurred during the process of rebasing the changes. I gave the complete change set a first pass for any issues, but additional eyes would be very appreciated. 

In sum, this change set does the following:
closes #6942 
merges in #6849
2022-01-26 16:00:23 +00:00

324 lines
9.8 KiB
Go

package types
import (
"errors"
"fmt"
"time"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/tendermint/tendermint/crypto/sr25519"
"github.com/tendermint/tendermint/crypto/tmhash"
tmstrings "github.com/tendermint/tendermint/libs/strings"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
const (
// MaxBlockSizeBytes is the maximum permitted size of the blocks.
MaxBlockSizeBytes = 104857600 // 100MB
// BlockPartSizeBytes is the size of one block part.
BlockPartSizeBytes uint32 = 65536 // 64kB
// MaxBlockPartsCount is the maximum number of block parts.
MaxBlockPartsCount = (MaxBlockSizeBytes / BlockPartSizeBytes) + 1
ABCIPubKeyTypeEd25519 = ed25519.KeyType
ABCIPubKeyTypeSecp256k1 = secp256k1.KeyType
ABCIPubKeyTypeSr25519 = sr25519.KeyType
)
var ABCIPubKeyTypesToNames = map[string]string{
ABCIPubKeyTypeEd25519: ed25519.PubKeyName,
ABCIPubKeyTypeSecp256k1: secp256k1.PubKeyName,
ABCIPubKeyTypeSr25519: sr25519.PubKeyName,
}
// ConsensusParams contains consensus critical parameters that determine the
// validity of blocks.
type ConsensusParams struct {
Block BlockParams `json:"block"`
Evidence EvidenceParams `json:"evidence"`
Validator ValidatorParams `json:"validator"`
Version VersionParams `json:"version"`
Synchrony SynchronyParams `json:"synchrony"`
}
// HashedParams is a subset of ConsensusParams.
// It is amino encoded and hashed into
// the Header.ConsensusHash.
type HashedParams struct {
BlockMaxBytes int64
BlockMaxGas int64
}
// BlockParams define limits on the block size and gas plus minimum time
// between blocks.
type BlockParams struct {
MaxBytes int64 `json:"max_bytes,string"`
MaxGas int64 `json:"max_gas,string"`
}
// EvidenceParams determine how we handle evidence of malfeasance.
type EvidenceParams struct {
MaxAgeNumBlocks int64 `json:"max_age_num_blocks,string"` // only accept new evidence more recent than this
MaxAgeDuration time.Duration `json:"max_age_duration,string"`
MaxBytes int64 `json:"max_bytes,string"`
}
// ValidatorParams restrict the public key types validators can use.
// NOTE: uses ABCI pubkey naming, not Amino names.
type ValidatorParams struct {
PubKeyTypes []string `json:"pub_key_types"`
}
type VersionParams struct {
AppVersion uint64 `json:"app_version,string"`
}
// SynchronyParams influence the validity of block timestamps.
// For more information on the relationship of the synchrony parameters to
// block validity, see the Proposer-Based Timestamps specification:
// https://github.com/tendermint/spec/blob/master/spec/consensus/proposer-based-timestamp/README.md
type SynchronyParams struct {
Precision time.Duration `json:"precision,string"`
MessageDelay time.Duration `json:"message_delay,string"`
}
// DefaultConsensusParams returns a default ConsensusParams.
func DefaultConsensusParams() *ConsensusParams {
return &ConsensusParams{
Block: DefaultBlockParams(),
Evidence: DefaultEvidenceParams(),
Validator: DefaultValidatorParams(),
Version: DefaultVersionParams(),
Synchrony: DefaultSynchronyParams(),
}
}
// DefaultBlockParams returns a default BlockParams.
func DefaultBlockParams() BlockParams {
return BlockParams{
MaxBytes: 22020096, // 21MB
MaxGas: -1,
}
}
// DefaultEvidenceParams returns a default EvidenceParams.
func DefaultEvidenceParams() EvidenceParams {
return EvidenceParams{
MaxAgeNumBlocks: 100000, // 27.8 hrs at 1block/s
MaxAgeDuration: 48 * time.Hour,
MaxBytes: 1048576, // 1MB
}
}
// DefaultValidatorParams returns a default ValidatorParams, which allows
// only ed25519 pubkeys.
func DefaultValidatorParams() ValidatorParams {
return ValidatorParams{
PubKeyTypes: []string{ABCIPubKeyTypeEd25519},
}
}
func DefaultVersionParams() VersionParams {
return VersionParams{
AppVersion: 0,
}
}
func DefaultSynchronyParams() SynchronyParams {
// TODO(@wbanfield): Determine experimental values for these defaults
// https://github.com/tendermint/tendermint/issues/7202
return SynchronyParams{
Precision: 500 * time.Millisecond,
MessageDelay: 2 * time.Second,
}
}
func (val *ValidatorParams) IsValidPubkeyType(pubkeyType string) bool {
for i := 0; i < len(val.PubKeyTypes); i++ {
if val.PubKeyTypes[i] == pubkeyType {
return true
}
}
return false
}
// Validate validates the ConsensusParams to ensure all values are within their
// allowed limits, and returns an error if they are not.
func (params ConsensusParams) ValidateConsensusParams() error {
if params.Block.MaxBytes <= 0 {
return fmt.Errorf("block.MaxBytes must be greater than 0. Got %d",
params.Block.MaxBytes)
}
if params.Block.MaxBytes > MaxBlockSizeBytes {
return fmt.Errorf("block.MaxBytes is too big. %d > %d",
params.Block.MaxBytes, MaxBlockSizeBytes)
}
if params.Block.MaxGas < -1 {
return fmt.Errorf("block.MaxGas must be greater or equal to -1. Got %d",
params.Block.MaxGas)
}
if params.Evidence.MaxAgeNumBlocks <= 0 {
return fmt.Errorf("evidence.MaxAgeNumBlocks must be greater than 0. Got %d",
params.Evidence.MaxAgeNumBlocks)
}
if params.Evidence.MaxAgeDuration <= 0 {
return fmt.Errorf("evidence.MaxAgeDuration must be greater than 0 if provided, Got %v",
params.Evidence.MaxAgeDuration)
}
if params.Evidence.MaxBytes > params.Block.MaxBytes {
return fmt.Errorf("evidence.MaxBytesEvidence is greater than upper bound, %d > %d",
params.Evidence.MaxBytes, params.Block.MaxBytes)
}
if params.Evidence.MaxBytes < 0 {
return fmt.Errorf("evidence.MaxBytes must be non negative. Got: %d",
params.Evidence.MaxBytes)
}
if params.Synchrony.MessageDelay <= 0 {
return fmt.Errorf("synchrony.MessageDelay must be greater than 0. Got: %d",
params.Synchrony.MessageDelay)
}
if params.Synchrony.Precision <= 0 {
return fmt.Errorf("synchrony.Precision must be greater than 0. Got: %d",
params.Synchrony.Precision)
}
if len(params.Validator.PubKeyTypes) == 0 {
return errors.New("len(Validator.PubKeyTypes) must be greater than 0")
}
// Check if keyType is a known ABCIPubKeyType
for i := 0; i < len(params.Validator.PubKeyTypes); i++ {
keyType := params.Validator.PubKeyTypes[i]
if _, ok := ABCIPubKeyTypesToNames[keyType]; !ok {
return fmt.Errorf("params.Validator.PubKeyTypes[%d], %s, is an unknown pubkey type",
i, keyType)
}
}
return nil
}
// Hash returns a hash of a subset of the parameters to store in the block header.
// Only the Block.MaxBytes and Block.MaxGas are included in the hash.
// This allows the ConsensusParams to evolve more without breaking the block
// protocol. No need for a Merkle tree here, just a small struct to hash.
func (params ConsensusParams) HashConsensusParams() []byte {
hasher := tmhash.New()
hp := tmproto.HashedParams{
BlockMaxBytes: params.Block.MaxBytes,
BlockMaxGas: params.Block.MaxGas,
}
bz, err := hp.Marshal()
if err != nil {
panic(err)
}
_, err = hasher.Write(bz)
if err != nil {
panic(err)
}
return hasher.Sum(nil)
}
func (params *ConsensusParams) Equals(params2 *ConsensusParams) bool {
return params.Block == params2.Block &&
params.Evidence == params2.Evidence &&
params.Version == params2.Version &&
params.Synchrony == params2.Synchrony &&
tmstrings.StringSliceEqual(params.Validator.PubKeyTypes, params2.Validator.PubKeyTypes)
}
// Update returns a copy of the params with updates from the non-zero fields of p2.
// NOTE: note: must not modify the original
func (params ConsensusParams) UpdateConsensusParams(params2 *tmproto.ConsensusParams) ConsensusParams {
res := params // explicit copy
if params2 == nil {
return res
}
// we must defensively consider any structs may be nil
if params2.Block != nil {
res.Block.MaxBytes = params2.Block.MaxBytes
res.Block.MaxGas = params2.Block.MaxGas
}
if params2.Evidence != nil {
res.Evidence.MaxAgeNumBlocks = params2.Evidence.MaxAgeNumBlocks
res.Evidence.MaxAgeDuration = params2.Evidence.MaxAgeDuration
res.Evidence.MaxBytes = params2.Evidence.MaxBytes
}
if params2.Validator != nil {
// Copy params2.Validator.PubkeyTypes, and set result's value to the copy.
// This avoids having to initialize the slice to 0 values, and then write to it again.
res.Validator.PubKeyTypes = append([]string{}, params2.Validator.PubKeyTypes...)
}
if params2.Version != nil {
res.Version.AppVersion = params2.Version.AppVersion
}
if params2.Synchrony != nil {
res.Synchrony.Precision = params2.Synchrony.Precision
res.Synchrony.MessageDelay = params2.Synchrony.MessageDelay
}
return res
}
func (params *ConsensusParams) ToProto() tmproto.ConsensusParams {
return tmproto.ConsensusParams{
Block: &tmproto.BlockParams{
MaxBytes: params.Block.MaxBytes,
MaxGas: params.Block.MaxGas,
},
Evidence: &tmproto.EvidenceParams{
MaxAgeNumBlocks: params.Evidence.MaxAgeNumBlocks,
MaxAgeDuration: params.Evidence.MaxAgeDuration,
MaxBytes: params.Evidence.MaxBytes,
},
Validator: &tmproto.ValidatorParams{
PubKeyTypes: params.Validator.PubKeyTypes,
},
Version: &tmproto.VersionParams{
AppVersion: params.Version.AppVersion,
},
Synchrony: &tmproto.SynchronyParams{
MessageDelay: params.Synchrony.MessageDelay,
Precision: params.Synchrony.Precision,
},
}
}
func ConsensusParamsFromProto(pbParams tmproto.ConsensusParams) ConsensusParams {
return ConsensusParams{
Block: BlockParams{
MaxBytes: pbParams.Block.MaxBytes,
MaxGas: pbParams.Block.MaxGas,
},
Evidence: EvidenceParams{
MaxAgeNumBlocks: pbParams.Evidence.MaxAgeNumBlocks,
MaxAgeDuration: pbParams.Evidence.MaxAgeDuration,
MaxBytes: pbParams.Evidence.MaxBytes,
},
Validator: ValidatorParams{
PubKeyTypes: pbParams.Validator.PubKeyTypes,
},
Version: VersionParams{
AppVersion: pbParams.Version.AppVersion,
},
Synchrony: SynchronyParams{
MessageDelay: pbParams.Synchrony.MessageDelay,
Precision: pbParams.Synchrony.Precision,
},
}
}