From 43313e9b85d8202bf6eabbe91bfc20e06bb61d8f Mon Sep 17 00:00:00 2001 From: William Banfield <4561443+williambanfield@users.noreply.github.com> Date: Mon, 23 May 2022 14:23:23 -0400 Subject: [PATCH] abci++: add proto fields for enabling vote extensions (#8587) This pull requests adds the protocol buffer field for the `ABCI.VoteExtensionsEnableHeight` parameter. This proto field is threaded throughout all of the relevant places where consensus params are used and referenced. This PR also adds validation of the consensus param updates. Previous consensus param changes didn't depend on _previous_ versions of the params, so this change adds a method for validating against the old params as well. closes: #8453 --- internal/state/execution.go | 9 +- internal/state/store.go | 20 -- proto/tendermint/blocksync/types.proto | 2 +- proto/tendermint/privval/service.proto | 2 +- proto/tendermint/types/params.pb.go | 415 ++++++++++++++++++++----- proto/tendermint/types/params.proto | 15 + test/e2e/generator/generate.go | 7 + test/e2e/pkg/manifest.go | 5 + test/e2e/pkg/testnet.go | 29 +- test/e2e/runner/evidence.go | 8 +- test/e2e/runner/setup.go | 1 + test/e2e/tests/app_test.go | 16 +- types/params.go | 37 +++ types/params_test.go | 116 ++++++- 14 files changed, 553 insertions(+), 129 deletions(-) diff --git a/internal/state/execution.go b/internal/state/execution.go index 47c2cb7ae..1d87104d4 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -534,7 +534,7 @@ func (state State) Update( if len(validatorUpdates) > 0 { err := nValSet.UpdateWithChangeSet(validatorUpdates) if err != nil { - return state, fmt.Errorf("error changing validator set: %w", err) + return state, fmt.Errorf("changing validator set: %w", err) } // Change results from this height but only applies to the next next height. lastHeightValsChanged = header.Height + 1 + 1 @@ -551,7 +551,12 @@ func (state State) Update( nextParams = state.ConsensusParams.UpdateConsensusParams(consensusParamUpdates) err := nextParams.ValidateConsensusParams() if err != nil { - return state, fmt.Errorf("error updating consensus params: %w", err) + return state, fmt.Errorf("updating consensus params: %w", err) + } + + err = state.ConsensusParams.ValidateUpdate(consensusParamUpdates, header.Height) + if err != nil { + return state, fmt.Errorf("updating consensus params: %w", err) } state.Version.Consensus.App = nextParams.Version.AppVersion diff --git a/internal/state/store.go b/internal/state/store.go index d592016f6..a41719c92 100644 --- a/internal/state/store.go +++ b/internal/state/store.go @@ -2,7 +2,6 @@ package state import ( "bytes" - "encoding/binary" "errors" "fmt" @@ -60,7 +59,6 @@ func abciResponsesKey(height int64) []byte { // stateKey should never change after being set in init() var stateKey []byte -var tmpABCIKey []byte func init() { var err error @@ -68,12 +66,6 @@ func init() { if err != nil { panic(err) } - // temporary extra key before consensus param protos are regenerated - // TODO(wbanfield) remove in next PR - tmpABCIKey, err = orderedcode.Append(nil, int64(10000)) - if err != nil { - panic(err) - } } //---------------------- @@ -145,13 +137,6 @@ func (store dbStore) loadState(key []byte) (state State, err error) { if err != nil { return state, err } - buf, err = store.db.Get(tmpABCIKey) - if err != nil { - return state, err - } - h, _ := binary.Varint(buf) - sm.ConsensusParams.ABCI.VoteExtensionsEnableHeight = h - return *sm, nil } @@ -195,11 +180,6 @@ func (store dbStore) save(state State, key []byte) error { if err := batch.Set(key, stateBz); err != nil { return err } - bz := make([]byte, 5) - binary.PutVarint(bz, state.ConsensusParams.ABCI.VoteExtensionsEnableHeight) - if err := batch.Set(tmpABCIKey, bz); err != nil { - return err - } return batch.WriteSync() } diff --git a/proto/tendermint/blocksync/types.proto b/proto/tendermint/blocksync/types.proto index 67da76dce..dca81db2b 100644 --- a/proto/tendermint/blocksync/types.proto +++ b/proto/tendermint/blocksync/types.proto @@ -19,7 +19,7 @@ message NoBlockResponse { // BlockResponse returns block to the requested message BlockResponse { - tendermint.types.Block block = 1; + tendermint.types.Block block = 1; tendermint.types.ExtendedCommit ext_commit = 2; } diff --git a/proto/tendermint/privval/service.proto b/proto/tendermint/privval/service.proto index 2c699e1cd..63e9afca7 100644 --- a/proto/tendermint/privval/service.proto +++ b/proto/tendermint/privval/service.proto @@ -1,6 +1,6 @@ syntax = "proto3"; package tendermint.privval; -option go_package = "github.com/tendermint/tendermint/proto/tendermint/privval"; +option go_package = "github.com/tendermint/tendermint/proto/tendermint/privval"; import "tendermint/privval/types.proto"; diff --git a/proto/tendermint/types/params.pb.go b/proto/tendermint/types/params.pb.go index 41d417b91..764d7b385 100644 --- a/proto/tendermint/types/params.pb.go +++ b/proto/tendermint/types/params.pb.go @@ -36,6 +36,7 @@ type ConsensusParams struct { Version *VersionParams `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` Synchrony *SynchronyParams `protobuf:"bytes,5,opt,name=synchrony,proto3" json:"synchrony,omitempty"` Timeout *TimeoutParams `protobuf:"bytes,6,opt,name=timeout,proto3" json:"timeout,omitempty"` + Abci *ABCIParams `protobuf:"bytes,7,opt,name=abci,proto3" json:"abci,omitempty"` } func (m *ConsensusParams) Reset() { *m = ConsensusParams{} } @@ -113,6 +114,13 @@ func (m *ConsensusParams) GetTimeout() *TimeoutParams { return nil } +func (m *ConsensusParams) GetAbci() *ABCIParams { + if m != nil { + return m.Abci + } + return nil +} + // BlockParams contains limits on the block size. type BlockParams struct { // Max block size, in bytes. @@ -566,6 +574,60 @@ func (m *TimeoutParams) GetBypassCommitTimeout() bool { return false } +// ABCIParams configure functionality specific to the Application Blockchain Interface. +type ABCIParams struct { + // vote_extensions_enable_height configures the first height during which + // vote extensions will be enabled. During this specified height, and for all + // subsequent heights, precommit messages that do not contain valid extension data + // will be considered invalid. Prior to this height, vote extensions will not + // be used or accepted by validators on the network. + // + // Once enabled, vote extensions will be created by the application in ExtendVote, + // passed to the application for validation in VerifyVoteExtension and given + // to the application to use when proposing a block during PrepareProposal. + VoteExtensionsEnableHeight int64 `protobuf:"varint,1,opt,name=vote_extensions_enable_height,json=voteExtensionsEnableHeight,proto3" json:"vote_extensions_enable_height,omitempty"` +} + +func (m *ABCIParams) Reset() { *m = ABCIParams{} } +func (m *ABCIParams) String() string { return proto.CompactTextString(m) } +func (*ABCIParams) ProtoMessage() {} +func (*ABCIParams) Descriptor() ([]byte, []int) { + return fileDescriptor_e12598271a686f57, []int{8} +} +func (m *ABCIParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ABCIParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ABCIParams.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ABCIParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_ABCIParams.Merge(m, src) +} +func (m *ABCIParams) XXX_Size() int { + return m.Size() +} +func (m *ABCIParams) XXX_DiscardUnknown() { + xxx_messageInfo_ABCIParams.DiscardUnknown(m) +} + +var xxx_messageInfo_ABCIParams proto.InternalMessageInfo + +func (m *ABCIParams) GetVoteExtensionsEnableHeight() int64 { + if m != nil { + return m.VoteExtensionsEnableHeight + } + return 0 +} + func init() { proto.RegisterType((*ConsensusParams)(nil), "tendermint.types.ConsensusParams") proto.RegisterType((*BlockParams)(nil), "tendermint.types.BlockParams") @@ -575,55 +637,60 @@ func init() { proto.RegisterType((*HashedParams)(nil), "tendermint.types.HashedParams") proto.RegisterType((*SynchronyParams)(nil), "tendermint.types.SynchronyParams") proto.RegisterType((*TimeoutParams)(nil), "tendermint.types.TimeoutParams") + proto.RegisterType((*ABCIParams)(nil), "tendermint.types.ABCIParams") } func init() { proto.RegisterFile("tendermint/types/params.proto", fileDescriptor_e12598271a686f57) } var fileDescriptor_e12598271a686f57 = []byte{ - // 680 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x94, 0xcf, 0x6e, 0xd3, 0x4a, - 0x14, 0xc6, 0xe3, 0x26, 0x4d, 0x93, 0x93, 0xa6, 0xa9, 0xe6, 0xde, 0xab, 0xeb, 0xdb, 0xab, 0x3a, - 0xc5, 0x0b, 0x54, 0x09, 0xc9, 0x41, 0xad, 0x50, 0x85, 0xc4, 0x1f, 0x91, 0x06, 0x81, 0x84, 0x8a, - 0x90, 0x29, 0x2c, 0xba, 0xb1, 0xc6, 0xc9, 0xe0, 0x5a, 0x8d, 0x3d, 0x96, 0xc7, 0x8e, 0xe2, 0xb7, - 0x60, 0x85, 0x78, 0x04, 0x78, 0x93, 0x2e, 0xbb, 0x64, 0x05, 0x28, 0x7d, 0x03, 0xd6, 0x2c, 0xd0, - 0xfc, 0x6b, 0x9a, 0x94, 0xd2, 0xac, 0xe2, 0xcc, 0xf9, 0x7e, 0xfe, 0x3c, 0xdf, 0x39, 0x33, 0xb0, - 0x99, 0x91, 0x78, 0x40, 0xd2, 0x28, 0x8c, 0xb3, 0x4e, 0x56, 0x24, 0x84, 0x75, 0x12, 0x9c, 0xe2, - 0x88, 0x39, 0x49, 0x4a, 0x33, 0x8a, 0xd6, 0xa7, 0x65, 0x47, 0x94, 0x37, 0xfe, 0x0e, 0x68, 0x40, - 0x45, 0xb1, 0xc3, 0x9f, 0xa4, 0x6e, 0xc3, 0x0a, 0x28, 0x0d, 0x86, 0xa4, 0x23, 0xfe, 0xf9, 0xf9, - 0xbb, 0xce, 0x20, 0x4f, 0x71, 0x16, 0xd2, 0x58, 0xd6, 0xed, 0x9f, 0x4b, 0xd0, 0xda, 0xa7, 0x31, - 0x23, 0x31, 0xcb, 0xd9, 0x2b, 0xe1, 0x80, 0x76, 0x61, 0xd9, 0x1f, 0xd2, 0xfe, 0x89, 0x69, 0x6c, - 0x19, 0xdb, 0x8d, 0x9d, 0x4d, 0x67, 0xde, 0xcb, 0xe9, 0xf2, 0xb2, 0x54, 0xbb, 0x52, 0x8b, 0x1e, - 0x40, 0x8d, 0x8c, 0xc2, 0x01, 0x89, 0xfb, 0xc4, 0x5c, 0x12, 0xdc, 0xd6, 0x55, 0xee, 0xa9, 0x52, - 0x28, 0xf4, 0x82, 0x40, 0x8f, 0xa1, 0x3e, 0xc2, 0xc3, 0x70, 0x80, 0x33, 0x9a, 0x9a, 0x65, 0x81, - 0xdf, 0xba, 0x8a, 0xbf, 0xd5, 0x12, 0xc5, 0x4f, 0x19, 0x74, 0x1f, 0x56, 0x46, 0x24, 0x65, 0x21, - 0x8d, 0xcd, 0x8a, 0xc0, 0xdb, 0xbf, 0xc1, 0xa5, 0x40, 0xc1, 0x5a, 0xcf, 0xbd, 0x59, 0x11, 0xf7, - 0x8f, 0x53, 0x1a, 0x17, 0xe6, 0xf2, 0x75, 0xde, 0xaf, 0xb5, 0x44, 0x7b, 0x5f, 0x30, 0xdc, 0x3b, - 0x0b, 0x23, 0x42, 0xf3, 0xcc, 0xac, 0x5e, 0xe7, 0x7d, 0x28, 0x05, 0xda, 0x5b, 0xe9, 0xed, 0x7d, - 0x68, 0x5c, 0xca, 0x12, 0xfd, 0x0f, 0xf5, 0x08, 0x8f, 0x3d, 0xbf, 0xc8, 0x08, 0x13, 0xe9, 0x97, - 0xdd, 0x5a, 0x84, 0xc7, 0x5d, 0xfe, 0x1f, 0xfd, 0x0b, 0x2b, 0xbc, 0x18, 0x60, 0x26, 0x02, 0x2e, - 0xbb, 0xd5, 0x08, 0x8f, 0x9f, 0x61, 0x66, 0x7f, 0x36, 0x60, 0x6d, 0x36, 0x59, 0x74, 0x07, 0x10, - 0xd7, 0xe2, 0x80, 0x78, 0x71, 0x1e, 0x79, 0xa2, 0x45, 0xfa, 0x8d, 0xad, 0x08, 0x8f, 0x9f, 0x04, - 0xe4, 0x65, 0x1e, 0x09, 0x6b, 0x86, 0x0e, 0x60, 0x5d, 0x8b, 0xf5, 0x74, 0xa8, 0x16, 0xfe, 0xe7, - 0xc8, 0xf1, 0x71, 0xf4, 0xf8, 0x38, 0x3d, 0x25, 0xe8, 0xd6, 0x4e, 0xbf, 0xb6, 0x4b, 0x1f, 0xbf, - 0xb5, 0x0d, 0x77, 0x4d, 0xbe, 0x4f, 0x57, 0x66, 0x37, 0x51, 0x9e, 0xdd, 0x84, 0x7d, 0x0f, 0x5a, - 0x73, 0x5d, 0x44, 0x36, 0x34, 0x93, 0xdc, 0xf7, 0x4e, 0x48, 0xe1, 0x89, 0xac, 0x4c, 0x63, 0xab, - 0xbc, 0x5d, 0x77, 0x1b, 0x49, 0xee, 0xbf, 0x20, 0xc5, 0x21, 0x5f, 0xb2, 0xef, 0x42, 0x73, 0xa6, - 0x7b, 0xa8, 0x0d, 0x0d, 0x9c, 0x24, 0x9e, 0xee, 0x39, 0xdf, 0x59, 0xc5, 0x05, 0x9c, 0x24, 0x4a, - 0x66, 0x1f, 0xc1, 0xea, 0x73, 0xcc, 0x8e, 0xc9, 0x40, 0x01, 0xb7, 0xa1, 0x25, 0x52, 0xf0, 0xe6, - 0x03, 0x6e, 0x8a, 0xe5, 0x03, 0x9d, 0xb2, 0x0d, 0xcd, 0xa9, 0x6e, 0x9a, 0x75, 0x43, 0xab, 0x78, - 0xe0, 0x1f, 0x0c, 0x68, 0xcd, 0xcd, 0x03, 0xea, 0x41, 0x33, 0x22, 0x8c, 0x89, 0x10, 0xc9, 0x10, - 0x17, 0xea, 0xf0, 0xfc, 0x21, 0xc1, 0x8a, 0x48, 0x6f, 0x55, 0x51, 0x3d, 0x0e, 0xa1, 0x87, 0x50, - 0x4f, 0x52, 0xd2, 0x0f, 0xd9, 0x42, 0x3d, 0x90, 0x6f, 0x98, 0x12, 0xf6, 0x8f, 0x25, 0x68, 0xce, - 0x4c, 0x1a, 0x9f, 0xcd, 0x24, 0xa5, 0x09, 0x65, 0x64, 0xd1, 0x0f, 0xd2, 0x7a, 0xbe, 0x23, 0xf5, - 0xc8, 0x77, 0x94, 0xe1, 0x45, 0xbf, 0x67, 0x55, 0x51, 0x3d, 0x0e, 0xa1, 0x5d, 0xa8, 0x8c, 0x68, - 0x46, 0xd4, 0xa1, 0xbe, 0x11, 0x16, 0x62, 0xf4, 0x08, 0x80, 0xff, 0x2a, 0xdf, 0xca, 0x82, 0x39, - 0x70, 0x44, 0x9a, 0xee, 0x41, 0xb5, 0x4f, 0xa3, 0x28, 0xcc, 0xd4, 0x79, 0xbe, 0x91, 0x55, 0x72, - 0xb4, 0x03, 0xff, 0xf8, 0x45, 0x82, 0x19, 0xf3, 0xe4, 0x82, 0x77, 0xf9, 0x60, 0xd7, 0xdc, 0xbf, - 0x64, 0x71, 0x5f, 0xd4, 0x54, 0xd0, 0xdd, 0x37, 0x9f, 0x26, 0x96, 0x71, 0x3a, 0xb1, 0x8c, 0xb3, - 0x89, 0x65, 0x7c, 0x9f, 0x58, 0xc6, 0xfb, 0x73, 0xab, 0x74, 0x76, 0x6e, 0x95, 0xbe, 0x9c, 0x5b, - 0xa5, 0xa3, 0xbd, 0x20, 0xcc, 0x8e, 0x73, 0xdf, 0xe9, 0xd3, 0xa8, 0x73, 0xf9, 0x4a, 0x9f, 0x3e, - 0xca, 0x3b, 0x7b, 0xfe, 0xba, 0xf7, 0xab, 0x62, 0x7d, 0xf7, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xfc, 0x06, 0xae, 0x9f, 0x09, 0x06, 0x00, 0x00, + // 741 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x95, 0xcd, 0x6e, 0xd3, 0x4a, + 0x14, 0x80, 0xe3, 0x26, 0x4d, 0x93, 0x93, 0xa6, 0xa9, 0xe6, 0xde, 0xab, 0x6b, 0x0a, 0x75, 0x8a, + 0x17, 0xa8, 0x12, 0x92, 0x53, 0xb5, 0x42, 0x15, 0x12, 0x3f, 0x6a, 0x92, 0x8a, 0x22, 0x54, 0x40, + 0xa1, 0xb0, 0xe8, 0xc6, 0x1a, 0x27, 0x83, 0x63, 0x35, 0xf6, 0x58, 0x9e, 0x71, 0x14, 0xbf, 0x05, + 0x2b, 0xc4, 0x23, 0xc0, 0x86, 0xe7, 0xe8, 0xb2, 0x4b, 0x56, 0x80, 0xd2, 0x37, 0xe0, 0x09, 0xd0, + 0x8c, 0xc7, 0x4d, 0x93, 0x52, 0x9a, 0x55, 0x9c, 0x39, 0xdf, 0xe7, 0xe3, 0x39, 0xe7, 0xd8, 0x03, + 0xeb, 0x9c, 0x04, 0x3d, 0x12, 0xf9, 0x5e, 0xc0, 0x1b, 0x3c, 0x09, 0x09, 0x6b, 0x84, 0x38, 0xc2, + 0x3e, 0xb3, 0xc2, 0x88, 0x72, 0x8a, 0x56, 0x27, 0x61, 0x4b, 0x86, 0xd7, 0xfe, 0x75, 0xa9, 0x4b, + 0x65, 0xb0, 0x21, 0xae, 0x52, 0x6e, 0xcd, 0x70, 0x29, 0x75, 0x07, 0xa4, 0x21, 0xff, 0x39, 0xf1, + 0xfb, 0x46, 0x2f, 0x8e, 0x30, 0xf7, 0x68, 0x90, 0xc6, 0xcd, 0xaf, 0x79, 0xa8, 0xb5, 0x68, 0xc0, + 0x48, 0xc0, 0x62, 0xf6, 0x5a, 0x66, 0x40, 0x3b, 0xb0, 0xe8, 0x0c, 0x68, 0xf7, 0x44, 0xd7, 0x36, + 0xb4, 0xcd, 0xca, 0xf6, 0xba, 0x35, 0x9b, 0xcb, 0x6a, 0x8a, 0x70, 0x4a, 0x77, 0x52, 0x16, 0x3d, + 0x82, 0x12, 0x19, 0x7a, 0x3d, 0x12, 0x74, 0x89, 0xbe, 0x20, 0xbd, 0x8d, 0xab, 0xde, 0xbe, 0x22, + 0x94, 0x7a, 0x61, 0xa0, 0xa7, 0x50, 0x1e, 0xe2, 0x81, 0xd7, 0xc3, 0x9c, 0x46, 0x7a, 0x5e, 0xea, + 0x77, 0xaf, 0xea, 0xef, 0x32, 0x44, 0xf9, 0x13, 0x07, 0x3d, 0x84, 0xa5, 0x21, 0x89, 0x98, 0x47, + 0x03, 0xbd, 0x20, 0xf5, 0xfa, 0x1f, 0xf4, 0x14, 0x50, 0x72, 0xc6, 0x8b, 0xdc, 0x2c, 0x09, 0xba, + 0xfd, 0x88, 0x06, 0x89, 0xbe, 0x78, 0x5d, 0xee, 0x37, 0x19, 0x92, 0xe5, 0xbe, 0x70, 0x44, 0x6e, + 0xee, 0xf9, 0x84, 0xc6, 0x5c, 0x2f, 0x5e, 0x97, 0xfb, 0x28, 0x05, 0xb2, 0xdc, 0x8a, 0x47, 0x5b, + 0x50, 0xc0, 0x4e, 0xd7, 0xd3, 0x97, 0xa4, 0x77, 0xe7, 0xaa, 0xb7, 0xd7, 0x6c, 0x3d, 0x57, 0x92, + 0x24, 0xcd, 0x16, 0x54, 0x2e, 0x55, 0x1f, 0xdd, 0x86, 0xb2, 0x8f, 0x47, 0xb6, 0x93, 0x70, 0xc2, + 0x64, 0xbf, 0xf2, 0x9d, 0x92, 0x8f, 0x47, 0x4d, 0xf1, 0x1f, 0xfd, 0x0f, 0x4b, 0x22, 0xe8, 0x62, + 0x26, 0x5b, 0x92, 0xef, 0x14, 0x7d, 0x3c, 0x7a, 0x86, 0x99, 0xf9, 0x45, 0x83, 0x95, 0xe9, 0x5e, + 0xa0, 0xfb, 0x80, 0x04, 0x8b, 0x5d, 0x62, 0x07, 0xb1, 0x6f, 0xcb, 0xa6, 0x66, 0x77, 0xac, 0xf9, + 0x78, 0xb4, 0xe7, 0x92, 0x97, 0xb1, 0x2f, 0x53, 0x33, 0x74, 0x08, 0xab, 0x19, 0x9c, 0xcd, 0x93, + 0x6a, 0xfa, 0x2d, 0x2b, 0x1d, 0x38, 0x2b, 0x1b, 0x38, 0xab, 0xad, 0x80, 0x66, 0xe9, 0xf4, 0x7b, + 0x3d, 0xf7, 0xe9, 0x47, 0x5d, 0xeb, 0xac, 0xa4, 0xf7, 0xcb, 0x22, 0xd3, 0x9b, 0xc8, 0x4f, 0x6f, + 0xc2, 0x7c, 0x00, 0xb5, 0x99, 0xbe, 0x23, 0x13, 0xaa, 0x61, 0xec, 0xd8, 0x27, 0x24, 0xb1, 0x65, + 0x95, 0x74, 0x6d, 0x23, 0xbf, 0x59, 0xee, 0x54, 0xc2, 0xd8, 0x79, 0x41, 0x92, 0x23, 0xb1, 0x64, + 0x6e, 0x41, 0x75, 0xaa, 0xdf, 0xa8, 0x0e, 0x15, 0x1c, 0x86, 0x76, 0x36, 0x25, 0x62, 0x67, 0x85, + 0x0e, 0xe0, 0x30, 0x54, 0x98, 0x79, 0x0c, 0xcb, 0x07, 0x98, 0xf5, 0x49, 0x4f, 0x09, 0xf7, 0xa0, + 0x26, 0xab, 0x60, 0xcf, 0x16, 0xb8, 0x2a, 0x97, 0x0f, 0xb3, 0x2a, 0x9b, 0x50, 0x9d, 0x70, 0x93, + 0x5a, 0x57, 0x32, 0x4a, 0x14, 0xfc, 0xa3, 0x06, 0xb5, 0x99, 0x09, 0x42, 0x6d, 0xa8, 0xfa, 0x84, + 0x31, 0x59, 0x44, 0x32, 0xc0, 0x89, 0x7a, 0xdd, 0xfe, 0x52, 0xc1, 0x82, 0xac, 0xde, 0xb2, 0xb2, + 0xda, 0x42, 0x42, 0x8f, 0xa1, 0x1c, 0x46, 0xa4, 0xeb, 0xb1, 0xb9, 0x7a, 0x90, 0xde, 0x61, 0x62, + 0x98, 0xbf, 0x16, 0xa0, 0x3a, 0x35, 0x9b, 0x62, 0x9a, 0xc3, 0x88, 0x86, 0x94, 0x91, 0x79, 0x1f, + 0x28, 0xe3, 0xc5, 0x8e, 0xd4, 0xa5, 0xd8, 0x11, 0xc7, 0xf3, 0x3e, 0xcf, 0xb2, 0xb2, 0xda, 0x42, + 0x42, 0x3b, 0x50, 0x18, 0x52, 0x4e, 0xd4, 0x67, 0xe0, 0x46, 0x59, 0xc2, 0xe8, 0x09, 0x80, 0xf8, + 0x55, 0x79, 0x0b, 0x73, 0xd6, 0x41, 0x28, 0x69, 0xd2, 0x5d, 0x28, 0x76, 0xa9, 0xef, 0x7b, 0x5c, + 0x7d, 0x01, 0x6e, 0x74, 0x15, 0x8e, 0xb6, 0xe1, 0x3f, 0x27, 0x09, 0x31, 0x63, 0x76, 0xba, 0x60, + 0x5f, 0xfe, 0x14, 0x94, 0x3a, 0xff, 0xa4, 0xc1, 0x96, 0x8c, 0xa9, 0x42, 0x9b, 0xaf, 0x00, 0x26, + 0xef, 0x35, 0xda, 0x83, 0x75, 0xf9, 0xe8, 0x64, 0xc4, 0x49, 0x20, 0x9a, 0xc2, 0x6c, 0x12, 0x60, + 0x67, 0x40, 0xec, 0x3e, 0xf1, 0xdc, 0x3e, 0x57, 0x53, 0xb7, 0x26, 0xa0, 0xfd, 0x0b, 0x66, 0x5f, + 0x22, 0x07, 0x92, 0x68, 0xbe, 0xfd, 0x3c, 0x36, 0xb4, 0xd3, 0xb1, 0xa1, 0x9d, 0x8d, 0x0d, 0xed, + 0xe7, 0xd8, 0xd0, 0x3e, 0x9c, 0x1b, 0xb9, 0xb3, 0x73, 0x23, 0xf7, 0xed, 0xdc, 0xc8, 0x1d, 0xef, + 0xba, 0x1e, 0xef, 0xc7, 0x8e, 0xd5, 0xa5, 0x7e, 0xe3, 0xf2, 0xa9, 0x32, 0xb9, 0x4c, 0x8f, 0x8d, + 0xd9, 0x13, 0xc7, 0x29, 0xca, 0xf5, 0x9d, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x28, 0x35, 0x60, + 0x76, 0x8c, 0x06, 0x00, 0x00, } func (this *ConsensusParams) Equal(that interface{}) bool { @@ -663,6 +730,9 @@ func (this *ConsensusParams) Equal(that interface{}) bool { if !this.Timeout.Equal(that1.Timeout) { return false } + if !this.Abci.Equal(that1.Abci) { + return false + } return true } func (this *BlockParams) Equal(that interface{}) bool { @@ -910,6 +980,30 @@ func (this *TimeoutParams) Equal(that interface{}) bool { } return true } +func (this *ABCIParams) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ABCIParams) + if !ok { + that2, ok := that.(ABCIParams) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.VoteExtensionsEnableHeight != that1.VoteExtensionsEnableHeight { + return false + } + return true +} func (m *ConsensusParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -930,6 +1024,18 @@ func (m *ConsensusParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Abci != nil { + { + size, err := m.Abci.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.Timeout != nil { { size, err := m.Timeout.MarshalToSizedBuffer(dAtA[:i]) @@ -1063,12 +1169,12 @@ func (m *EvidenceParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x18 } - n7, err7 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.MaxAgeDuration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxAgeDuration):]) - if err7 != nil { - return 0, err7 + n8, err8 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.MaxAgeDuration, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxAgeDuration):]) + if err8 != nil { + return 0, err8 } - i -= n7 - i = encodeVarintParams(dAtA, i, uint64(n7)) + i -= n8 + i = encodeVarintParams(dAtA, i, uint64(n8)) i-- dAtA[i] = 0x12 if m.MaxAgeNumBlocks != 0 { @@ -1193,23 +1299,23 @@ func (m *SynchronyParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l if m.Precision != nil { - n8, err8 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Precision, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Precision):]) - if err8 != nil { - return 0, err8 - } - i -= n8 - i = encodeVarintParams(dAtA, i, uint64(n8)) - i-- - dAtA[i] = 0x12 - } - if m.MessageDelay != nil { - n9, err9 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.MessageDelay, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.MessageDelay):]) + n9, err9 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Precision, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Precision):]) if err9 != nil { return 0, err9 } i -= n9 i = encodeVarintParams(dAtA, i, uint64(n9)) i-- + dAtA[i] = 0x12 + } + if m.MessageDelay != nil { + n10, err10 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.MessageDelay, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.MessageDelay):]) + if err10 != nil { + return 0, err10 + } + i -= n10 + i = encodeVarintParams(dAtA, i, uint64(n10)) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil @@ -1246,58 +1352,86 @@ func (m *TimeoutParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x30 } if m.Commit != nil { - n10, err10 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Commit, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Commit):]) - if err10 != nil { - return 0, err10 - } - i -= n10 - i = encodeVarintParams(dAtA, i, uint64(n10)) - i-- - dAtA[i] = 0x2a - } - if m.VoteDelta != nil { - n11, err11 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.VoteDelta, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.VoteDelta):]) + n11, err11 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Commit, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Commit):]) if err11 != nil { return 0, err11 } i -= n11 i = encodeVarintParams(dAtA, i, uint64(n11)) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x2a } - if m.Vote != nil { - n12, err12 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Vote, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Vote):]) + if m.VoteDelta != nil { + n12, err12 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.VoteDelta, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.VoteDelta):]) if err12 != nil { return 0, err12 } i -= n12 i = encodeVarintParams(dAtA, i, uint64(n12)) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 } - if m.ProposeDelta != nil { - n13, err13 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.ProposeDelta, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.ProposeDelta):]) + if m.Vote != nil { + n13, err13 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Vote, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Vote):]) if err13 != nil { return 0, err13 } i -= n13 i = encodeVarintParams(dAtA, i, uint64(n13)) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a } - if m.Propose != nil { - n14, err14 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Propose, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Propose):]) + if m.ProposeDelta != nil { + n14, err14 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.ProposeDelta, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.ProposeDelta):]) if err14 != nil { return 0, err14 } i -= n14 i = encodeVarintParams(dAtA, i, uint64(n14)) i-- + dAtA[i] = 0x12 + } + if m.Propose != nil { + n15, err15 := github_com_gogo_protobuf_types.StdDurationMarshalTo(*m.Propose, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(*m.Propose):]) + if err15 != nil { + return 0, err15 + } + i -= n15 + i = encodeVarintParams(dAtA, i, uint64(n15)) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } +func (m *ABCIParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ABCIParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ABCIParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.VoteExtensionsEnableHeight != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.VoteExtensionsEnableHeight)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintParams(dAtA []byte, offset int, v uint64) int { offset -= sovParams(v) base := offset @@ -1339,6 +1473,10 @@ func (m *ConsensusParams) Size() (n int) { l = m.Timeout.Size() n += 1 + l + sovParams(uint64(l)) } + if m.Abci != nil { + l = m.Abci.Size() + n += 1 + l + sovParams(uint64(l)) + } return n } @@ -1465,6 +1603,18 @@ func (m *TimeoutParams) Size() (n int) { return n } +func (m *ABCIParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.VoteExtensionsEnableHeight != 0 { + n += 1 + sovParams(uint64(m.VoteExtensionsEnableHeight)) + } + return n +} + func sovParams(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1716,6 +1866,42 @@ func (m *ConsensusParams) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Abci", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Abci == nil { + m.Abci = &ABCIParams{} + } + if err := m.Abci.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) @@ -2557,6 +2743,75 @@ func (m *TimeoutParams) Unmarshal(dAtA []byte) error { } return nil } +func (m *ABCIParams) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ABCIParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ABCIParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VoteExtensionsEnableHeight", wireType) + } + m.VoteExtensionsEnableHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VoteExtensionsEnableHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipParams(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/proto/tendermint/types/params.proto b/proto/tendermint/types/params.proto index 466ba464f..21bbd037d 100644 --- a/proto/tendermint/types/params.proto +++ b/proto/tendermint/types/params.proto @@ -17,6 +17,7 @@ message ConsensusParams { VersionParams version = 4; SynchronyParams synchrony = 5; TimeoutParams timeout = 6; + ABCIParams abci = 7; } // BlockParams contains limits on the block size. @@ -127,3 +128,17 @@ message TimeoutParams { // for the full commit timeout. bool bypass_commit_timeout = 6; } + +// ABCIParams configure functionality specific to the Application Blockchain Interface. +message ABCIParams { + // vote_extensions_enable_height configures the first height during which + // vote extensions will be enabled. During this specified height, and for all + // subsequent heights, precommit messages that do not contain valid extension data + // will be considered invalid. Prior to this height, vote extensions will not + // be used or accepted by validators on the network. + // + // Once enabled, vote extensions will be created by the application in ExtendVote, + // passed to the application for validation in VerifyVoteExtension and given + // to the application to use when proposing a block during PrepareProposal. + int64 vote_extensions_enable_height = 1; +} diff --git a/test/e2e/generator/generate.go b/test/e2e/generator/generate.go index 90c19e6ff..5f917d746 100644 --- a/test/e2e/generator/generate.go +++ b/test/e2e/generator/generate.go @@ -66,6 +66,9 @@ var ( txSize = uniformChoice{1024, 4096} // either 1kb or 4kb ipv6 = uniformChoice{false, true} keyType = uniformChoice{types.ABCIPubKeyTypeEd25519, types.ABCIPubKeyTypeSecp256k1} + + voteExtensionEnableHeightOffset = uniformChoice{int64(0), int64(10), int64(100)} + voteExtensionEnabled = uniformChoice{true, false} ) // Generate generates random testnets using the given RNG. @@ -116,6 +119,10 @@ func generateTestnet(r *rand.Rand, opt map[string]interface{}) (e2e.Manifest, er TxSize: txSize.Choose(r).(int), } + if voteExtensionEnabled.Choose(r).(bool) { + manifest.VoteExtensionsEnableHeight = manifest.InitialHeight + voteExtensionEnableHeightOffset.Choose(r).(int64) + } + var numSeeds, numValidators, numFulls, numLightClients int switch opt["topology"].(string) { case "single": diff --git a/test/e2e/pkg/manifest.go b/test/e2e/pkg/manifest.go index 895e62939..dd2ad02ba 100644 --- a/test/e2e/pkg/manifest.go +++ b/test/e2e/pkg/manifest.go @@ -66,6 +66,11 @@ type Manifest struct { // Number of bytes per tx. Default is 1kb (1024) TxSize int + // VoteExtensionsEnableHeight configures the first height during which + // the chain will use and require vote extension data to be present + // in precommit messages. + VoteExtensionsEnableHeight int64 `toml:"vote_extensions_enable_height"` + // ABCIProtocol specifies the protocol used to communicate with the ABCI // application: "unix", "tcp", "grpc", or "builtin". Defaults to builtin. // builtin will build a complete Tendermint node into the application and diff --git a/test/e2e/pkg/testnet.go b/test/e2e/pkg/testnet.go index f4b75c71a..ad79c99c6 100644 --- a/test/e2e/pkg/testnet.go +++ b/test/e2e/pkg/testnet.go @@ -58,20 +58,21 @@ const ( // Testnet represents a single testnet. type Testnet struct { - Name string - File string - Dir string - IP *net.IPNet - InitialHeight int64 - InitialState map[string]string - Validators map[*Node]int64 - ValidatorUpdates map[int64]map[*Node]int64 - Nodes []*Node - KeyType string - Evidence int - LogLevel string - TxSize int - ABCIProtocol string + Name string + File string + Dir string + IP *net.IPNet + InitialHeight int64 + InitialState map[string]string + Validators map[*Node]int64 + ValidatorUpdates map[int64]map[*Node]int64 + Nodes []*Node + KeyType string + Evidence int + VoteExtensionsEnableHeight int64 + LogLevel string + TxSize int + ABCIProtocol string } // Node represents a Tendermint node in a testnet. diff --git a/test/e2e/runner/evidence.go b/test/e2e/runner/evidence.go index fab1d7b20..9050c52bd 100644 --- a/test/e2e/runner/evidence.go +++ b/test/e2e/runner/evidence.go @@ -86,9 +86,15 @@ func InjectEvidence(ctx context.Context, logger log.Logger, r *rand.Rand, testne privVals, evidenceHeight, valSet, testnet.Name, blockRes.Block.Time, ) } else { - ev, err = generateDuplicateVoteEvidence(ctx, + var dve *types.DuplicateVoteEvidence + dve, err = generateDuplicateVoteEvidence(ctx, privVals, evidenceHeight, valSet, testnet.Name, blockRes.Block.Time, ) + if dve.VoteA.Height < testnet.VoteExtensionsEnableHeight { + dve.VoteA.StripExtension() + dve.VoteB.StripExtension() + } + ev = dve } if err != nil { return err diff --git a/test/e2e/runner/setup.go b/test/e2e/runner/setup.go index 507dc2d04..5f78a5b35 100644 --- a/test/e2e/runner/setup.go +++ b/test/e2e/runner/setup.go @@ -209,6 +209,7 @@ func MakeGenesis(testnet *e2e.Testnet) (types.GenesisDoc, error) { } genesis.ConsensusParams.Evidence.MaxAgeNumBlocks = e2e.EvidenceAgeHeight genesis.ConsensusParams.Evidence.MaxAgeDuration = e2e.EvidenceAgeTime + genesis.ConsensusParams.ABCI.VoteExtensionsEnableHeight = testnet.VoteExtensionsEnableHeight for validator, power := range testnet.Validators { genesis.Validators = append(genesis.Validators, types.GenesisValidator{ Name: validator.Name, diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index 20a153c1d..6b378225a 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -3,6 +3,7 @@ package e2e_test import ( "bytes" "context" + "errors" "fmt" "math/rand" "strconv" @@ -190,16 +191,25 @@ func TestApp_Tx(t *testing.T) { func TestApp_VoteExtensions(t *testing.T) { testNode(t, func(ctx context.Context, t *testing.T, node e2e.Node) { - t.Skip() client, err := node.Client() require.NoError(t, err) + info, err := client.ABCIInfo(ctx) + require.NoError(t, err) // This special value should have been created by way of vote extensions resp, err := client.ABCIQuery(ctx, "", []byte("extensionSum")) require.NoError(t, err) extSum, err := strconv.Atoi(string(resp.Response.Value)) - require.NoError(t, err) - require.GreaterOrEqual(t, extSum, 0) + // if extensions are not enabled on the network, we should not expect + // the app to have any extension value set. + if node.Testnet.VoteExtensionsEnableHeight == 0 || + info.Response.LastBlockHeight < node.Testnet.VoteExtensionsEnableHeight+1 { + target := &strconv.NumError{} + require.True(t, errors.As(err, &target)) + } else { + require.NoError(t, err) + require.GreaterOrEqual(t, extSum, 0) + } }) } diff --git a/types/params.go b/types/params.go index 3b5e9a250..a2651b186 100644 --- a/types/params.go +++ b/types/params.go @@ -330,6 +330,9 @@ func (params ConsensusParams) ValidateConsensusParams() error { if params.Timeout.Commit <= 0 { return fmt.Errorf("timeout.Commit must be greater than 0. Got: %d", params.Timeout.Commit) } + if params.ABCI.VoteExtensionsEnableHeight < 0 { + return fmt.Errorf("ABCI.VoteExtensionsEnableHeight cannot be negative. Got: %d", params.ABCI.VoteExtensionsEnableHeight) + } if len(params.Validator.PubKeyTypes) == 0 { return errors.New("len(Validator.PubKeyTypes) must be greater than 0") @@ -347,6 +350,30 @@ func (params ConsensusParams) ValidateConsensusParams() error { return nil } +func (params ConsensusParams) ValidateUpdate(updated *tmproto.ConsensusParams, h int64) error { + if updated.Abci == nil { + return nil + } + if params.ABCI.VoteExtensionsEnableHeight == updated.Abci.VoteExtensionsEnableHeight { + return nil + } + if params.ABCI.VoteExtensionsEnableHeight != 0 && updated.Abci.VoteExtensionsEnableHeight == 0 { + return errors.New("vote extensions cannot be disabled once enabled") + } + if updated.Abci.VoteExtensionsEnableHeight <= h { + return fmt.Errorf("VoteExtensionsEnableHeight cannot be updated to a past height, "+ + "initial height: %d, current height %d", + params.ABCI.VoteExtensionsEnableHeight, h) + } + if params.ABCI.VoteExtensionsEnableHeight <= h { + return fmt.Errorf("VoteExtensionsEnableHeight cannot be updated modified once"+ + "the initial height has occurred, "+ + "initial height: %d, current height %d", + params.ABCI.VoteExtensionsEnableHeight, h) + } + 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 @@ -373,6 +400,7 @@ func (params *ConsensusParams) Equals(params2 *ConsensusParams) bool { params.Version == params2.Version && params.Synchrony == params2.Synchrony && params.Timeout == params2.Timeout && + params.ABCI == params2.ABCI && tmstrings.StringSliceEqual(params.Validator.PubKeyTypes, params2.Validator.PubKeyTypes) } @@ -429,6 +457,9 @@ func (params ConsensusParams) UpdateConsensusParams(params2 *tmproto.ConsensusPa } res.Timeout.BypassCommitTimeout = params2.Timeout.GetBypassCommitTimeout() } + if params2.Abci != nil { + res.ABCI.VoteExtensionsEnableHeight = params2.Abci.GetVoteExtensionsEnableHeight() + } return res } @@ -461,6 +492,9 @@ func (params *ConsensusParams) ToProto() tmproto.ConsensusParams { Commit: ¶ms.Timeout.Commit, BypassCommitTimeout: params.Timeout.BypassCommitTimeout, }, + Abci: &tmproto.ABCIParams{ + VoteExtensionsEnableHeight: params.ABCI.VoteExtensionsEnableHeight, + }, } } @@ -508,5 +542,8 @@ func ConsensusParamsFromProto(pbParams tmproto.ConsensusParams) ConsensusParams } c.Timeout.BypassCommitTimeout = pbParams.Timeout.BypassCommitTimeout } + if pbParams.Abci != nil { + c.ABCI.VoteExtensionsEnableHeight = pbParams.Abci.GetVoteExtensionsEnableHeight() + } return c } diff --git a/types/params_test.go b/types/params_test.go index f19ed001b..e434e9534 100644 --- a/types/params_test.go +++ b/types/params_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -189,6 +190,8 @@ type makeParamsArgs struct { vote *time.Duration voteDelta *time.Duration commit *time.Duration + + abciExtensionHeight int64 } func makeParams(args makeParamsArgs) ConsensusParams { @@ -235,6 +238,9 @@ func makeParams(args makeParamsArgs) ConsensusParams { Commit: *args.commit, BypassCommitTimeout: args.bypassCommitTimeout, }, + ABCI: ABCIParams{ + VoteExtensionsEnableHeight: args.abciExtensionHeight, + }, } } @@ -267,19 +273,19 @@ func TestConsensusParamsHash(t *testing.T) { func TestConsensusParamsUpdate(t *testing.T) { testCases := []struct { - intialParams ConsensusParams + initialParams ConsensusParams updates *tmproto.ConsensusParams updatedParams ConsensusParams }{ // empty updates { - intialParams: makeParams(makeParamsArgs{blockBytes: 1, blockGas: 2, evidenceAge: 3}), + initialParams: makeParams(makeParamsArgs{blockBytes: 1, blockGas: 2, evidenceAge: 3}), updates: &tmproto.ConsensusParams{}, updatedParams: makeParams(makeParamsArgs{blockBytes: 1, blockGas: 2, evidenceAge: 3}), }, { // update synchrony params - intialParams: makeParams(makeParamsArgs{evidenceAge: 3, precision: time.Second, messageDelay: 3 * time.Second}), + initialParams: makeParams(makeParamsArgs{evidenceAge: 3, precision: time.Second, messageDelay: 3 * time.Second}), updates: &tmproto.ConsensusParams{ Synchrony: &tmproto.SynchronyParams{ Precision: durationPtr(time.Second * 2), @@ -290,7 +296,21 @@ func TestConsensusParamsUpdate(t *testing.T) { }, { // update timeout params - intialParams: makeParams(makeParamsArgs{ + initialParams: makeParams(makeParamsArgs{ + abciExtensionHeight: 1, + }), + updates: &tmproto.ConsensusParams{ + Abci: &tmproto.ABCIParams{ + VoteExtensionsEnableHeight: 10, + }, + }, + updatedParams: makeParams(makeParamsArgs{ + abciExtensionHeight: 10, + }), + }, + { + // update timeout params + initialParams: makeParams(makeParamsArgs{ propose: durationPtr(3 * time.Second), proposeDelta: durationPtr(500 * time.Millisecond), vote: durationPtr(time.Second), @@ -319,7 +339,7 @@ func TestConsensusParamsUpdate(t *testing.T) { }, // fine updates { - intialParams: makeParams(makeParamsArgs{blockBytes: 1, blockGas: 2, evidenceAge: 3}), + initialParams: makeParams(makeParamsArgs{blockBytes: 1, blockGas: 2, evidenceAge: 3}), updates: &tmproto.ConsensusParams{ Block: &tmproto.BlockParams{ MaxBytes: 100, @@ -341,7 +361,7 @@ func TestConsensusParamsUpdate(t *testing.T) { pubkeyTypes: valSecp256k1}), }, { - intialParams: makeParams(makeParamsArgs{blockBytes: 1, blockGas: 2, evidenceAge: 3}), + initialParams: makeParams(makeParamsArgs{blockBytes: 1, blockGas: 2, evidenceAge: 3}), updates: &tmproto.ConsensusParams{ Block: &tmproto.BlockParams{ MaxBytes: 100, @@ -366,7 +386,7 @@ func TestConsensusParamsUpdate(t *testing.T) { } for _, tc := range testCases { - assert.Equal(t, tc.updatedParams, tc.intialParams.UpdateConsensusParams(tc.updates)) + assert.Equal(t, tc.updatedParams, tc.initialParams.UpdateConsensusParams(tc.updates)) } } @@ -381,6 +401,78 @@ func TestConsensusParamsUpdate_AppVersion(t *testing.T) { assert.EqualValues(t, 1, updated.Version.AppVersion) } +func TestConsensusParamsUpdate_VoteExtensionsEnableHeight(t *testing.T) { + t.Run("set to height but initial height already run", func(*testing.T) { + initialParams := makeParams(makeParamsArgs{ + abciExtensionHeight: 1, + }) + update := &tmproto.ConsensusParams{ + Abci: &tmproto.ABCIParams{ + VoteExtensionsEnableHeight: 10, + }, + } + require.Error(t, initialParams.ValidateUpdate(update, 1)) + require.Error(t, initialParams.ValidateUpdate(update, 5)) + }) + t.Run("reset to 0", func(t *testing.T) { + initialParams := makeParams(makeParamsArgs{ + abciExtensionHeight: 1, + }) + update := &tmproto.ConsensusParams{ + Abci: &tmproto.ABCIParams{ + VoteExtensionsEnableHeight: 0, + }, + } + require.Error(t, initialParams.ValidateUpdate(update, 1)) + }) + t.Run("set to height before current height run", func(*testing.T) { + initialParams := makeParams(makeParamsArgs{ + abciExtensionHeight: 100, + }) + update := &tmproto.ConsensusParams{ + Abci: &tmproto.ABCIParams{ + VoteExtensionsEnableHeight: 10, + }, + } + require.Error(t, initialParams.ValidateUpdate(update, 11)) + require.Error(t, initialParams.ValidateUpdate(update, 99)) + }) + t.Run("set to height after current height run", func(*testing.T) { + initialParams := makeParams(makeParamsArgs{ + abciExtensionHeight: 300, + }) + update := &tmproto.ConsensusParams{ + Abci: &tmproto.ABCIParams{ + VoteExtensionsEnableHeight: 99, + }, + } + require.NoError(t, initialParams.ValidateUpdate(update, 11)) + require.NoError(t, initialParams.ValidateUpdate(update, 98)) + }) + t.Run("no error when unchanged", func(*testing.T) { + initialParams := makeParams(makeParamsArgs{ + abciExtensionHeight: 100, + }) + update := &tmproto.ConsensusParams{ + Abci: &tmproto.ABCIParams{ + VoteExtensionsEnableHeight: 100, + }, + } + require.NoError(t, initialParams.ValidateUpdate(update, 500)) + }) + t.Run("updated from 0 to 0", func(t *testing.T) { + initialParams := makeParams(makeParamsArgs{ + abciExtensionHeight: 0, + }) + update := &tmproto.ConsensusParams{ + Abci: &tmproto.ABCIParams{ + VoteExtensionsEnableHeight: 0, + }, + } + require.NoError(t, initialParams.ValidateUpdate(update, 100)) + }) +} + func TestProto(t *testing.T) { params := []ConsensusParams{ makeParams(makeParamsArgs{blockBytes: 4, blockGas: 2, evidenceAge: 3, maxEvidenceBytes: 1}), @@ -393,6 +485,16 @@ func TestProto(t *testing.T) { makeParams(makeParamsArgs{blockBytes: 4, blockGas: 6, evidenceAge: 5, maxEvidenceBytes: 1}), makeParams(makeParamsArgs{precision: time.Second, messageDelay: time.Minute}), makeParams(makeParamsArgs{precision: time.Nanosecond, messageDelay: time.Millisecond}), + makeParams(makeParamsArgs{abciExtensionHeight: 100}), + makeParams(makeParamsArgs{abciExtensionHeight: 100}), + makeParams(makeParamsArgs{ + propose: durationPtr(2 * time.Second), + proposeDelta: durationPtr(400 * time.Millisecond), + vote: durationPtr(5 * time.Second), + voteDelta: durationPtr(400 * time.Millisecond), + commit: durationPtr(time.Minute), + bypassCommitTimeout: true, + }), } for i := range params {