mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-25 16:46:42 +00:00
implement vote extensions
This commit is contained in:
+31
-39
@@ -15,6 +15,7 @@ import (
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
abcicli "github.com/tendermint/tendermint/abci/client"
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/evidence"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -23,7 +24,7 @@ import (
|
||||
mempl "github.com/tendermint/tendermint/mempool"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/config"
|
||||
mempoolv0 "github.com/tendermint/tendermint/mempool/v0"
|
||||
mempoolv1 "github.com/tendermint/tendermint/mempool/v1"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
@@ -42,10 +43,8 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
const byzantineNode = 0
|
||||
const prevoteHeight = int64(2)
|
||||
testName := "consensus_byzantine_test"
|
||||
tickerFunc := newMockTickerFunc(true)
|
||||
appFunc := newKVStore
|
||||
|
||||
genDoc, privVals := randGenesisDoc(nValidators, false, 30)
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{validators: nValidators})
|
||||
css := make([]*State, nValidators)
|
||||
|
||||
for i := 0; i < nValidators; i++ {
|
||||
@@ -54,11 +53,10 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardFinalizeBlockResponses: false,
|
||||
})
|
||||
state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
|
||||
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
|
||||
defer os.RemoveAll(thisConfig.RootDir)
|
||||
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
|
||||
app := appFunc()
|
||||
cfg := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
|
||||
defer os.RemoveAll(cfg.RootDir)
|
||||
ensureDir(path.Dir(cfg.Consensus.WalFile()), 0700) // dir for wal
|
||||
app := kvstore.NewInMemoryApplication()
|
||||
vals := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
_, err := app.InitChain(context.Background(), &abci.RequestInitChain{Validators: vals})
|
||||
require.NoError(t, err)
|
||||
@@ -74,16 +72,16 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
// Make Mempool
|
||||
var mempool mempl.Mempool
|
||||
|
||||
switch thisConfig.Mempool.Version {
|
||||
case cfg.MempoolV0:
|
||||
mempool = mempoolv0.NewCListMempool(config.Mempool,
|
||||
switch cfg.Mempool.Version {
|
||||
case config.MempoolV0:
|
||||
mempool = mempoolv0.NewCListMempool(cfg.Mempool,
|
||||
proxyAppConnMem,
|
||||
state.LastBlockHeight,
|
||||
mempoolv0.WithPreCheck(sm.TxPreCheck(state)),
|
||||
mempoolv0.WithPostCheck(sm.TxPostCheck(state)))
|
||||
case cfg.MempoolV1:
|
||||
case config.MempoolV1:
|
||||
mempool = mempoolv1.NewTxMempool(logger,
|
||||
config.Mempool,
|
||||
cfg.Mempool,
|
||||
proxyAppConnMem,
|
||||
state.LastBlockHeight,
|
||||
mempoolv1.WithPreCheck(sm.TxPreCheck(state)),
|
||||
@@ -91,7 +89,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
if thisConfig.Consensus.WaitForTxs() {
|
||||
if cfg.Consensus.WaitForTxs() {
|
||||
mempool.EnableTxsAvailable()
|
||||
}
|
||||
|
||||
@@ -103,7 +101,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
|
||||
// Make State
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
|
||||
cs := NewState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool)
|
||||
cs := NewState(cfg.Consensus, state, blockExec, blockStore, mempool, evpool)
|
||||
cs.SetLogger(cs.Logger)
|
||||
// set private validator
|
||||
pv := privVals[i]
|
||||
@@ -115,7 +113,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
cs.SetEventBus(eventBus)
|
||||
|
||||
cs.SetTimeoutTicker(tickerFunc())
|
||||
cs.SetTimeoutTicker(newMockTickerFunc(true)())
|
||||
cs.SetLogger(logger)
|
||||
|
||||
css[i] = cs
|
||||
@@ -143,7 +141,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// make connected switches and start all reactors
|
||||
p2p.MakeConnectedSwitches(config.P2P, nValidators, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
p2p.MakeConnectedSwitches(config.TestP2PConfig(), nValidators, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
s.AddReactor("CONSENSUS", reactors[i])
|
||||
s.SetLogger(reactors[i].conS.Logger.With("module", "p2p"))
|
||||
return s
|
||||
@@ -190,22 +188,22 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
panic("entered createProposalBlock with privValidator being nil")
|
||||
}
|
||||
|
||||
var commit *types.Commit
|
||||
var commit *types.ExtendedCommit
|
||||
switch {
|
||||
case lazyProposer.Height == lazyProposer.state.InitialHeight:
|
||||
// We're creating a proposal for the first block.
|
||||
// The commit is empty, but not nil.
|
||||
commit = types.NewCommit(0, 0, types.BlockID{}, nil)
|
||||
commit = &types.ExtendedCommit{}
|
||||
case lazyProposer.LastCommit.HasTwoThirdsMajority():
|
||||
// Make the commit from LastCommit
|
||||
commit = lazyProposer.LastCommit.MakeCommit()
|
||||
commit = lazyProposer.LastCommit.MakeExtendedCommit()
|
||||
default: // This shouldn't happen.
|
||||
lazyProposer.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block")
|
||||
return
|
||||
}
|
||||
|
||||
// omit the last signature in the commit
|
||||
commit.Signatures[len(commit.Signatures)-1] = types.NewCommitSigAbsent()
|
||||
commit.ExtendedSignatures[len(commit.ExtendedSignatures)-1] = types.NewExtendedCommitSigAbsent()
|
||||
|
||||
if lazyProposer.privValidatorPubKey == nil {
|
||||
// If this node is a validator & proposer in the current round, it will
|
||||
@@ -303,22 +301,20 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
// B sees a commit, A doesn't.
|
||||
// Heal partition and ensure A sees the commit
|
||||
func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
|
||||
N := 4
|
||||
logger := consensusLogger().With("test", "byzantine")
|
||||
app := newKVStore
|
||||
css, cleanup := randConsensusNet(t, N, "consensus_byzantine_test", newMockTickerFunc(false), app)
|
||||
defer cleanup()
|
||||
css, _, cfg := makeNetwork(t, makeNetworkArgs{})
|
||||
n := len(css)
|
||||
|
||||
// give the byzantine validator a normal ticker
|
||||
ticker := NewTimeoutTicker()
|
||||
ticker.SetLogger(css[0].Logger)
|
||||
css[0].SetTimeoutTicker(ticker)
|
||||
|
||||
switches := make([]*p2p.Switch, N)
|
||||
switches := make([]*p2p.Switch, n)
|
||||
p2pLogger := logger.With("module", "p2p")
|
||||
for i := 0; i < N; i++ {
|
||||
for i := 0; i < n; i++ {
|
||||
switches[i] = p2p.MakeSwitch(
|
||||
config.P2P,
|
||||
cfg.P2P,
|
||||
i,
|
||||
"foo", "1.0.0",
|
||||
func(i int, sw *p2p.Switch) *p2p.Switch {
|
||||
@@ -327,9 +323,9 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
|
||||
switches[i].SetLogger(p2pLogger.With("validator", i))
|
||||
}
|
||||
|
||||
blocksSubs := make([]types.Subscription, N)
|
||||
reactors := make([]p2p.Reactor, N)
|
||||
for i := 0; i < N; i++ {
|
||||
blocksSubs := make([]types.Subscription, n)
|
||||
reactors := make([]p2p.Reactor, n)
|
||||
for i := 0; i < n; i++ {
|
||||
|
||||
// enable txs so we can create different proposals
|
||||
assertMempool(css[i].txNotifier).EnableTxsAvailable()
|
||||
@@ -383,7 +379,7 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
p2p.MakeConnectedSwitches(config.P2P, N, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
p2p.MakeConnectedSwitches(cfg.P2P, n, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
// ignore new switch s, we already made ours
|
||||
switches[i].AddReactor("CONSENSUS", reactors[i])
|
||||
return switches[i]
|
||||
@@ -397,7 +393,7 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
|
||||
|
||||
// start the non-byz state machines.
|
||||
// note these must be started before the byz
|
||||
for i := 1; i < N; i++ {
|
||||
for i := 1; i < n; i++ {
|
||||
cr := reactors[i].(*Reactor)
|
||||
cr.SwitchToConsensus(cr.conS.GetState(), false)
|
||||
}
|
||||
@@ -430,7 +426,7 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
|
||||
// wait till everyone makes the first new block
|
||||
// (one of them already has)
|
||||
wg := new(sync.WaitGroup)
|
||||
for i := 1; i < N-1; i++ {
|
||||
for i := 1; i < n-1; i++ {
|
||||
wg.Add(1)
|
||||
go func(j int) {
|
||||
<-blocksSubs[j].Out()
|
||||
@@ -448,10 +444,6 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-tick.C:
|
||||
for i, reactor := range reactors {
|
||||
t.Logf("Consensus Reactor %v", i)
|
||||
t.Logf("%v", reactor)
|
||||
}
|
||||
t.Fatalf("Timed out waiting for all validators to commit first block")
|
||||
}
|
||||
}
|
||||
|
||||
+241
-227
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -15,15 +14,14 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"path"
|
||||
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
abcicli "github.com/tendermint/tendermint/abci/client"
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/config"
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
@@ -44,18 +42,38 @@ import (
|
||||
|
||||
const (
|
||||
testSubscriber = "test-client"
|
||||
|
||||
// genesis, chain_id, priv_val
|
||||
ensureTimeout = time.Millisecond * 200
|
||||
)
|
||||
|
||||
// A cleanupFunc cleans up any config / test files created for a particular
|
||||
// test.
|
||||
type cleanupFunc func()
|
||||
|
||||
// genesis, chain_id, priv_val
|
||||
var (
|
||||
config *cfg.Config // NOTE: must be reset for each _test.go file
|
||||
consensusReplayConfig *cfg.Config
|
||||
ensureTimeout = time.Millisecond * 200
|
||||
)
|
||||
func configSetup(t *testing.T) *config.Config {
|
||||
t.Helper()
|
||||
|
||||
cfg := ResetConfig("consensus_reactor_test")
|
||||
t.Cleanup(func() { os.RemoveAll(cfg.RootDir) })
|
||||
|
||||
consensusReplayConfig := ResetConfig("consensus_replay_test")
|
||||
t.Cleanup(func() { os.RemoveAll(consensusReplayConfig.RootDir) })
|
||||
|
||||
configStateTest := ResetConfig("consensus_state_test")
|
||||
t.Cleanup(func() { os.RemoveAll(configStateTest.RootDir) })
|
||||
|
||||
configMempoolTest := ResetConfig("consensus_mempool_test")
|
||||
t.Cleanup(func() { os.RemoveAll(configMempoolTest.RootDir) })
|
||||
|
||||
configByzantineTest := ResetConfig("consensus_byzantine_test")
|
||||
t.Cleanup(func() { os.RemoveAll(configByzantineTest.RootDir) })
|
||||
|
||||
walDir := filepath.Dir(cfg.Consensus.WalFile())
|
||||
ensureDir(walDir, 0700)
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func ensureDir(dir string, mode os.FileMode) {
|
||||
if err := tmos.EnsureDir(dir, mode); err != nil {
|
||||
@@ -63,8 +81,8 @@ func ensureDir(dir string, mode os.FileMode) {
|
||||
}
|
||||
}
|
||||
|
||||
func ResetConfig(name string) *cfg.Config {
|
||||
return cfg.ResetTestRoot(name)
|
||||
func ResetConfig(name string) *config.Config {
|
||||
return config.ResetTestRoot(name)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
@@ -91,8 +109,10 @@ func newValidatorStub(privValidator types.PrivValidator, valIndex int32) *valida
|
||||
|
||||
func (vs *validatorStub) signVote(
|
||||
voteType tmproto.SignedMsgType,
|
||||
hash []byte,
|
||||
header types.PartSetHeader) (*types.Vote, error) {
|
||||
chainID string,
|
||||
blockID types.BlockID,
|
||||
voteExtension []byte,
|
||||
) (*types.Vote, error) {
|
||||
|
||||
pubKey, err := vs.PrivValidator.GetPubKey()
|
||||
if err != nil {
|
||||
@@ -106,10 +126,11 @@ func (vs *validatorStub) signVote(
|
||||
Round: vs.Round,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: voteType,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: header},
|
||||
BlockID: blockID,
|
||||
Extension: voteExtension,
|
||||
}
|
||||
v := vote.ToProto()
|
||||
if err := vs.PrivValidator.SignVote(config.ChainID(), v); err != nil {
|
||||
if err := vs.PrivValidator.SignVote(chainID, v); err != nil {
|
||||
return nil, fmt.Errorf("sign vote failed: %w", err)
|
||||
}
|
||||
|
||||
@@ -117,20 +138,31 @@ func (vs *validatorStub) signVote(
|
||||
if signDataIsEqual(vs.lastVote, v) {
|
||||
v.Signature = vs.lastVote.Signature
|
||||
v.Timestamp = vs.lastVote.Timestamp
|
||||
v.ExtensionSignature = vs.lastVote.ExtensionSignature
|
||||
}
|
||||
|
||||
vote.Signature = v.Signature
|
||||
vote.Timestamp = v.Timestamp
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
|
||||
return vote, err
|
||||
}
|
||||
|
||||
// Sign vote for type/hash/header
|
||||
func signVote(vs *validatorStub, voteType tmproto.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
|
||||
v, err := vs.signVote(voteType, hash, header)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to sign vote: %v", err))
|
||||
func signVote(
|
||||
t *testing.T,
|
||||
vs *validatorStub,
|
||||
voteType tmproto.SignedMsgType,
|
||||
chainID string,
|
||||
blockID types.BlockID) *types.Vote {
|
||||
|
||||
var ext []byte
|
||||
// Only non-nil precommits are allowed to carry vote extensions.
|
||||
if voteType == tmproto.PrecommitType && !blockID.IsNil() {
|
||||
ext = []byte("extension")
|
||||
}
|
||||
v, err := vs.signVote(voteType, chainID, blockID, ext)
|
||||
require.NoError(t, err, "failed to sign vote")
|
||||
|
||||
vs.lastVote = v
|
||||
|
||||
@@ -138,17 +170,30 @@ func signVote(vs *validatorStub, voteType tmproto.SignedMsgType, hash []byte, he
|
||||
}
|
||||
|
||||
func signVotes(
|
||||
t *testing.T,
|
||||
voteType tmproto.SignedMsgType,
|
||||
hash []byte,
|
||||
header types.PartSetHeader,
|
||||
vss ...*validatorStub) []*types.Vote {
|
||||
chainID string,
|
||||
blockID types.BlockID,
|
||||
vss ...*validatorStub,
|
||||
) []*types.Vote {
|
||||
votes := make([]*types.Vote, len(vss))
|
||||
for i, vs := range vss {
|
||||
votes[i] = signVote(vs, voteType, hash, header)
|
||||
votes[i] = signVote(t, vs, voteType, chainID, blockID)
|
||||
}
|
||||
return votes
|
||||
}
|
||||
|
||||
func signAddPrecommitWithExtension(
|
||||
t *testing.T,
|
||||
cs *State,
|
||||
blockID types.BlockID,
|
||||
extension []byte,
|
||||
stub *validatorStub) {
|
||||
v, err := stub.signVote(tmproto.PrecommitType, test.DefaultTestChainID, blockID, extension)
|
||||
require.NoError(t, err, "failed to sign vote")
|
||||
addVotes(cs, v)
|
||||
}
|
||||
|
||||
func incrementHeight(vss ...*validatorStub) {
|
||||
for _, vs := range vss {
|
||||
vs.Height++
|
||||
@@ -239,14 +284,13 @@ func addVotes(to *State, votes ...*types.Vote) {
|
||||
}
|
||||
|
||||
func signAddVotes(
|
||||
t *testing.T,
|
||||
to *State,
|
||||
voteType tmproto.SignedMsgType,
|
||||
hash []byte,
|
||||
header types.PartSetHeader,
|
||||
blockID types.BlockID,
|
||||
vss ...*validatorStub,
|
||||
) {
|
||||
votes := signVotes(voteType, hash, header, vss...)
|
||||
addVotes(to, votes...)
|
||||
addVotes(to, signVotes(t, voteType, test.DefaultTestChainID, blockID, vss...)...)
|
||||
}
|
||||
|
||||
func validatePrevote(t *testing.T, cs *State, round int32, privVal *validatorStub, blockHash []byte) {
|
||||
@@ -369,30 +413,62 @@ func subscribeToVoter(cs *State, addr []byte) <-chan tmpubsub.Message {
|
||||
//-------------------------------------------------------------------------------
|
||||
// consensus states
|
||||
|
||||
func newState(state sm.State, pv types.PrivValidator, app abci.Application) *State {
|
||||
config := cfg.ResetTestRoot("consensus_state_test")
|
||||
return newStateWithConfig(config, state, pv, app)
|
||||
type makeStateArgs struct {
|
||||
config *config.Config
|
||||
consensusParams *types.ConsensusParams
|
||||
validators int
|
||||
application abci.Application
|
||||
}
|
||||
|
||||
func newStateWithConfig(
|
||||
thisConfig *cfg.Config,
|
||||
func makeState(t *testing.T, args makeStateArgs) (*State, []*validatorStub) {
|
||||
t.Helper()
|
||||
// Get State
|
||||
validators := 4
|
||||
if args.validators != 0 {
|
||||
validators = args.validators
|
||||
}
|
||||
var app abci.Application
|
||||
app = kvstore.NewInMemoryApplication()
|
||||
if args.application != nil {
|
||||
app = args.application
|
||||
}
|
||||
if args.config == nil {
|
||||
args.config = configSetup(t)
|
||||
}
|
||||
cp := test.ConsensusParams()
|
||||
if args.consensusParams != nil {
|
||||
cp = args.consensusParams
|
||||
}
|
||||
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{
|
||||
params: cp,
|
||||
validators: validators,
|
||||
})
|
||||
|
||||
vss := make([]*validatorStub, validators)
|
||||
|
||||
cs := newState(t, args.config, state, privVals[0], app)
|
||||
|
||||
for i := 0; i < validators; i++ {
|
||||
vss[i] = newValidatorStub(privVals[i], int32(i))
|
||||
}
|
||||
// since cs1 starts at 1
|
||||
incrementHeight(vss[1:]...)
|
||||
|
||||
return cs, vss
|
||||
}
|
||||
|
||||
func newState(
|
||||
t *testing.T,
|
||||
cfg *config.Config,
|
||||
state sm.State,
|
||||
pv types.PrivValidator,
|
||||
app abci.Application,
|
||||
) *State {
|
||||
blockDB := dbm.NewMemDB()
|
||||
return newStateWithConfigAndBlockStore(thisConfig, state, pv, app, blockDB)
|
||||
}
|
||||
t.Helper()
|
||||
|
||||
func newStateWithConfigAndBlockStore(
|
||||
thisConfig *cfg.Config,
|
||||
state sm.State,
|
||||
pv types.PrivValidator,
|
||||
app abci.Application,
|
||||
blockDB dbm.DB,
|
||||
) *State {
|
||||
// Get BlockStore
|
||||
blockStore := store.NewBlockStore(blockDB)
|
||||
blockStore := store.NewBlockStore(dbm.NewMemDB())
|
||||
|
||||
// one for mempool, one for consensus
|
||||
mtx := new(tmsync.Mutex)
|
||||
@@ -405,18 +481,18 @@ func newStateWithConfigAndBlockStore(
|
||||
// Make Mempool
|
||||
var mempool mempl.Mempool
|
||||
|
||||
switch config.Mempool.Version {
|
||||
case cfg.MempoolV0:
|
||||
mempool = mempoolv0.NewCListMempool(config.Mempool,
|
||||
switch cfg.Mempool.Version {
|
||||
case config.MempoolV0:
|
||||
mempool = mempoolv0.NewCListMempool(cfg.Mempool,
|
||||
proxyAppConnMem,
|
||||
state.LastBlockHeight,
|
||||
mempoolv0.WithMetrics(memplMetrics),
|
||||
mempoolv0.WithPreCheck(sm.TxPreCheck(state)),
|
||||
mempoolv0.WithPostCheck(sm.TxPostCheck(state)))
|
||||
case cfg.MempoolV1:
|
||||
case config.MempoolV1:
|
||||
logger := consensusLogger()
|
||||
mempool = mempoolv1.NewTxMempool(logger,
|
||||
config.Mempool,
|
||||
cfg.Mempool,
|
||||
proxyAppConnMem,
|
||||
state.LastBlockHeight,
|
||||
mempoolv1.WithMetrics(memplMetrics),
|
||||
@@ -424,38 +500,34 @@ func newStateWithConfigAndBlockStore(
|
||||
mempoolv1.WithPostCheck(sm.TxPostCheck(state)),
|
||||
)
|
||||
}
|
||||
if thisConfig.Consensus.WaitForTxs() {
|
||||
if cfg.Consensus.WaitForTxs() {
|
||||
mempool.EnableTxsAvailable()
|
||||
}
|
||||
|
||||
evpool := sm.EmptyEvidencePool{}
|
||||
|
||||
// Make State
|
||||
stateDB := blockDB
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
stateStore := sm.NewStore(dbm.NewMemDB(), sm.StoreOptions{
|
||||
DiscardFinalizeBlockResponses: false,
|
||||
})
|
||||
|
||||
if err := stateStore.Save(state); err != nil { // for save height 1's validators info
|
||||
panic(err)
|
||||
}
|
||||
err := stateStore.Save(state) // for save height 1's validators info
|
||||
require.NoError(t, err)
|
||||
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
|
||||
cs := NewState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool)
|
||||
cs := NewState(cfg.Consensus, state, blockExec, blockStore, mempool, evpool)
|
||||
cs.SetLogger(log.TestingLogger().With("module", "consensus"))
|
||||
cs.SetPrivValidator(pv)
|
||||
|
||||
eventBus := types.NewEventBus()
|
||||
eventBus.SetLogger(log.TestingLogger().With("module", "events"))
|
||||
err := eventBus.Start()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = eventBus.Start()
|
||||
require.NoError(t, err)
|
||||
cs.SetEventBus(eventBus)
|
||||
return cs
|
||||
}
|
||||
|
||||
func loadPrivValidator(config *cfg.Config) *privval.FilePV {
|
||||
func loadPrivValidator(config *config.Config) *privval.FilePV {
|
||||
privValidatorKeyFile := config.PrivValidatorKeyFile()
|
||||
ensureDir(filepath.Dir(privValidatorKeyFile), 0700)
|
||||
privValidatorStateFile := config.PrivValidatorStateFile()
|
||||
@@ -464,25 +536,115 @@ func loadPrivValidator(config *cfg.Config) *privval.FilePV {
|
||||
return privValidator
|
||||
}
|
||||
|
||||
func randState(nValidators int) (*State, []*validatorStub) {
|
||||
return randStateWithApp(nValidators, kvstore.NewInMemoryApplication())
|
||||
//-------------------------------------------------------------------------------
|
||||
// consensus nets
|
||||
|
||||
// consensusLogger is a TestingLogger which uses a different
|
||||
// color for each validator ("validator" key must exist).
|
||||
func consensusLogger() log.Logger {
|
||||
return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor {
|
||||
for i := 0; i < len(keyvals)-1; i += 2 {
|
||||
if keyvals[i] == "validator" {
|
||||
return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))}
|
||||
}
|
||||
}
|
||||
return term.FgBgColor{}
|
||||
}).With("module", "consensus")
|
||||
}
|
||||
|
||||
func randStateWithApp(nValidators int, app abci.Application) (*State, []*validatorStub) {
|
||||
// Get State
|
||||
state, privVals := randGenesisState(nValidators, false, 10)
|
||||
type makeNetworkArgs struct {
|
||||
config *config.Config
|
||||
params *types.ConsensusParams
|
||||
validators int
|
||||
nonValidators int
|
||||
tickerFunc func() TimeoutTicker
|
||||
appfactory func() abci.Application
|
||||
}
|
||||
|
||||
vss := make([]*validatorStub, nValidators)
|
||||
func makeNetwork(t *testing.T, args makeNetworkArgs) ([]*State, []types.PrivValidator, *config.Config) {
|
||||
t.Helper()
|
||||
|
||||
cs := newState(state, privVals[0], app)
|
||||
|
||||
for i := 0; i < nValidators; i++ {
|
||||
vss[i] = newValidatorStub(privVals[i], int32(i))
|
||||
if args.config == nil {
|
||||
args.config = config.TestConfig()
|
||||
}
|
||||
// since cs1 starts at 1
|
||||
incrementHeight(vss[1:]...)
|
||||
|
||||
return cs, vss
|
||||
if args.appfactory == nil {
|
||||
args.appfactory = func() abci.Application {
|
||||
return kvstore.NewInMemoryApplication()
|
||||
}
|
||||
}
|
||||
|
||||
if args.tickerFunc == nil {
|
||||
args.tickerFunc = newMockTickerFunc(true)
|
||||
}
|
||||
|
||||
if args.validators == 0 {
|
||||
args.validators = 4
|
||||
}
|
||||
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{
|
||||
validators: args.validators,
|
||||
params: args.params,
|
||||
})
|
||||
|
||||
for i := 0; i < args.nonValidators; i++ {
|
||||
privVals = append(privVals, types.NewMockPV())
|
||||
}
|
||||
|
||||
css := make([]*State, args.validators+args.nonValidators)
|
||||
logger := consensusLogger()
|
||||
for i := 0; i < args.validators+args.nonValidators; i++ {
|
||||
app := args.appfactory()
|
||||
vals := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
_, err := app.InitChain(context.Background(), &abci.RequestInitChain{Validators: vals})
|
||||
require.NoError(t, err)
|
||||
|
||||
css[i] = newState(t, args.config, state, privVals[i], app)
|
||||
css[i].SetTimeoutTicker(args.tickerFunc())
|
||||
css[i].SetLogger(logger.With("validator", i, "module", "consensus"))
|
||||
}
|
||||
|
||||
return css, privVals, args.config
|
||||
}
|
||||
|
||||
func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
|
||||
for i, s := range switches {
|
||||
if peer.NodeInfo().ID() == s.NodeInfo().ID() {
|
||||
return i
|
||||
}
|
||||
}
|
||||
panic("didnt find peer in switches")
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// genesis
|
||||
|
||||
type genesisStateArgs struct {
|
||||
validators int
|
||||
power int64
|
||||
params *types.ConsensusParams
|
||||
time time.Time
|
||||
}
|
||||
|
||||
func makeGenesisState(t *testing.T, args genesisStateArgs) (sm.State, []types.PrivValidator) {
|
||||
t.Helper()
|
||||
if args.power == 0 {
|
||||
args.power = 1
|
||||
}
|
||||
if args.validators == 0 {
|
||||
args.validators = 4
|
||||
}
|
||||
valSet, privValidators := test.ValidatorSet(t, args.validators, args.power)
|
||||
if args.params == nil {
|
||||
args.params = test.ConsensusParams()
|
||||
}
|
||||
if args.time.IsZero() {
|
||||
args.time = time.Now()
|
||||
}
|
||||
genDoc := test.GenesisDoc("", args.time, valSet.Validators, args.params)
|
||||
state, err := sm.MakeGenesisState(genDoc)
|
||||
require.NoError(t, err)
|
||||
return state, privValidators
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
@@ -694,6 +856,11 @@ func ensurePrevoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int
|
||||
ensureVoteMatch(t, voteCh, height, round, hash, tmproto.PrevoteType)
|
||||
}
|
||||
|
||||
func ensurePrecommitMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte) {
|
||||
t.Helper()
|
||||
ensureVoteMatch(t, voteCh, height, round, hash, tmproto.PrecommitType)
|
||||
}
|
||||
|
||||
func ensureVoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte, voteType tmproto.SignedMsgType) {
|
||||
t.Helper()
|
||||
select {
|
||||
@@ -732,159 +899,6 @@ func ensureNewEventOnChannel(ch <-chan tmpubsub.Message) {
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// consensus nets
|
||||
|
||||
// consensusLogger is a TestingLogger which uses a different
|
||||
// color for each validator ("validator" key must exist).
|
||||
func consensusLogger() log.Logger {
|
||||
return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor {
|
||||
for i := 0; i < len(keyvals)-1; i += 2 {
|
||||
if keyvals[i] == "validator" {
|
||||
return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))}
|
||||
}
|
||||
}
|
||||
return term.FgBgColor{}
|
||||
}).With("module", "consensus")
|
||||
}
|
||||
|
||||
func randConsensusNet(t *testing.T, nValidators int, testName string, tickerFunc func() TimeoutTicker,
|
||||
appFunc func() abci.Application, configOpts ...func(*cfg.Config)) ([]*State, cleanupFunc) {
|
||||
t.Helper()
|
||||
genDoc, privVals := randGenesisDoc(nValidators, false, 30)
|
||||
css := make([]*State, nValidators)
|
||||
logger := consensusLogger()
|
||||
configRootDirs := make([]string, 0, nValidators)
|
||||
for i := 0; i < nValidators; i++ {
|
||||
stateDB := dbm.NewMemDB() // each state needs its own db
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardFinalizeBlockResponses: false,
|
||||
})
|
||||
state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
|
||||
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
|
||||
configRootDirs = append(configRootDirs, thisConfig.RootDir)
|
||||
for _, opt := range configOpts {
|
||||
opt(thisConfig)
|
||||
}
|
||||
ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
|
||||
app := appFunc()
|
||||
vals := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
_, err := app.InitChain(context.Background(), &abci.RequestInitChain{Validators: vals})
|
||||
require.NoError(t, err)
|
||||
|
||||
css[i] = newStateWithConfigAndBlockStore(thisConfig, state, privVals[i], app, stateDB)
|
||||
css[i].SetTimeoutTicker(tickerFunc())
|
||||
css[i].SetLogger(logger.With("validator", i, "module", "consensus"))
|
||||
}
|
||||
return css, func() {
|
||||
for _, dir := range configRootDirs {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nPeers = nValidators + nNotValidator
|
||||
func randConsensusNetWithPeers(
|
||||
t *testing.T,
|
||||
nValidators,
|
||||
nPeers int,
|
||||
testName string,
|
||||
tickerFunc func() TimeoutTicker,
|
||||
appFunc func(string) abci.Application,
|
||||
) ([]*State, *types.GenesisDoc, *cfg.Config, cleanupFunc) {
|
||||
genDoc, privVals := randGenesisDoc(nValidators, false, testMinPower)
|
||||
css := make([]*State, nPeers)
|
||||
logger := consensusLogger()
|
||||
var peer0Config *cfg.Config
|
||||
configRootDirs := make([]string, 0, nPeers)
|
||||
for i := 0; i < nPeers; i++ {
|
||||
stateDB := dbm.NewMemDB() // each state needs its own db
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardFinalizeBlockResponses: false,
|
||||
})
|
||||
t.Cleanup(func() { _ = stateStore.Close() })
|
||||
state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
|
||||
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
|
||||
configRootDirs = append(configRootDirs, thisConfig.RootDir)
|
||||
ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
|
||||
if i == 0 {
|
||||
peer0Config = thisConfig
|
||||
}
|
||||
var privVal types.PrivValidator
|
||||
if i < nValidators {
|
||||
privVal = privVals[i]
|
||||
} else {
|
||||
tempKeyFile, err := os.CreateTemp("", "priv_validator_key_")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
privVal = privval.GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
|
||||
}
|
||||
|
||||
app := appFunc(path.Join(config.DBDir(), fmt.Sprintf("%s_%d", testName, i)))
|
||||
vals := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
if _, ok := app.(*kvstore.Application); ok {
|
||||
// simulate handshake, receive app version. If don't do this, replay test will fail
|
||||
state.Version.Consensus.App = kvstore.AppVersion
|
||||
}
|
||||
_, err := app.InitChain(context.Background(), &abci.RequestInitChain{Validators: vals})
|
||||
require.NoError(t, err)
|
||||
|
||||
css[i] = newStateWithConfig(thisConfig, state, privVal, app)
|
||||
css[i].SetTimeoutTicker(tickerFunc())
|
||||
css[i].SetLogger(logger.With("validator", i, "module", "consensus"))
|
||||
}
|
||||
return css, genDoc, peer0Config, func() {
|
||||
for _, dir := range configRootDirs {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
|
||||
for i, s := range switches {
|
||||
if peer.NodeInfo().ID() == s.NodeInfo().ID() {
|
||||
return i
|
||||
}
|
||||
}
|
||||
panic("didnt find peer in switches")
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// genesis
|
||||
|
||||
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []types.PrivValidator) {
|
||||
validators := make([]types.GenesisValidator, numValidators)
|
||||
privValidators := make([]types.PrivValidator, numValidators)
|
||||
for i := 0; i < numValidators; i++ {
|
||||
val, privVal := types.RandValidator(randPower, minPower)
|
||||
validators[i] = types.GenesisValidator{
|
||||
PubKey: val.PubKey,
|
||||
Power: val.VotingPower,
|
||||
}
|
||||
privValidators[i] = privVal
|
||||
}
|
||||
sort.Sort(types.PrivValidatorsByAddress(privValidators))
|
||||
|
||||
return &types.GenesisDoc{
|
||||
GenesisTime: tmtime.Now(),
|
||||
InitialHeight: 1,
|
||||
ChainID: config.ChainID(),
|
||||
Validators: validators,
|
||||
}, privValidators
|
||||
}
|
||||
|
||||
func randGenesisState(numValidators int, randPower bool, minPower int64) (sm.State, []types.PrivValidator) {
|
||||
genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
|
||||
s0, _ := sm.MakeGenesisState(genDoc)
|
||||
return s0, privValidators
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// mock ticker
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ import (
|
||||
// Ensure a testnet makes blocks
|
||||
func TestReactorInvalidPrecommit(t *testing.T) {
|
||||
N := 4
|
||||
css, cleanup := randConsensusNet(t, N, "consensus_reactor_test", newMockTickerFunc(true), newKVStore)
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{})
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
ticker := NewTimeoutTicker()
|
||||
|
||||
+13
-12
@@ -30,12 +30,12 @@ func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
|
||||
config := ResetConfig("consensus_mempool_txs_available_test")
|
||||
defer os.RemoveAll(config.RootDir)
|
||||
config.Consensus.CreateEmptyBlocks = false
|
||||
state, privVals := randGenesisState(1, false, 10)
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{validators: 1})
|
||||
app := kvstore.NewInMemoryApplication()
|
||||
resp, err := app.Info(context.Background(), proxy.RequestInfo)
|
||||
require.NoError(t, err)
|
||||
state.AppHash = resp.LastBlockAppHash
|
||||
cs := newStateWithConfig(config, state, privVals[0], app)
|
||||
cs := newState(t, config, state, privVals[0], app)
|
||||
assertMempool(cs.txNotifier).EnableTxsAvailable()
|
||||
height, round := cs.Height, cs.Round
|
||||
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
|
||||
@@ -54,12 +54,12 @@ func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
|
||||
defer os.RemoveAll(config.RootDir)
|
||||
|
||||
config.Consensus.CreateEmptyBlocksInterval = ensureTimeout
|
||||
state, privVals := randGenesisState(1, false, 10)
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{validators: 1})
|
||||
app := kvstore.NewInMemoryApplication()
|
||||
resp, err := app.Info(context.Background(), proxy.RequestInfo)
|
||||
require.NoError(t, err)
|
||||
state.AppHash = resp.LastBlockAppHash
|
||||
cs := newStateWithConfig(config, state, privVals[0], app)
|
||||
cs := newState(t, config, state, privVals[0], app)
|
||||
|
||||
assertMempool(cs.txNotifier).EnableTxsAvailable()
|
||||
|
||||
@@ -75,8 +75,8 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
|
||||
config := ResetConfig("consensus_mempool_txs_available_test")
|
||||
defer os.RemoveAll(config.RootDir)
|
||||
config.Consensus.CreateEmptyBlocks = false
|
||||
state, privVals := randGenesisState(1, false, 10)
|
||||
cs := newStateWithConfig(config, state, privVals[0], kvstore.NewInMemoryApplication())
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{validators: 1})
|
||||
cs := newState(t, config, state, privVals[0], kvstore.NewInMemoryApplication())
|
||||
assertMempool(cs.txNotifier).EnableTxsAvailable()
|
||||
height, round := cs.Height, cs.Round
|
||||
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
|
||||
@@ -117,10 +117,10 @@ func deliverTxsRange(t *testing.T, cs *State, start, end int) {
|
||||
}
|
||||
|
||||
func TestMempoolTxConcurrentWithCommit(t *testing.T) {
|
||||
state, privVals := randGenesisState(1, false, 10)
|
||||
blockDB := dbm.NewMemDB()
|
||||
stateStore := sm.NewStore(blockDB, sm.StoreOptions{DiscardFinalizeBlockResponses: false})
|
||||
cs := newStateWithConfigAndBlockStore(config, state, privVals[0], kvstore.NewInMemoryApplication(), blockDB)
|
||||
cfg := ResetConfig(t.Name())
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{validators: 1})
|
||||
stateStore := sm.NewStore(dbm.NewMemDB(), sm.StoreOptions{DiscardFinalizeBlockResponses: false})
|
||||
cs := newState(t, cfg, state, privVals[0], kvstore.NewInMemoryApplication())
|
||||
err := stateStore.Save(state)
|
||||
require.NoError(t, err)
|
||||
newBlockEventsCh := subscribe(cs.eventBus, types.EventQueryNewBlockEvents)
|
||||
@@ -141,11 +141,12 @@ func TestMempoolTxConcurrentWithCommit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMempoolRmBadTx(t *testing.T) {
|
||||
state, privVals := randGenesisState(1, false, 10)
|
||||
cfg := ResetConfig(t.Name())
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{validators: 1})
|
||||
app := kvstore.NewInMemoryApplication()
|
||||
blockDB := dbm.NewMemDB()
|
||||
stateStore := sm.NewStore(blockDB, sm.StoreOptions{DiscardFinalizeBlockResponses: false})
|
||||
cs := newStateWithConfigAndBlockStore(config, state, privVals[0], app, blockDB)
|
||||
cs := newState(t, cfg, state, privVals[0], app)
|
||||
err := stateStore.Save(state)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -162,6 +162,12 @@ func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
|
||||
Name: "full_prevote_delay",
|
||||
Help: "Interval in seconds between the proposal timestamp and the timestamp of the latest prevote in a round where all validators voted.",
|
||||
}, append(labels, "proposer_address")).With(labelsAndValues...),
|
||||
VoteExtensionReceiveCount: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: MetricsSubsystem,
|
||||
Name: "vote_extension_receive_count",
|
||||
Help: "Number of vote extensions received labeled by application response status.",
|
||||
}, append(labels, "status")).With(labelsAndValues...),
|
||||
ProposalReceiveCount: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: MetricsSubsystem,
|
||||
@@ -215,6 +221,7 @@ func NopMetrics() *Metrics {
|
||||
BlockGossipPartsReceived: discard.NewCounter(),
|
||||
QuorumPrevoteDelay: discard.NewGauge(),
|
||||
FullPrevoteDelay: discard.NewGauge(),
|
||||
VoteExtensionReceiveCount: discard.NewCounter(),
|
||||
ProposalReceiveCount: discard.NewCounter(),
|
||||
ProposalCreateCount: discard.NewCounter(),
|
||||
RoundVotingPowerPercent: discard.NewGauge(),
|
||||
|
||||
@@ -95,6 +95,12 @@ type Metrics struct {
|
||||
//metrics:Interval in seconds between the proposal timestamp and the timestamp of the latest prevote in a round where all validators voted.
|
||||
FullPrevoteDelay metrics.Gauge `metrics_labels:"proposer_address"`
|
||||
|
||||
// VoteExtensionReceiveCount is the number of vote extensions received by this
|
||||
// node. The metric is annotated by the status of the vote extension from the
|
||||
// application, either 'accepted' or 'rejected'.
|
||||
//metrics:Number of vote extensions received labeled by application response status.
|
||||
VoteExtensionReceiveCount metrics.Counter `metrics_labels:"status"`
|
||||
|
||||
// ProposalReceiveCount is the total number of proposals received by this node
|
||||
// since process start.
|
||||
// The metric is annotated by the status of the proposal from the application,
|
||||
@@ -132,6 +138,14 @@ func (m *Metrics) MarkProposalProcessed(accepted bool) {
|
||||
m.ProposalReceiveCount.With("status", status).Add(1)
|
||||
}
|
||||
|
||||
func (m *Metrics) MarkVoteExtensionReceived(accepted bool) {
|
||||
status := "accepted"
|
||||
if !accepted {
|
||||
status = "rejected"
|
||||
}
|
||||
m.VoteExtensionReceiveCount.With("status", status).Add(1)
|
||||
}
|
||||
|
||||
func (m *Metrics) MarkVoteReceived(vt tmproto.SignedMsgType, power, totalPower int64) {
|
||||
p := float64(power) / float64(totalPower)
|
||||
n := strings.ToLower(strings.TrimPrefix(vt.String(), "SIGNED_MSG_TYPE_"))
|
||||
|
||||
+26
-47
@@ -18,10 +18,11 @@ import (
|
||||
abcicli "github.com/tendermint/tendermint/abci/client"
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/config"
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
"github.com/tendermint/tendermint/libs/bits"
|
||||
"github.com/tendermint/tendermint/libs/bytes"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -74,7 +75,7 @@ func startConsensusNet(t *testing.T, css []*State, n int) (
|
||||
}
|
||||
}
|
||||
// make connected switches and start all reactors
|
||||
p2p.MakeConnectedSwitches(config.P2P, n, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
p2p.MakeConnectedSwitches(config.TestP2PConfig(), n, func(i int, s *p2p.Switch) *p2p.Switch {
|
||||
s.AddReactor("CONSENSUS", reactors[i])
|
||||
s.SetLogger(reactors[i].conS.Logger.With("module", "p2p"))
|
||||
return s
|
||||
@@ -111,8 +112,10 @@ func stopConsensusNet(logger log.Logger, reactors []*Reactor, eventBuses []*type
|
||||
// Ensure a testnet makes blocks
|
||||
func TestReactorBasic(t *testing.T) {
|
||||
N := 4
|
||||
css, cleanup := randConsensusNet(t, N, "consensus_reactor_test", newMockTickerFunc(true), newKVStore)
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{
|
||||
tickerFunc: newMockTickerFunc(true),
|
||||
validators: N,
|
||||
})
|
||||
reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N)
|
||||
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
|
||||
// wait till everyone makes the first new block
|
||||
@@ -132,7 +135,7 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
// to unroll unwieldy abstractions. Here we duplicate the code from:
|
||||
// css := randConsensusNet(N, "consensus_reactor_test", newMockTickerFunc(true), newKVStore)
|
||||
|
||||
genDoc, privVals := randGenesisDoc(nValidators, false, 30)
|
||||
state, privVals := makeGenesisState(t, genesisStateArgs{validators: nValidators, power: 30})
|
||||
css := make([]*State, nValidators)
|
||||
logger := consensusLogger()
|
||||
for i := 0; i < nValidators; i++ {
|
||||
@@ -140,10 +143,9 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardFinalizeBlockResponses: false,
|
||||
})
|
||||
state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
|
||||
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
|
||||
defer os.RemoveAll(thisConfig.RootDir)
|
||||
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
|
||||
cfg := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
|
||||
defer os.RemoveAll(cfg.RootDir)
|
||||
ensureDir(path.Dir(cfg.Consensus.WalFile()), 0700) // dir for wal
|
||||
app := appFunc()
|
||||
vals := types.TM2PB.ValidatorUpdates(state.Validators)
|
||||
_, err := app.InitChain(context.Background(), &abci.RequestInitChain{Validators: vals})
|
||||
@@ -165,17 +167,17 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
// Make Mempool
|
||||
var mempool mempl.Mempool
|
||||
|
||||
switch config.Mempool.Version {
|
||||
case cfg.MempoolV0:
|
||||
mempool = mempoolv0.NewCListMempool(config.Mempool,
|
||||
switch cfg.Mempool.Version {
|
||||
case config.MempoolV0:
|
||||
mempool = mempoolv0.NewCListMempool(cfg.Mempool,
|
||||
proxyAppConnMem,
|
||||
state.LastBlockHeight,
|
||||
mempoolv0.WithMetrics(memplMetrics),
|
||||
mempoolv0.WithPreCheck(sm.TxPreCheck(state)),
|
||||
mempoolv0.WithPostCheck(sm.TxPostCheck(state)))
|
||||
case cfg.MempoolV1:
|
||||
case config.MempoolV1:
|
||||
mempool = mempoolv1.NewTxMempool(logger,
|
||||
config.Mempool,
|
||||
cfg.Mempool,
|
||||
proxyAppConnMem,
|
||||
state.LastBlockHeight,
|
||||
mempoolv1.WithMetrics(memplMetrics),
|
||||
@@ -183,14 +185,14 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
mempoolv1.WithPostCheck(sm.TxPostCheck(state)),
|
||||
)
|
||||
}
|
||||
if thisConfig.Consensus.WaitForTxs() {
|
||||
if cfg.Consensus.WaitForTxs() {
|
||||
mempool.EnableTxsAvailable()
|
||||
}
|
||||
|
||||
// mock the evidence pool
|
||||
// everyone includes evidence of another double signing
|
||||
vIdx := (i + 1) % nValidators
|
||||
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, privVals[vIdx], config.ChainID())
|
||||
ev, err := types.NewMockDuplicateVoteEvidenceWithValidator(1, defaultTestTime, privVals[vIdx], test.DefaultTestChainID)
|
||||
require.NoError(t, err)
|
||||
evpool := &statemocks.EvidencePool{}
|
||||
evpool.On("CheckEvidence", mock.AnythingOfType("types.EvidenceList")).Return(nil)
|
||||
@@ -202,7 +204,7 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
|
||||
// Make State
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
|
||||
cs := NewState(thisConfig.Consensus, state, blockExec, blockStore, mempool, evpool2)
|
||||
cs := NewState(cfg.Consensus, state, blockExec, blockStore, mempool, evpool2)
|
||||
cs.SetLogger(log.TestingLogger().With("module", "consensus"))
|
||||
cs.SetPrivValidator(pv)
|
||||
|
||||
@@ -236,11 +238,7 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
// Ensure a testnet makes blocks when there are txs
|
||||
func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
|
||||
N := 4
|
||||
css, cleanup := randConsensusNet(t, N, "consensus_reactor_test", newMockTickerFunc(true), newKVStore,
|
||||
func(c *cfg.Config) {
|
||||
c.Consensus.CreateEmptyBlocks = false
|
||||
})
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{validators: N})
|
||||
reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N)
|
||||
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
|
||||
|
||||
@@ -259,8 +257,7 @@ func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
|
||||
|
||||
func TestReactorReceiveDoesNotPanicIfAddPeerHasntBeenCalledYet(t *testing.T) {
|
||||
N := 1
|
||||
css, cleanup := randConsensusNet(t, N, "consensus_reactor_test", newMockTickerFunc(true), newKVStore)
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{validators: N})
|
||||
reactors, _, eventBuses := startConsensusNet(t, css, N)
|
||||
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
|
||||
|
||||
@@ -282,8 +279,7 @@ func TestReactorReceiveDoesNotPanicIfAddPeerHasntBeenCalledYet(t *testing.T) {
|
||||
|
||||
func TestReactorReceivePanicsIfInitPeerHasntBeenCalledYet(t *testing.T) {
|
||||
N := 1
|
||||
css, cleanup := randConsensusNet(t, N, "consensus_reactor_test", newMockTickerFunc(true), newKVStore)
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{validators: N})
|
||||
reactors, _, eventBuses := startConsensusNet(t, css, N)
|
||||
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
|
||||
|
||||
@@ -305,8 +301,7 @@ func TestReactorReceivePanicsIfInitPeerHasntBeenCalledYet(t *testing.T) {
|
||||
// Test we record stats about votes and block parts from other peers.
|
||||
func TestReactorRecordsVotesAndBlockParts(t *testing.T) {
|
||||
N := 4
|
||||
css, cleanup := randConsensusNet(t, N, "consensus_reactor_test", newMockTickerFunc(true), newKVStore)
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{validators: N})
|
||||
reactors, blocksSubs, eventBuses := startConsensusNet(t, css, N)
|
||||
defer stopConsensusNet(log.TestingLogger(), reactors, eventBuses)
|
||||
|
||||
@@ -330,13 +325,7 @@ func TestReactorRecordsVotesAndBlockParts(t *testing.T) {
|
||||
func TestReactorVotingPowerChange(t *testing.T) {
|
||||
nVals := 4
|
||||
logger := log.TestingLogger()
|
||||
css, cleanup := randConsensusNet(
|
||||
t,
|
||||
nVals,
|
||||
"consensus_voting_power_changes_test",
|
||||
newMockTickerFunc(true),
|
||||
newPersistentKVStore)
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{validators: nVals})
|
||||
reactors, blocksSubs, eventBuses := startConsensusNet(t, css, nVals)
|
||||
defer stopConsensusNet(logger, reactors, eventBuses)
|
||||
|
||||
@@ -411,15 +400,7 @@ func TestReactorVotingPowerChange(t *testing.T) {
|
||||
func TestReactorValidatorSetChanges(t *testing.T) {
|
||||
nPeers := 7
|
||||
nVals := 4
|
||||
css, _, _, cleanup := randConsensusNetWithPeers(
|
||||
t,
|
||||
nVals,
|
||||
nPeers,
|
||||
"consensus_val_set_changes_test",
|
||||
newMockTickerFunc(true),
|
||||
newPersistentKVStoreWithPath)
|
||||
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{validators: nVals, nonValidators: nPeers - nVals})
|
||||
logger := log.TestingLogger()
|
||||
|
||||
reactors, blocksSubs, eventBuses := startConsensusNet(t, css, nPeers)
|
||||
@@ -526,8 +507,7 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
||||
// Check we can make blocks with skip_timeout_commit=false
|
||||
func TestReactorWithTimeoutCommit(t *testing.T) {
|
||||
N := 4
|
||||
css, cleanup := randConsensusNet(t, N, "consensus_reactor_with_timeout_commit_test", newMockTickerFunc(false), newKVStore)
|
||||
defer cleanup()
|
||||
css, _, _ := makeNetwork(t, makeNetworkArgs{validators: N, tickerFunc: newMockTickerFunc(false)})
|
||||
// override default SkipTimeoutCommit == true for tests
|
||||
for i := 0; i < N; i++ {
|
||||
css[i].config.SkipTimeoutCommit = false
|
||||
@@ -562,7 +542,6 @@ func waitForAndValidateBlock(
|
||||
for _, tx := range txs {
|
||||
err := assertMempool(css[j].txNotifier).CheckTx(tx, func(resp *abci.ResponseCheckTx) {
|
||||
require.False(t, resp.IsErr())
|
||||
fmt.Println(resp)
|
||||
}, mempl.TxInfo{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
+35
-49
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/abci/types/mocks"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -33,21 +33,6 @@ import (
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
config = ResetConfig("consensus_reactor_test")
|
||||
consensusReplayConfig = ResetConfig("consensus_replay_test")
|
||||
configStateTest := ResetConfig("consensus_state_test")
|
||||
configMempoolTest := ResetConfig("consensus_mempool_test")
|
||||
configByzantineTest := ResetConfig("consensus_byzantine_test")
|
||||
code := m.Run()
|
||||
os.RemoveAll(config.RootDir)
|
||||
os.RemoveAll(consensusReplayConfig.RootDir)
|
||||
os.RemoveAll(configStateTest.RootDir)
|
||||
os.RemoveAll(configMempoolTest.RootDir)
|
||||
os.RemoveAll(configByzantineTest.RootDir)
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// These tests ensure we can always recover from failure at any part of the consensus process.
|
||||
// There are two general failure scenarios: failure during consensus, and failure while applying the block.
|
||||
// Only the latter interacts with the app and store,
|
||||
@@ -63,17 +48,17 @@ func TestMain(m *testing.M) {
|
||||
// and which ones we need the wal for - then we'd also be able to only flush the
|
||||
// wal writer when we need to, instead of with every message.
|
||||
|
||||
func startNewStateAndWaitForBlock(t *testing.T, consensusReplayConfig *cfg.Config,
|
||||
lastBlockHeight int64, blockDB dbm.DB, stateStore sm.Store) {
|
||||
func startNewStateAndWaitForBlock(t *testing.T, consensusReplayConfig *config.Config,
|
||||
lastBlockHeight int64, stateStore sm.Store) {
|
||||
logger := log.TestingLogger()
|
||||
state, _ := stateStore.LoadFromDBOrGenesisFile(consensusReplayConfig.GenesisFile())
|
||||
privValidator := loadPrivValidator(consensusReplayConfig)
|
||||
cs := newStateWithConfigAndBlockStore(
|
||||
cs := newState(
|
||||
t,
|
||||
consensusReplayConfig,
|
||||
state,
|
||||
privValidator,
|
||||
kvstore.NewInMemoryApplication(),
|
||||
blockDB,
|
||||
)
|
||||
cs.SetLogger(logger)
|
||||
|
||||
@@ -148,7 +133,7 @@ func TestWALCrash(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func crashWALandCheckLiveness(t *testing.T, consensusReplayConfig *cfg.Config,
|
||||
func crashWALandCheckLiveness(t *testing.T, cfg *config.Config,
|
||||
initFn func(dbm.DB, *State, context.Context), heightToStop int64) {
|
||||
walPanicked := make(chan error)
|
||||
crashingWal := &crashingWAL{panicCh: walPanicked, heightToStop: heightToStop}
|
||||
@@ -160,20 +145,19 @@ LOOP:
|
||||
|
||||
// create consensus state from a clean slate
|
||||
logger := log.NewNopLogger()
|
||||
blockDB := dbm.NewMemDB()
|
||||
stateDB := blockDB
|
||||
stateDB := dbm.NewMemDB()
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardFinalizeBlockResponses: false,
|
||||
})
|
||||
state, err := sm.MakeGenesisStateFromFile(consensusReplayConfig.GenesisFile())
|
||||
state, err := sm.MakeGenesisStateFromFile(cfg.GenesisFile())
|
||||
require.NoError(t, err)
|
||||
privValidator := loadPrivValidator(consensusReplayConfig)
|
||||
cs := newStateWithConfigAndBlockStore(
|
||||
consensusReplayConfig,
|
||||
privValidator := loadPrivValidator(cfg)
|
||||
cs := newState(
|
||||
t,
|
||||
cfg,
|
||||
state,
|
||||
privValidator,
|
||||
kvstore.NewInMemoryApplication(),
|
||||
blockDB,
|
||||
)
|
||||
cs.SetLogger(logger)
|
||||
|
||||
@@ -205,7 +189,7 @@ LOOP:
|
||||
t.Logf("WAL panicked: %v", err)
|
||||
|
||||
// make sure we can make blocks after a crash
|
||||
startNewStateAndWaitForBlock(t, consensusReplayConfig, cs.Height, blockDB, stateStore)
|
||||
startNewStateAndWaitForBlock(t, cfg, cs.Height, stateStore)
|
||||
|
||||
// stop consensus state and transactions sender (initFn)
|
||||
cs.Stop() //nolint:errcheck // Logging this error causes failure
|
||||
@@ -311,28 +295,28 @@ var modes = []uint{0, 1, 2, 3}
|
||||
// Sync from scratch
|
||||
func TestHandshakeReplayAll(t *testing.T) {
|
||||
for _, m := range modes {
|
||||
testHandshakeReplay(t, config, 0, m)
|
||||
testHandshakeReplay(t, 0, m)
|
||||
}
|
||||
}
|
||||
|
||||
// Sync many, not from scratch
|
||||
func TestHandshakeReplaySome(t *testing.T) {
|
||||
for _, m := range modes {
|
||||
testHandshakeReplay(t, config, 2, m)
|
||||
testHandshakeReplay(t, 2, m)
|
||||
}
|
||||
}
|
||||
|
||||
// Sync from lagging by one
|
||||
func TestHandshakeReplayOne(t *testing.T) {
|
||||
for _, m := range modes {
|
||||
testHandshakeReplay(t, config, numBlocks-1, m)
|
||||
testHandshakeReplay(t, numBlocks-1, m)
|
||||
}
|
||||
}
|
||||
|
||||
// Sync from caught up
|
||||
func TestHandshakeReplayNone(t *testing.T) {
|
||||
for _, m := range modes {
|
||||
testHandshakeReplay(t, config, numBlocks, m)
|
||||
testHandshakeReplay(t, numBlocks, m)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +337,7 @@ func tempWALWithData(data []byte) string {
|
||||
|
||||
// Make some blocks. Start a fresh app and apply nBlocks blocks.
|
||||
// Then restart the app and sync it up with the remaining blocks
|
||||
func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uint) {
|
||||
func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
||||
var (
|
||||
chain []*types.Block
|
||||
commits []*types.Commit
|
||||
@@ -364,16 +348,16 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
|
||||
evpool = sm.EmptyEvidencePool{}
|
||||
)
|
||||
|
||||
testConfig := ResetConfig(fmt.Sprintf("%d_%d_s", nBlocks, mode))
|
||||
testConfig := ResetConfig(fmt.Sprintf("handhsake_%d_%d", nBlocks, mode))
|
||||
t.Cleanup(func() {
|
||||
_ = os.RemoveAll(testConfig.RootDir)
|
||||
})
|
||||
walBody, err := WALWithNBlocks(t, numBlocks)
|
||||
require.NoError(t, err)
|
||||
walFile := tempWALWithData(walBody)
|
||||
config.Consensus.SetWalFile(walFile)
|
||||
testConfig.Consensus.SetWalFile(walFile)
|
||||
|
||||
privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
|
||||
privVal := privval.LoadFilePV(testConfig.PrivValidatorKeyFile(), testConfig.PrivValidatorStateFile())
|
||||
|
||||
wal, err := NewWAL(walFile)
|
||||
require.NoError(t, err)
|
||||
@@ -389,7 +373,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
|
||||
require.NoError(t, err)
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
stateDB, genesisState, store = stateAndStore(t, config, pubKey, kvstore.AppVersion)
|
||||
stateDB, genesisState, store = stateAndStore(t, testConfig, pubKey, kvstore.AppVersion)
|
||||
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardFinalizeBlockResponses: false,
|
||||
@@ -402,12 +386,12 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
|
||||
|
||||
state := genesisState.Copy()
|
||||
// run the chain through state.ApplyBlock to build up the tendermint state
|
||||
state = buildTMStateFromChain(t, config, stateStore, mempool, evpool, state, chain, nBlocks, mode)
|
||||
state = buildTMStateFromChain(t, testConfig, stateStore, mempool, evpool, state, chain, nBlocks, mode)
|
||||
latestAppHash := state.AppHash
|
||||
|
||||
// make a new client creator
|
||||
kvstoreApp := kvstore.NewPersistentApplication(
|
||||
filepath.Join(config.DBDir(), fmt.Sprintf("replay_test_%d_%d_a", nBlocks, mode)))
|
||||
filepath.Join(testConfig.DBDir(), fmt.Sprintf("replay_test_%d_%d_a", nBlocks, mode)))
|
||||
t.Cleanup(func() {
|
||||
_ = kvstoreApp.Close()
|
||||
})
|
||||
@@ -436,7 +420,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
|
||||
}
|
||||
|
||||
// now start the app using the handshake - it should sync
|
||||
genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
|
||||
genDoc, _ := sm.MakeGenesisDocFromFile(testConfig.GenesisFile())
|
||||
handshaker := NewHandshaker(stateStore, state, store, genDoc)
|
||||
proxyApp := proxy.NewAppConns(clientCreator2, proxy.NopMetrics())
|
||||
if err := proxyApp.Start(); err != nil {
|
||||
@@ -538,7 +522,7 @@ func buildAppStateFromChain(t *testing.T, proxyApp proxy.AppConns, stateStore sm
|
||||
|
||||
func buildTMStateFromChain(
|
||||
t *testing.T,
|
||||
config *cfg.Config,
|
||||
cfg *config.Config,
|
||||
stateStore sm.Store,
|
||||
mempool mempool.Mempool,
|
||||
evpool sm.EvidencePool,
|
||||
@@ -549,7 +533,7 @@ func buildTMStateFromChain(
|
||||
// run the whole chain against this client to build up the tendermint state
|
||||
clientCreator := proxy.NewLocalClientCreator(
|
||||
kvstore.NewPersistentApplication(
|
||||
filepath.Join(config.DBDir(), fmt.Sprintf("replay_test_%d_%d_t", nBlocks, mode))))
|
||||
filepath.Join(cfg.DBDir(), fmt.Sprintf("replay_test_%d_%d_t", nBlocks, mode))))
|
||||
proxyApp := proxy.NewAppConns(clientCreator, proxy.NopMetrics())
|
||||
if err := proxyApp.Start(); err != nil {
|
||||
panic(err)
|
||||
@@ -814,7 +798,7 @@ func readPieceFromWAL(msg *TimedWALMessage) interface{} {
|
||||
// fresh state and mock store
|
||||
func stateAndStore(
|
||||
t *testing.T,
|
||||
config *cfg.Config,
|
||||
cfg *config.Config,
|
||||
pubKey crypto.PubKey,
|
||||
appVersion uint64,
|
||||
) (dbm.DB, sm.State, *mockBlockStore) {
|
||||
@@ -822,10 +806,10 @@ func stateAndStore(
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardFinalizeBlockResponses: false,
|
||||
})
|
||||
state, err := sm.MakeGenesisStateFromFile(config.GenesisFile())
|
||||
state, err := sm.MakeGenesisStateFromFile(cfg.GenesisFile())
|
||||
require.NoError(t, err)
|
||||
state.Version.Consensus.App = appVersion
|
||||
store := newMockBlockStore(t, config, state.ConsensusParams)
|
||||
store := newMockBlockStore(t, cfg, state.ConsensusParams)
|
||||
require.NoError(t, stateStore.Save(state))
|
||||
|
||||
return stateDB, state, store
|
||||
@@ -835,7 +819,7 @@ func stateAndStore(
|
||||
// mock block store
|
||||
|
||||
type mockBlockStore struct {
|
||||
config *cfg.Config
|
||||
cfg *config.Config
|
||||
params types.ConsensusParams
|
||||
chain []*types.Block
|
||||
commits []*types.Commit
|
||||
@@ -844,9 +828,9 @@ type mockBlockStore struct {
|
||||
}
|
||||
|
||||
// TODO: NewBlockStore(db.NewMemDB) ...
|
||||
func newMockBlockStore(t *testing.T, config *cfg.Config, params types.ConsensusParams) *mockBlockStore {
|
||||
func newMockBlockStore(t *testing.T, cfg *config.Config, params types.ConsensusParams) *mockBlockStore {
|
||||
return &mockBlockStore{
|
||||
config: config,
|
||||
cfg: cfg,
|
||||
params: params,
|
||||
t: t,
|
||||
}
|
||||
@@ -873,6 +857,8 @@ func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
|
||||
func (bs *mockBlockStore) LoadBlockPart(height int64, index int) *types.Part { return nil }
|
||||
func (bs *mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
|
||||
}
|
||||
func (bs *mockBlockStore) SaveBlockWithExtendedCommit(block *types.Block, blockParts *types.PartSet, seenExtCommit *types.ExtendedCommit) {
|
||||
}
|
||||
func (bs *mockBlockStore) LoadBlockCommit(height int64) *types.Commit {
|
||||
return bs.commits[height-1]
|
||||
}
|
||||
|
||||
+75
-8
@@ -2,6 +2,7 @@ package consensus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -1211,16 +1212,16 @@ func (cs *State) createProposalBlock() (*types.Block, error) {
|
||||
return nil, errors.New("entered createProposalBlock with privValidator being nil")
|
||||
}
|
||||
|
||||
var commit *types.Commit
|
||||
var lastExtCommit *types.ExtendedCommit
|
||||
switch {
|
||||
case cs.Height == cs.state.InitialHeight:
|
||||
// We're creating a proposal for the first block.
|
||||
// The commit is empty, but not nil.
|
||||
commit = types.NewCommit(0, 0, types.BlockID{}, nil)
|
||||
lastExtCommit = &types.ExtendedCommit{}
|
||||
|
||||
case cs.LastCommit.HasTwoThirdsMajority():
|
||||
// Make the commit from LastCommit
|
||||
commit = cs.LastCommit.MakeCommit()
|
||||
lastExtCommit = cs.LastCommit.MakeExtendedCommit()
|
||||
|
||||
default: // This shouldn't happen.
|
||||
return nil, errors.New("propose step; cannot propose anything without commit for the previous block")
|
||||
@@ -1234,7 +1235,7 @@ func (cs *State) createProposalBlock() (*types.Block, error) {
|
||||
|
||||
proposerAddr := cs.privValidatorPubKey.Address()
|
||||
|
||||
ret, err := cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes())
|
||||
ret, err := cs.blockExec.CreateProposalBlock(cs.Height, cs.state, lastExtCommit, proposerAddr, cs.LastCommit.GetVotes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -1656,9 +1657,12 @@ func (cs *State) finalizeCommit(height int64) {
|
||||
if cs.blockStore.Height() < block.Height {
|
||||
// NOTE: the seenCommit is local justification to commit this block,
|
||||
// but may differ from the LastCommit included in the next block
|
||||
precommits := cs.Votes.Precommits(cs.CommitRound)
|
||||
seenCommit := precommits.MakeCommit()
|
||||
cs.blockStore.SaveBlock(block, blockParts, seenCommit)
|
||||
seenExtendedCommit := cs.Votes.Precommits(cs.CommitRound).MakeExtendedCommit()
|
||||
if cs.state.ConsensusParams.ABCI.VoteExtensionsEnabled(block.Height) {
|
||||
cs.blockStore.SaveBlockWithExtendedCommit(block, blockParts, seenExtendedCommit)
|
||||
} else {
|
||||
cs.blockStore.SaveBlock(block, blockParts, seenExtendedCommit.ToCommit())
|
||||
}
|
||||
} else {
|
||||
// Happens during replay if we already saved the block but didn't commit
|
||||
logger.Debug("calling finalizeCommit on already stored block", "height", block.Height)
|
||||
@@ -1968,7 +1972,7 @@ func (cs *State) handleCompleteProposal(blockHeight int64) {
|
||||
// Update Valid* if we can.
|
||||
prevotes := cs.Votes.Prevotes(cs.Round)
|
||||
blockID, hasTwoThirds := prevotes.TwoThirdsMajority()
|
||||
if hasTwoThirds && !blockID.IsZero() && (cs.ValidRound < cs.Round) {
|
||||
if hasTwoThirds && !blockID.IsNil() && (cs.ValidRound < cs.Round) {
|
||||
if cs.ProposalBlock.HashesTo(blockID.Hash) {
|
||||
cs.Logger.Debug(
|
||||
"updating valid block to new proposal block",
|
||||
@@ -2099,6 +2103,48 @@ func (cs *State) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error
|
||||
return
|
||||
}
|
||||
|
||||
// Check to see if the chain is configured to extend votes.
|
||||
if cs.state.ConsensusParams.ABCI.VoteExtensionsEnabled(cs.Height) {
|
||||
// The chain is configured to extend votes, check that the vote is
|
||||
// not for a nil block and verify the extensions signature against the
|
||||
// corresponding public key.
|
||||
|
||||
var myAddr []byte
|
||||
if cs.privValidatorPubKey != nil {
|
||||
myAddr = cs.privValidatorPubKey.Address()
|
||||
}
|
||||
// Verify VoteExtension if precommit and not nil
|
||||
// https://github.com/tendermint/tendermint/issues/8487
|
||||
if vote.Type == tmproto.PrecommitType && !vote.BlockID.IsNil() &&
|
||||
!bytes.Equal(vote.ValidatorAddress, myAddr) { // Skip the VerifyVoteExtension call if the vote was issued by this validator.
|
||||
|
||||
// The core fields of the vote message were already validated in the
|
||||
// consensus reactor when the vote was received.
|
||||
// Here, we verify the signature of the vote extension included in the vote
|
||||
// message.
|
||||
_, val := cs.state.Validators.GetByIndex(vote.ValidatorIndex)
|
||||
if err := vote.VerifyExtension(cs.state.ChainID, val.PubKey); err != nil {
|
||||
return false, fmt.Errorf("invalid vote extension: %w; vote: %v", err, vote)
|
||||
}
|
||||
|
||||
err := cs.blockExec.VerifyVoteExtension(context.TODO(), vote)
|
||||
cs.metrics.MarkVoteExtensionReceived(err == nil)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("application rejected vote extension: %w", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Vote extensions are not enabled on the network.
|
||||
// strip the extension data from the vote in case any is present.
|
||||
//
|
||||
// TODO punish a peer if it sent a vote with an extension when the feature
|
||||
// is disabled on the network.
|
||||
// https://github.com/tendermint/tendermint/issues/8565
|
||||
if hadExtension := vote.StripExtension(); hadExtension {
|
||||
cs.Logger.Error("vote included extension data but vote extensions are not enabled; extension ignored", "peer", peerID)
|
||||
}
|
||||
}
|
||||
|
||||
height := cs.Height
|
||||
added, err = cs.Votes.AddVote(vote, peerID)
|
||||
if !added {
|
||||
@@ -2260,9 +2306,30 @@ func (cs *State) signVote(
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: header},
|
||||
}
|
||||
|
||||
if msgType == tmproto.PrecommitType && !vote.BlockID.IsNil() {
|
||||
// if the signedMessage type is for a non-nil precommit, add
|
||||
// VoteExtension
|
||||
if cs.state.ConsensusParams.ABCI.VoteExtensionsEnabled(cs.Height) {
|
||||
ext, err := cs.blockExec.ExtendVote(context.TODO(), vote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vote.Extension = ext
|
||||
}
|
||||
}
|
||||
|
||||
v := vote.ToProto()
|
||||
err := cs.privValidator.SignVote(cs.state.ChainID, v)
|
||||
vote.Signature = v.Signature
|
||||
// append the extension signature if expect it
|
||||
if msgType == tmproto.PrecommitType && !vote.BlockID.IsNil() &&
|
||||
cs.state.ConsensusParams.ABCI.VoteExtensionsEnabled(cs.Height) {
|
||||
// defensively check that the signer correctly signed the vote extension
|
||||
if len(v.ExtensionSignature) == 0 {
|
||||
panic(fmt.Sprintf("expected signer to sign vote extension but empty signature returned (%d/%d)", vote.Height, vote.Round))
|
||||
}
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
}
|
||||
vote.Timestamp = v.Timestamp
|
||||
|
||||
return vote, err
|
||||
|
||||
+584
-126
File diff suppressed because it is too large
Load Diff
+10
-6
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/evidence"
|
||||
"github.com/tendermint/tendermint/evidence/mocks"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
|
||||
@@ -207,7 +208,7 @@ func TestVerifyLightClientAttack_Equivocation(t *testing.T) {
|
||||
// except the last validator vote twice
|
||||
blockID := makeBlockID(conflictingHeader.Hash(), 1000, []byte("partshash"))
|
||||
voteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals)
|
||||
commit, err := types.MakeCommit(blockID, 10, 1, voteSet, conflictingPrivVals[:4], defaultEvidenceTime)
|
||||
commit, err := test.MakeCommitFromVoteSet(blockID, voteSet, conflictingPrivVals[:4], defaultEvidenceTime)
|
||||
require.NoError(t, err)
|
||||
ev := &types.LightClientAttackEvidence{
|
||||
ConflictingBlock: &types.LightBlock{
|
||||
@@ -225,8 +226,9 @@ func TestVerifyLightClientAttack_Equivocation(t *testing.T) {
|
||||
|
||||
trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash"))
|
||||
trustedVoteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals)
|
||||
trustedCommit, err := types.MakeCommit(trustedBlockID, 10, 1, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime)
|
||||
trustedExtCommit, err := test.MakeExtendedCommitFromVoteSet(trustedBlockID, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime)
|
||||
require.NoError(t, err)
|
||||
trustedCommit := trustedExtCommit.ToCommit()
|
||||
trustedSignedHeader := &types.SignedHeader{
|
||||
Header: trustedHeader,
|
||||
Commit: trustedCommit,
|
||||
@@ -291,7 +293,7 @@ func TestVerifyLightClientAttack_Amnesia(t *testing.T) {
|
||||
// except the last validator vote twice. However this time the commits are of different rounds.
|
||||
blockID := makeBlockID(conflictingHeader.Hash(), 1000, []byte("partshash"))
|
||||
voteSet := types.NewVoteSet(evidenceChainID, 10, 0, tmproto.SignedMsgType(2), conflictingVals)
|
||||
commit, err := types.MakeCommit(blockID, 10, 0, voteSet, conflictingPrivVals, defaultEvidenceTime)
|
||||
commit, err := test.MakeCommitFromVoteSet(blockID, voteSet, conflictingPrivVals, defaultEvidenceTime)
|
||||
require.NoError(t, err)
|
||||
ev := &types.LightClientAttackEvidence{
|
||||
ConflictingBlock: &types.LightBlock{
|
||||
@@ -309,7 +311,7 @@ func TestVerifyLightClientAttack_Amnesia(t *testing.T) {
|
||||
|
||||
trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash"))
|
||||
trustedVoteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals)
|
||||
trustedCommit, err := types.MakeCommit(trustedBlockID, 10, 1, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime)
|
||||
trustedCommit, err := test.MakeCommitFromVoteSet(trustedBlockID, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime)
|
||||
require.NoError(t, err)
|
||||
trustedSignedHeader := &types.SignedHeader{
|
||||
Header: trustedHeader,
|
||||
@@ -483,8 +485,10 @@ func makeLunaticEvidence(
|
||||
|
||||
blockID := makeBlockID(conflictingHeader.Hash(), 1000, []byte("partshash"))
|
||||
voteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), conflictingVals)
|
||||
commit, err := types.MakeCommit(blockID, height, 1, voteSet, conflictingPrivVals, defaultEvidenceTime)
|
||||
extCommit, err := test.MakeExtendedCommitFromVoteSet(blockID, voteSet, conflictingPrivVals, defaultEvidenceTime)
|
||||
require.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
|
||||
ev = &types.LightClientAttackEvidence{
|
||||
ConflictingBlock: &types.LightBlock{
|
||||
SignedHeader: &types.SignedHeader{
|
||||
@@ -510,7 +514,7 @@ func makeLunaticEvidence(
|
||||
trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash"))
|
||||
trustedVals, privVals := types.RandValidatorSet(totalVals, defaultVotingPower)
|
||||
trustedVoteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), trustedVals)
|
||||
trustedCommit, err := types.MakeCommit(trustedBlockID, height, 1, trustedVoteSet, privVals, defaultEvidenceTime)
|
||||
trustedCommit, err := test.MakeCommitFromVoteSet(trustedBlockID, trustedVoteSet, privVals, defaultEvidenceTime)
|
||||
require.NoError(t, err)
|
||||
trusted = &types.LightBlock{
|
||||
SignedHeader: &types.SignedHeader{
|
||||
|
||||
@@ -53,7 +53,7 @@ func MakeHeader(t *testing.T, h *types.Header) *types.Header {
|
||||
if h.Height == 0 {
|
||||
h.Height = 1
|
||||
}
|
||||
if h.LastBlockID.IsZero() {
|
||||
if h.LastBlockID.IsNil() {
|
||||
h.LastBlockID = MakeBlockID()
|
||||
}
|
||||
if h.ChainID == "" {
|
||||
|
||||
+11
-2
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func MakeCommitFromVoteSet(blockID types.BlockID, voteSet *types.VoteSet, validators []types.PrivValidator, now time.Time) (*types.Commit, error) {
|
||||
func MakeExtendedCommitFromVoteSet(blockID types.BlockID, voteSet *types.VoteSet, validators []types.PrivValidator, now time.Time) (*types.ExtendedCommit, error) {
|
||||
// all sign
|
||||
for i := 0; i < len(validators); i++ {
|
||||
pubKey, err := validators[i].GetPubKey()
|
||||
@@ -32,12 +32,21 @@ func MakeCommitFromVoteSet(blockID types.BlockID, voteSet *types.VoteSet, valida
|
||||
return nil, err
|
||||
}
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
if _, err := voteSet.AddVote(vote); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return voteSet.MakeCommit(), nil
|
||||
return voteSet.MakeExtendedCommit(), nil
|
||||
}
|
||||
|
||||
func MakeCommitFromVoteSet(blockID types.BlockID, voteSet *types.VoteSet, validators []types.PrivValidator, now time.Time) (*types.Commit, error) {
|
||||
extCommit, err := MakeExtendedCommitFromVoteSet(blockID, voteSet, validators, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return extCommit.ToCommit(), nil
|
||||
}
|
||||
|
||||
func MakeVoteSet(lastState sm.State, round int32) *types.VoteSet {
|
||||
|
||||
@@ -3,16 +3,25 @@ package test
|
||||
import (
|
||||
"time"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func ConsensusParams() *types.ConsensusParams {
|
||||
c := types.DefaultConsensusParams()
|
||||
// enable vote extensions
|
||||
c.ABCI.VoteExtensionsEnableHeight = 1
|
||||
return c
|
||||
}
|
||||
|
||||
func GenesisDoc(
|
||||
config *cfg.Config,
|
||||
chainID string,
|
||||
time time.Time,
|
||||
validators []*types.Validator,
|
||||
consensusParams *types.ConsensusParams,
|
||||
) *types.GenesisDoc {
|
||||
if chainID == "" {
|
||||
chainID = DefaultTestChainID
|
||||
}
|
||||
|
||||
genesisValidators := make([]types.GenesisValidator, len(validators))
|
||||
|
||||
@@ -26,7 +35,7 @@ func GenesisDoc(
|
||||
return &types.GenesisDoc{
|
||||
GenesisTime: time,
|
||||
InitialHeight: 1,
|
||||
ChainID: config.ChainID(),
|
||||
ChainID: chainID,
|
||||
Validators: genesisValidators,
|
||||
ConsensusParams: consensusParams,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
@@ -10,7 +9,7 @@ import (
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func Validator(ctx context.Context, votingPower int64) (*types.Validator, types.PrivValidator, error) {
|
||||
func Validator(votingPower int64) (*types.Validator, types.PrivValidator, error) {
|
||||
privVal := types.NewMockPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
if err != nil {
|
||||
@@ -21,7 +20,7 @@ func Validator(ctx context.Context, votingPower int64) (*types.Validator, types.
|
||||
return val, privVal, nil
|
||||
}
|
||||
|
||||
func ValidatorSet(ctx context.Context, t *testing.T, numValidators int, votingPower int64) (*types.ValidatorSet, []types.PrivValidator) {
|
||||
func ValidatorSet(t *testing.T, numValidators int, votingPower int64) (*types.ValidatorSet, []types.PrivValidator) {
|
||||
var (
|
||||
valz = make([]*types.Validator, numValidators)
|
||||
privValidators = make([]types.PrivValidator, numValidators)
|
||||
@@ -29,7 +28,7 @@ func ValidatorSet(ctx context.Context, t *testing.T, numValidators int, votingPo
|
||||
t.Helper()
|
||||
|
||||
for i := 0; i < numValidators; i++ {
|
||||
val, privValidator, err := Validator(ctx, votingPower)
|
||||
val, privValidator, err := Validator(votingPower)
|
||||
require.NoError(t, err)
|
||||
valz[i] = val
|
||||
privValidators[i] = privValidator
|
||||
|
||||
+6
-4
@@ -307,10 +307,11 @@ func TestCreateProposalBlock(t *testing.T) {
|
||||
evidencePool,
|
||||
)
|
||||
|
||||
commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
|
||||
extCommit := &types.ExtendedCommit{Height: height - 1}
|
||||
block, err := blockExec.CreateProposalBlock(
|
||||
height,
|
||||
state, commit,
|
||||
state,
|
||||
extCommit,
|
||||
proposerAddr,
|
||||
nil,
|
||||
)
|
||||
@@ -390,10 +391,11 @@ func TestMaxProposalBlockSize(t *testing.T) {
|
||||
sm.EmptyEvidencePool{},
|
||||
)
|
||||
|
||||
commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
|
||||
extCommit := &types.ExtendedCommit{Height: height - 1}
|
||||
block, err := blockExec.CreateProposalBlock(
|
||||
height,
|
||||
state, commit,
|
||||
state,
|
||||
extCommit,
|
||||
proposerAddr,
|
||||
nil,
|
||||
)
|
||||
|
||||
+56
-22
@@ -82,6 +82,14 @@ type FilePVLastSignState struct {
|
||||
filePath string
|
||||
}
|
||||
|
||||
func (lss *FilePVLastSignState) reset() {
|
||||
lss.Height = 0
|
||||
lss.Round = 0
|
||||
lss.Step = 0
|
||||
lss.Signature = nil
|
||||
lss.SignBytes = nil
|
||||
}
|
||||
|
||||
// CheckHRS checks the given height, round, step (HRS) against that of the
|
||||
// FilePVLastSignState. It returns an error if the arguments constitute a regression,
|
||||
// or if they match but the SignBytes are empty.
|
||||
@@ -124,7 +132,7 @@ func (lss *FilePVLastSignState) CheckHRS(height int64, round int32, step int8) (
|
||||
}
|
||||
|
||||
// Save persists the FilePvLastSignState to its filePath.
|
||||
func (lss *FilePVLastSignState) Save() {
|
||||
func (lss *FilePVLastSignState) Save() error {
|
||||
outFile := lss.filePath
|
||||
if outFile == "" {
|
||||
panic("cannot save FilePVLastSignState: filePath not set")
|
||||
@@ -133,10 +141,7 @@ func (lss *FilePVLastSignState) Save() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = tempfile.WriteFileAtomic(outFile, jsonBytes, 0600)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tempfile.WriteFileAtomic(outFile, jsonBytes, 0600)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
@@ -276,12 +281,7 @@ func (pv *FilePV) Save() {
|
||||
// Reset resets all fields in the FilePV.
|
||||
// NOTE: Unsafe!
|
||||
func (pv *FilePV) Reset() {
|
||||
var sig []byte
|
||||
pv.LastSignState.Height = 0
|
||||
pv.LastSignState.Round = 0
|
||||
pv.LastSignState.Step = 0
|
||||
pv.LastSignState.Signature = sig
|
||||
pv.LastSignState.SignBytes = nil
|
||||
pv.LastSignState.reset()
|
||||
pv.Save()
|
||||
}
|
||||
|
||||
@@ -301,6 +301,7 @@ func (pv *FilePV) String() string {
|
||||
// signVote checks if the vote is good to sign and sets the vote signature.
|
||||
// It may need to set the timestamp as well if the vote is otherwise the same as
|
||||
// a previously signed vote (ie. we crashed after signing but before the vote hit the WAL).
|
||||
// extension signatures are aways signed for non-nil precommits (even if the data is empty)
|
||||
func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
|
||||
height, round, step := vote.Height, vote.Round, voteToStep(vote)
|
||||
|
||||
@@ -313,6 +314,22 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
|
||||
|
||||
signBytes := types.VoteSignBytes(chainID, vote)
|
||||
|
||||
// Vote extensions are non-deterministic, so it is possible that an
|
||||
// application may have created a different extension. We therefore always
|
||||
// re-sign the vote extensions of precommits. For prevotes and nil
|
||||
// precommits, the extension signature will always be empty.
|
||||
// Even if the signed over data is empty, we still add the signature
|
||||
var extSig []byte
|
||||
if vote.Type == tmproto.PrecommitType && !types.IsProtoBlockIDNil(&vote.BlockID) {
|
||||
extSignBytes := types.VoteExtensionSignBytes(chainID, vote)
|
||||
extSig, err = pv.Key.PrivKey.Sign(extSignBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(vote.Extension) > 0 {
|
||||
return errors.New("unexpected vote extension - extensions are only allowed in non-nil precommits")
|
||||
}
|
||||
|
||||
// We might crash before writing to the wal,
|
||||
// causing us to try to re-sign for the same HRS.
|
||||
// If signbytes are the same, use the last signature.
|
||||
@@ -321,13 +338,24 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
|
||||
if sameHRS {
|
||||
if bytes.Equal(signBytes, lss.SignBytes) {
|
||||
vote.Signature = lss.Signature
|
||||
} else if timestamp, ok := checkVotesOnlyDifferByTimestamp(lss.SignBytes, signBytes); ok {
|
||||
} else {
|
||||
// Compares the canonicalized votes (i.e. without vote extensions
|
||||
// or vote extension signatures).
|
||||
timestamp, ok, err := checkVotesOnlyDifferByTimestamp(lss.SignBytes, signBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("conflicting data")
|
||||
}
|
||||
|
||||
vote.Timestamp = timestamp
|
||||
vote.Signature = lss.Signature
|
||||
} else {
|
||||
err = fmt.Errorf("conflicting data")
|
||||
}
|
||||
return err
|
||||
|
||||
vote.ExtensionSignature = extSig
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// It passed the checks. Sign the vote
|
||||
@@ -335,8 +363,14 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pv.saveSigned(height, round, step, signBytes, sig)
|
||||
|
||||
if err := pv.saveSigned(height, round, step, signBytes, sig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vote.Signature = sig
|
||||
vote.ExtensionSignature = extSig
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -384,27 +418,27 @@ func (pv *FilePV) signProposal(chainID string, proposal *tmproto.Proposal) error
|
||||
|
||||
// Persist height/round/step and signature
|
||||
func (pv *FilePV) saveSigned(height int64, round int32, step int8,
|
||||
signBytes []byte, sig []byte) {
|
||||
signBytes []byte, sig []byte) error {
|
||||
|
||||
pv.LastSignState.Height = height
|
||||
pv.LastSignState.Round = round
|
||||
pv.LastSignState.Step = step
|
||||
pv.LastSignState.Signature = sig
|
||||
pv.LastSignState.SignBytes = signBytes
|
||||
pv.LastSignState.Save()
|
||||
return pv.LastSignState.Save()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
// returns the timestamp from the lastSignBytes.
|
||||
// returns true if the only difference in the votes is their timestamp.
|
||||
func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
|
||||
func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool, error) {
|
||||
var lastVote, newVote tmproto.CanonicalVote
|
||||
if err := protoio.UnmarshalDelimited(lastSignBytes, &lastVote); err != nil {
|
||||
panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into vote: %v", err))
|
||||
return time.Time{}, false, fmt.Errorf("LastSignBytes cannot be unmarshalled into vote: %w", err)
|
||||
}
|
||||
if err := protoio.UnmarshalDelimited(newSignBytes, &newVote); err != nil {
|
||||
panic(fmt.Sprintf("signBytes cannot be unmarshalled into vote: %v", err))
|
||||
return time.Time{}, false, fmt.Errorf("signBytes cannot be unmarshalled into vote: %w", err)
|
||||
}
|
||||
|
||||
lastTime := lastVote.Timestamp
|
||||
@@ -413,7 +447,7 @@ func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.T
|
||||
lastVote.Timestamp = now
|
||||
newVote.Timestamp = now
|
||||
|
||||
return lastTime, proto.Equal(&newVote, &lastVote)
|
||||
return lastTime, proto.Equal(&newVote, &lastVote), nil
|
||||
}
|
||||
|
||||
// returns the timestamp from the lastSignBytes.
|
||||
|
||||
@@ -308,48 +308,121 @@ func (m *CanonicalVote) GetChainID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// CanonicalVoteExtension provides us a way to serialize a vote extension from
|
||||
// a particular validator such that we can sign over those serialized bytes.
|
||||
type CanonicalVoteExtension struct {
|
||||
Extension []byte `protobuf:"bytes,1,opt,name=extension,proto3" json:"extension,omitempty"`
|
||||
Height int64 `protobuf:"fixed64,2,opt,name=height,proto3" json:"height,omitempty"`
|
||||
Round int64 `protobuf:"fixed64,3,opt,name=round,proto3" json:"round,omitempty"`
|
||||
ChainId string `protobuf:"bytes,4,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
|
||||
}
|
||||
|
||||
func (m *CanonicalVoteExtension) Reset() { *m = CanonicalVoteExtension{} }
|
||||
func (m *CanonicalVoteExtension) String() string { return proto.CompactTextString(m) }
|
||||
func (*CanonicalVoteExtension) ProtoMessage() {}
|
||||
func (*CanonicalVoteExtension) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_8d1a1a84ff7267ed, []int{4}
|
||||
}
|
||||
func (m *CanonicalVoteExtension) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *CanonicalVoteExtension) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_CanonicalVoteExtension.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 *CanonicalVoteExtension) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CanonicalVoteExtension.Merge(m, src)
|
||||
}
|
||||
func (m *CanonicalVoteExtension) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *CanonicalVoteExtension) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CanonicalVoteExtension.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CanonicalVoteExtension proto.InternalMessageInfo
|
||||
|
||||
func (m *CanonicalVoteExtension) GetExtension() []byte {
|
||||
if m != nil {
|
||||
return m.Extension
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CanonicalVoteExtension) GetHeight() int64 {
|
||||
if m != nil {
|
||||
return m.Height
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *CanonicalVoteExtension) GetRound() int64 {
|
||||
if m != nil {
|
||||
return m.Round
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *CanonicalVoteExtension) GetChainId() string {
|
||||
if m != nil {
|
||||
return m.ChainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*CanonicalBlockID)(nil), "tendermint.types.CanonicalBlockID")
|
||||
proto.RegisterType((*CanonicalPartSetHeader)(nil), "tendermint.types.CanonicalPartSetHeader")
|
||||
proto.RegisterType((*CanonicalProposal)(nil), "tendermint.types.CanonicalProposal")
|
||||
proto.RegisterType((*CanonicalVote)(nil), "tendermint.types.CanonicalVote")
|
||||
proto.RegisterType((*CanonicalVoteExtension)(nil), "tendermint.types.CanonicalVoteExtension")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("tendermint/types/canonical.proto", fileDescriptor_8d1a1a84ff7267ed) }
|
||||
|
||||
var fileDescriptor_8d1a1a84ff7267ed = []byte{
|
||||
// 487 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x53, 0x3d, 0x6f, 0xd3, 0x40,
|
||||
0x18, 0xce, 0xa5, 0x4e, 0xe2, 0x5c, 0x1b, 0x08, 0xa7, 0xaa, 0xb2, 0x22, 0x64, 0x5b, 0x1e, 0x90,
|
||||
0x59, 0x6c, 0xa9, 0x1d, 0xd8, 0x5d, 0x06, 0x82, 0x40, 0x94, 0x6b, 0xd5, 0x81, 0x25, 0xba, 0xd8,
|
||||
0x87, 0x6d, 0xe1, 0xf8, 0x4e, 0xf6, 0x65, 0xe8, 0xc2, 0x6f, 0xe8, 0xef, 0xe0, 0x97, 0x74, 0xec,
|
||||
0x08, 0x4b, 0x40, 0xce, 0x1f, 0x41, 0x77, 0x4e, 0xec, 0xa8, 0x01, 0x16, 0x10, 0xcb, 0xe9, 0xfd,
|
||||
0x78, 0xee, 0x79, 0x1f, 0x3d, 0xaf, 0x5e, 0x68, 0x0b, 0x9a, 0x47, 0xb4, 0x58, 0xa4, 0xb9, 0xf0,
|
||||
0xc5, 0x0d, 0xa7, 0xa5, 0x1f, 0x92, 0x9c, 0xe5, 0x69, 0x48, 0x32, 0x8f, 0x17, 0x4c, 0x30, 0x34,
|
||||
0x6e, 0x11, 0x9e, 0x42, 0x4c, 0x8e, 0x63, 0x16, 0x33, 0xd5, 0xf4, 0x65, 0x54, 0xe3, 0x26, 0x4f,
|
||||
0xf7, 0x98, 0xd4, 0xbb, 0xe9, 0x5a, 0x31, 0x63, 0x71, 0x46, 0x7d, 0x95, 0xcd, 0x97, 0x1f, 0x7d,
|
||||
0x91, 0x2e, 0x68, 0x29, 0xc8, 0x82, 0xd7, 0x00, 0xe7, 0x33, 0x1c, 0x9f, 0x6f, 0x27, 0x07, 0x19,
|
||||
0x0b, 0x3f, 0x4d, 0x5f, 0x22, 0x04, 0xb5, 0x84, 0x94, 0x89, 0x01, 0x6c, 0xe0, 0x1e, 0x61, 0x15,
|
||||
0xa3, 0x6b, 0xf8, 0x98, 0x93, 0x42, 0xcc, 0x4a, 0x2a, 0x66, 0x09, 0x25, 0x11, 0x2d, 0x8c, 0xae,
|
||||
0x0d, 0xdc, 0xc3, 0x53, 0xd7, 0x7b, 0x28, 0xd4, 0x6b, 0x08, 0x2f, 0x48, 0x21, 0x2e, 0xa9, 0x78,
|
||||
0xa5, 0xf0, 0x81, 0x76, 0xb7, 0xb2, 0x3a, 0x78, 0xc4, 0x77, 0x8b, 0x4e, 0x00, 0x4f, 0x7e, 0x0d,
|
||||
0x47, 0xc7, 0xb0, 0x27, 0x98, 0x20, 0x99, 0x92, 0x31, 0xc2, 0x75, 0xd2, 0x68, 0xeb, 0xb6, 0xda,
|
||||
0x9c, 0x6f, 0x5d, 0xf8, 0xa4, 0x25, 0x29, 0x18, 0x67, 0x25, 0xc9, 0xd0, 0x19, 0xd4, 0xa4, 0x1c,
|
||||
0xf5, 0xfd, 0xd1, 0xa9, 0xb5, 0x2f, 0xf3, 0x32, 0x8d, 0x73, 0x1a, 0xbd, 0x2d, 0xe3, 0xab, 0x1b,
|
||||
0x4e, 0xb1, 0x02, 0xa3, 0x13, 0xd8, 0x4f, 0x68, 0x1a, 0x27, 0x42, 0x0d, 0x18, 0xe3, 0x4d, 0x26,
|
||||
0xc5, 0x14, 0x6c, 0x99, 0x47, 0xc6, 0x81, 0x2a, 0xd7, 0x09, 0x7a, 0x0e, 0x87, 0x9c, 0x65, 0xb3,
|
||||
0xba, 0xa3, 0xd9, 0xc0, 0x3d, 0x08, 0x8e, 0xaa, 0x95, 0xa5, 0x5f, 0xbc, 0x7b, 0x83, 0x65, 0x0d,
|
||||
0xeb, 0x9c, 0x65, 0x2a, 0x42, 0xaf, 0xa1, 0x3e, 0x97, 0xf6, 0xce, 0xd2, 0xc8, 0xe8, 0x29, 0xe3,
|
||||
0x9c, 0x3f, 0x18, 0xb7, 0xd9, 0x44, 0x70, 0x58, 0xad, 0xac, 0xc1, 0x26, 0xc1, 0x03, 0x45, 0x30,
|
||||
0x8d, 0x50, 0x00, 0x87, 0xcd, 0x1a, 0x8d, 0xbe, 0x22, 0x9b, 0x78, 0xf5, 0xa2, 0xbd, 0xed, 0xa2,
|
||||
0xbd, 0xab, 0x2d, 0x22, 0xd0, 0xa5, 0xef, 0xb7, 0xdf, 0x2d, 0x80, 0xdb, 0x6f, 0xe8, 0x19, 0xd4,
|
||||
0xc3, 0x84, 0xa4, 0xb9, 0xd4, 0x33, 0xb0, 0x81, 0x3b, 0xac, 0x67, 0x9d, 0xcb, 0x9a, 0x9c, 0xa5,
|
||||
0x9a, 0xd3, 0xc8, 0xf9, 0xd2, 0x85, 0xa3, 0x46, 0xd6, 0x35, 0x13, 0xf4, 0x7f, 0xf8, 0xba, 0x6b,
|
||||
0x96, 0xf6, 0x2f, 0xcd, 0xea, 0xfd, 0xbd, 0x59, 0xfd, 0xdf, 0x9b, 0x15, 0xbc, 0xbf, 0xab, 0x4c,
|
||||
0x70, 0x5f, 0x99, 0xe0, 0x47, 0x65, 0x82, 0xdb, 0xb5, 0xd9, 0xb9, 0x5f, 0x9b, 0x9d, 0xaf, 0x6b,
|
||||
0xb3, 0xf3, 0xe1, 0x45, 0x9c, 0x8a, 0x64, 0x39, 0xf7, 0x42, 0xb6, 0xf0, 0x77, 0x0f, 0xb6, 0x0d,
|
||||
0xeb, 0xc3, 0x7e, 0x78, 0xcc, 0xf3, 0xbe, 0xaa, 0x9f, 0xfd, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x6d,
|
||||
0xdd, 0x12, 0x5d, 0x31, 0x04, 0x00, 0x00,
|
||||
// 523 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0xc1, 0x6e, 0xd3, 0x40,
|
||||
0x10, 0x8d, 0x53, 0x27, 0xb1, 0xb7, 0x0d, 0x84, 0x55, 0x55, 0x99, 0xa8, 0xb2, 0x2d, 0x1f, 0x90,
|
||||
0xb9, 0xd8, 0x52, 0x7b, 0xe0, 0xee, 0x82, 0x44, 0x10, 0x88, 0xe2, 0x56, 0x3d, 0x70, 0x89, 0x36,
|
||||
0xf6, 0x62, 0x5b, 0x38, 0xde, 0x95, 0xbd, 0x91, 0xe8, 0x05, 0x7e, 0xa1, 0xdf, 0xc1, 0x97, 0xf4,
|
||||
0xd8, 0x23, 0x5c, 0x02, 0x72, 0x7e, 0x04, 0xed, 0xda, 0xb1, 0xad, 0x16, 0x55, 0x42, 0x20, 0x2e,
|
||||
0xd1, 0xcc, 0x9b, 0xb7, 0x33, 0x4f, 0x6f, 0xe2, 0x01, 0x26, 0xc3, 0x59, 0x88, 0xf3, 0x65, 0x92,
|
||||
0x31, 0x97, 0x5d, 0x52, 0x5c, 0xb8, 0x01, 0xca, 0x48, 0x96, 0x04, 0x28, 0x75, 0x68, 0x4e, 0x18,
|
||||
0x81, 0x93, 0x96, 0xe1, 0x08, 0xc6, 0x74, 0x3f, 0x22, 0x11, 0x11, 0x45, 0x97, 0x47, 0x15, 0x6f,
|
||||
0x7a, 0x78, 0xa7, 0x93, 0xf8, 0xad, 0xab, 0x46, 0x44, 0x48, 0x94, 0x62, 0x57, 0x64, 0x8b, 0xd5,
|
||||
0x07, 0x97, 0x25, 0x4b, 0x5c, 0x30, 0xb4, 0xa4, 0x15, 0xc1, 0xfa, 0x0c, 0x26, 0x27, 0xdb, 0xc9,
|
||||
0x5e, 0x4a, 0x82, 0x8f, 0xb3, 0xe7, 0x10, 0x02, 0x39, 0x46, 0x45, 0xac, 0x49, 0xa6, 0x64, 0xef,
|
||||
0xf9, 0x22, 0x86, 0x17, 0xe0, 0x21, 0x45, 0x39, 0x9b, 0x17, 0x98, 0xcd, 0x63, 0x8c, 0x42, 0x9c,
|
||||
0x6b, 0x7d, 0x53, 0xb2, 0x77, 0x8f, 0x6c, 0xe7, 0xb6, 0x50, 0xa7, 0x69, 0x78, 0x8a, 0x72, 0x76,
|
||||
0x86, 0xd9, 0x4b, 0xc1, 0xf7, 0xe4, 0xeb, 0xb5, 0xd1, 0xf3, 0xc7, 0xb4, 0x0b, 0x5a, 0x1e, 0x38,
|
||||
0xf8, 0x3d, 0x1d, 0xee, 0x83, 0x01, 0x23, 0x0c, 0xa5, 0x42, 0xc6, 0xd8, 0xaf, 0x92, 0x46, 0x5b,
|
||||
0xbf, 0xd5, 0x66, 0x7d, 0xef, 0x83, 0x47, 0x6d, 0x93, 0x9c, 0x50, 0x52, 0xa0, 0x14, 0x1e, 0x03,
|
||||
0x99, 0xcb, 0x11, 0xcf, 0x1f, 0x1c, 0x19, 0x77, 0x65, 0x9e, 0x25, 0x51, 0x86, 0xc3, 0x37, 0x45,
|
||||
0x74, 0x7e, 0x49, 0xb1, 0x2f, 0xc8, 0xf0, 0x00, 0x0c, 0x63, 0x9c, 0x44, 0x31, 0x13, 0x03, 0x26,
|
||||
0x7e, 0x9d, 0x71, 0x31, 0x39, 0x59, 0x65, 0xa1, 0xb6, 0x23, 0xe0, 0x2a, 0x81, 0x4f, 0x81, 0x4a,
|
||||
0x49, 0x3a, 0xaf, 0x2a, 0xb2, 0x29, 0xd9, 0x3b, 0xde, 0x5e, 0xb9, 0x36, 0x94, 0xd3, 0xb7, 0xaf,
|
||||
0x7d, 0x8e, 0xf9, 0x0a, 0x25, 0xa9, 0x88, 0xe0, 0x2b, 0xa0, 0x2c, 0xb8, 0xbd, 0xf3, 0x24, 0xd4,
|
||||
0x06, 0xc2, 0x38, 0xeb, 0x1e, 0xe3, 0xea, 0x4d, 0x78, 0xbb, 0xe5, 0xda, 0x18, 0xd5, 0x89, 0x3f,
|
||||
0x12, 0x0d, 0x66, 0x21, 0xf4, 0x80, 0xda, 0xac, 0x51, 0x1b, 0x8a, 0x66, 0x53, 0xa7, 0x5a, 0xb4,
|
||||
0xb3, 0x5d, 0xb4, 0x73, 0xbe, 0x65, 0x78, 0x0a, 0xf7, 0xfd, 0xea, 0x87, 0x21, 0xf9, 0xed, 0x33,
|
||||
0xf8, 0x04, 0x28, 0x41, 0x8c, 0x92, 0x8c, 0xeb, 0x19, 0x99, 0x92, 0xad, 0x56, 0xb3, 0x4e, 0x38,
|
||||
0xc6, 0x67, 0x89, 0xe2, 0x2c, 0xb4, 0xbe, 0xf6, 0xc1, 0xb8, 0x91, 0x75, 0x41, 0x18, 0xfe, 0x1f,
|
||||
0xbe, 0x76, 0xcd, 0x92, 0xff, 0xa5, 0x59, 0x83, 0xbf, 0x37, 0x6b, 0x78, 0x8f, 0x59, 0x5f, 0x3a,
|
||||
0x7f, 0x66, 0xee, 0xd5, 0x8b, 0x4f, 0x0c, 0x67, 0x45, 0x42, 0x32, 0x78, 0x08, 0x54, 0xbc, 0x4d,
|
||||
0xea, 0xef, 0xaa, 0x05, 0xfe, 0xd0, 0x9d, 0xc7, 0x1d, 0x35, 0xdc, 0x1d, 0xb5, 0x11, 0xe0, 0xbd,
|
||||
0xbb, 0x2e, 0x75, 0xe9, 0xa6, 0xd4, 0xa5, 0x9f, 0xa5, 0x2e, 0x5d, 0x6d, 0xf4, 0xde, 0xcd, 0x46,
|
||||
0xef, 0x7d, 0xdb, 0xe8, 0xbd, 0xf7, 0xcf, 0xa2, 0x84, 0xc5, 0xab, 0x85, 0x13, 0x90, 0xa5, 0xdb,
|
||||
0xbd, 0x18, 0x6d, 0x58, 0x5d, 0x96, 0xdb, 0xd7, 0x64, 0x31, 0x14, 0xf8, 0xf1, 0xaf, 0x00, 0x00,
|
||||
0x00, 0xff, 0xff, 0x2b, 0x89, 0x89, 0x5b, 0xb2, 0x04, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *CanonicalBlockID) Marshal() (dAtA []byte, err error) {
|
||||
@@ -566,6 +639,55 @@ func (m *CanonicalVote) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *CanonicalVoteExtension) 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 *CanonicalVoteExtension) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *CanonicalVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.ChainId) > 0 {
|
||||
i -= len(m.ChainId)
|
||||
copy(dAtA[i:], m.ChainId)
|
||||
i = encodeVarintCanonical(dAtA, i, uint64(len(m.ChainId)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
if m.Round != 0 {
|
||||
i -= 8
|
||||
encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.Round))
|
||||
i--
|
||||
dAtA[i] = 0x19
|
||||
}
|
||||
if m.Height != 0 {
|
||||
i -= 8
|
||||
encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.Height))
|
||||
i--
|
||||
dAtA[i] = 0x11
|
||||
}
|
||||
if len(m.Extension) > 0 {
|
||||
i -= len(m.Extension)
|
||||
copy(dAtA[i:], m.Extension)
|
||||
i = encodeVarintCanonical(dAtA, i, uint64(len(m.Extension)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintCanonical(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovCanonical(v)
|
||||
base := offset
|
||||
@@ -667,6 +789,29 @@ func (m *CanonicalVote) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *CanonicalVoteExtension) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Extension)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovCanonical(uint64(l))
|
||||
}
|
||||
if m.Height != 0 {
|
||||
n += 9
|
||||
}
|
||||
if m.Round != 0 {
|
||||
n += 9
|
||||
}
|
||||
l = len(m.ChainId)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovCanonical(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovCanonical(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
@@ -1292,6 +1437,142 @@ func (m *CanonicalVote) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *CanonicalVoteExtension) 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 ErrIntOverflowCanonical
|
||||
}
|
||||
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: CanonicalVoteExtension: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: CanonicalVoteExtension: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Extension", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCanonical
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Extension = append(m.Extension[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Extension == nil {
|
||||
m.Extension = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 1 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType)
|
||||
}
|
||||
m.Height = 0
|
||||
if (iNdEx + 8) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Height = int64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:]))
|
||||
iNdEx += 8
|
||||
case 3:
|
||||
if wireType != 1 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Round", wireType)
|
||||
}
|
||||
m.Round = 0
|
||||
if (iNdEx + 8) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Round = int64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:]))
|
||||
iNdEx += 8
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCanonical
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ChainId = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipCanonical(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipCanonical(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
||||
@@ -35,3 +35,12 @@ message CanonicalVote {
|
||||
google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
string chain_id = 6 [(gogoproto.customname) = "ChainID"];
|
||||
}
|
||||
|
||||
// CanonicalVoteExtension provides us a way to serialize a vote extension from
|
||||
// a particular validator such that we can sign over those serialized bytes.
|
||||
message CanonicalVoteExtension {
|
||||
bytes extension = 1;
|
||||
sfixed64 height = 2;
|
||||
sfixed64 round = 3;
|
||||
string chain_id = 4;
|
||||
}
|
||||
+375
-121
@@ -34,6 +34,7 @@ type ConsensusParams struct {
|
||||
Evidence *EvidenceParams `protobuf:"bytes,2,opt,name=evidence,proto3" json:"evidence,omitempty"`
|
||||
Validator *ValidatorParams `protobuf:"bytes,3,opt,name=validator,proto3" json:"validator,omitempty"`
|
||||
Version *VersionParams `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Abci *ABCIParams `protobuf:"bytes,5,opt,name=abci,proto3" json:"abci,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ConsensusParams) Reset() { *m = ConsensusParams{} }
|
||||
@@ -97,6 +98,68 @@ func (m *ConsensusParams) GetVersion() *VersionParams {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ConsensusParams) GetAbci() *ABCIParams {
|
||||
if m != nil {
|
||||
return m.Abci
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HashedParams is a subset of ConsensusParams.
|
||||
//
|
||||
// It is hashed into the Header.ConsensusHash.
|
||||
type HashedParams struct {
|
||||
BlockMaxBytes int64 `protobuf:"varint,1,opt,name=block_max_bytes,json=blockMaxBytes,proto3" json:"block_max_bytes,omitempty"`
|
||||
BlockMaxGas int64 `protobuf:"varint,2,opt,name=block_max_gas,json=blockMaxGas,proto3" json:"block_max_gas,omitempty"`
|
||||
}
|
||||
|
||||
func (m *HashedParams) Reset() { *m = HashedParams{} }
|
||||
func (m *HashedParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*HashedParams) ProtoMessage() {}
|
||||
func (*HashedParams) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_e12598271a686f57, []int{1}
|
||||
}
|
||||
func (m *HashedParams) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *HashedParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_HashedParams.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 *HashedParams) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HashedParams.Merge(m, src)
|
||||
}
|
||||
func (m *HashedParams) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *HashedParams) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HashedParams.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HashedParams proto.InternalMessageInfo
|
||||
|
||||
func (m *HashedParams) GetBlockMaxBytes() int64 {
|
||||
if m != nil {
|
||||
return m.BlockMaxBytes
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *HashedParams) GetBlockMaxGas() int64 {
|
||||
if m != nil {
|
||||
return m.BlockMaxGas
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// BlockParams contains limits on the block size.
|
||||
type BlockParams struct {
|
||||
// Max block size, in bytes.
|
||||
@@ -111,7 +174,7 @@ func (m *BlockParams) Reset() { *m = BlockParams{} }
|
||||
func (m *BlockParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*BlockParams) ProtoMessage() {}
|
||||
func (*BlockParams) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_e12598271a686f57, []int{1}
|
||||
return fileDescriptor_e12598271a686f57, []int{2}
|
||||
}
|
||||
func (m *BlockParams) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -177,7 +240,7 @@ func (m *EvidenceParams) Reset() { *m = EvidenceParams{} }
|
||||
func (m *EvidenceParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*EvidenceParams) ProtoMessage() {}
|
||||
func (*EvidenceParams) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_e12598271a686f57, []int{2}
|
||||
return fileDescriptor_e12598271a686f57, []int{3}
|
||||
}
|
||||
func (m *EvidenceParams) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -237,7 +300,7 @@ func (m *ValidatorParams) Reset() { *m = ValidatorParams{} }
|
||||
func (m *ValidatorParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*ValidatorParams) ProtoMessage() {}
|
||||
func (*ValidatorParams) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_e12598271a686f57, []int{3}
|
||||
return fileDescriptor_e12598271a686f57, []int{4}
|
||||
}
|
||||
func (m *ValidatorParams) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -282,7 +345,7 @@ func (m *VersionParams) Reset() { *m = VersionParams{} }
|
||||
func (m *VersionParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*VersionParams) ProtoMessage() {}
|
||||
func (*VersionParams) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_e12598271a686f57, []int{4}
|
||||
return fileDescriptor_e12598271a686f57, []int{5}
|
||||
}
|
||||
func (m *VersionParams) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -318,26 +381,32 @@ func (m *VersionParams) GetApp() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// HashedParams is a subset of ConsensusParams.
|
||||
//
|
||||
// It is hashed into the Header.ConsensusHash.
|
||||
type HashedParams struct {
|
||||
BlockMaxBytes int64 `protobuf:"varint,1,opt,name=block_max_bytes,json=blockMaxBytes,proto3" json:"block_max_bytes,omitempty"`
|
||||
BlockMaxGas int64 `protobuf:"varint,2,opt,name=block_max_gas,json=blockMaxGas,proto3" json:"block_max_gas,omitempty"`
|
||||
// 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 *HashedParams) Reset() { *m = HashedParams{} }
|
||||
func (m *HashedParams) String() string { return proto.CompactTextString(m) }
|
||||
func (*HashedParams) ProtoMessage() {}
|
||||
func (*HashedParams) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_e12598271a686f57, []int{5}
|
||||
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{6}
|
||||
}
|
||||
func (m *HashedParams) XXX_Unmarshal(b []byte) error {
|
||||
func (m *ABCIParams) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *HashedParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
func (m *ABCIParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_HashedParams.Marshal(b, m, deterministic)
|
||||
return xxx_messageInfo_ABCIParams.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
@@ -347,78 +416,75 @@ func (m *HashedParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *HashedParams) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HashedParams.Merge(m, src)
|
||||
func (m *ABCIParams) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ABCIParams.Merge(m, src)
|
||||
}
|
||||
func (m *HashedParams) XXX_Size() int {
|
||||
func (m *ABCIParams) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *HashedParams) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HashedParams.DiscardUnknown(m)
|
||||
func (m *ABCIParams) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ABCIParams.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HashedParams proto.InternalMessageInfo
|
||||
var xxx_messageInfo_ABCIParams proto.InternalMessageInfo
|
||||
|
||||
func (m *HashedParams) GetBlockMaxBytes() int64 {
|
||||
func (m *ABCIParams) GetVoteExtensionsEnableHeight() int64 {
|
||||
if m != nil {
|
||||
return m.BlockMaxBytes
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *HashedParams) GetBlockMaxGas() int64 {
|
||||
if m != nil {
|
||||
return m.BlockMaxGas
|
||||
return m.VoteExtensionsEnableHeight
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*ConsensusParams)(nil), "tendermint.types.ConsensusParams")
|
||||
proto.RegisterType((*HashedParams)(nil), "tendermint.types.HashedParams")
|
||||
proto.RegisterType((*BlockParams)(nil), "tendermint.types.BlockParams")
|
||||
proto.RegisterType((*EvidenceParams)(nil), "tendermint.types.EvidenceParams")
|
||||
proto.RegisterType((*ValidatorParams)(nil), "tendermint.types.ValidatorParams")
|
||||
proto.RegisterType((*VersionParams)(nil), "tendermint.types.VersionParams")
|
||||
proto.RegisterType((*HashedParams)(nil), "tendermint.types.HashedParams")
|
||||
proto.RegisterType((*ABCIParams)(nil), "tendermint.types.ABCIParams")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("tendermint/types/params.proto", fileDescriptor_e12598271a686f57) }
|
||||
|
||||
var fileDescriptor_e12598271a686f57 = []byte{
|
||||
// 513 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x93, 0x4f, 0x6f, 0xd3, 0x30,
|
||||
0x18, 0xc6, 0xeb, 0xa5, 0x6c, 0xed, 0x5b, 0xba, 0x56, 0x16, 0x12, 0x61, 0x68, 0x49, 0xc9, 0x01,
|
||||
0x4d, 0x9a, 0x94, 0x48, 0xec, 0x80, 0x40, 0x48, 0x13, 0x05, 0x34, 0xfe, 0x68, 0x08, 0x45, 0xc0,
|
||||
0x61, 0x97, 0xc8, 0x69, 0x4c, 0x16, 0xad, 0x8e, 0xa3, 0x38, 0xa9, 0xda, 0x1b, 0x1f, 0x81, 0x23,
|
||||
0xc7, 0x1d, 0xe1, 0x1b, 0xf0, 0x11, 0x76, 0xdc, 0x91, 0x13, 0xa0, 0xf6, 0xc2, 0xc7, 0x40, 0x71,
|
||||
0x62, 0xd2, 0x76, 0xbb, 0x39, 0x7e, 0x7e, 0x8f, 0x9d, 0xe7, 0xb1, 0x5e, 0xd8, 0xcd, 0x68, 0x1c,
|
||||
0xd0, 0x94, 0x45, 0x71, 0xe6, 0x64, 0xb3, 0x84, 0x0a, 0x27, 0x21, 0x29, 0x61, 0xc2, 0x4e, 0x52,
|
||||
0x9e, 0x71, 0xdc, 0xaf, 0x65, 0x5b, 0xca, 0x3b, 0xb7, 0x42, 0x1e, 0x72, 0x29, 0x3a, 0xc5, 0xaa,
|
||||
0xe4, 0x76, 0x8c, 0x90, 0xf3, 0x70, 0x4c, 0x1d, 0xf9, 0xe5, 0xe7, 0x9f, 0x9c, 0x20, 0x4f, 0x49,
|
||||
0x16, 0xf1, 0xb8, 0xd4, 0xad, 0xcf, 0x1b, 0xd0, 0x7b, 0xc6, 0x63, 0x41, 0x63, 0x91, 0x8b, 0x77,
|
||||
0xf2, 0x06, 0x7c, 0x00, 0x37, 0xfc, 0x31, 0x1f, 0x9d, 0xe9, 0x68, 0x80, 0xf6, 0x3a, 0x0f, 0x76,
|
||||
0xed, 0xf5, 0xbb, 0xec, 0x61, 0x21, 0x97, 0xb4, 0x5b, 0xb2, 0xf8, 0x09, 0xb4, 0xe8, 0x24, 0x0a,
|
||||
0x68, 0x3c, 0xa2, 0xfa, 0x86, 0xf4, 0x0d, 0xae, 0xfa, 0x5e, 0x54, 0x44, 0x65, 0xfd, 0xef, 0xc0,
|
||||
0x87, 0xd0, 0x9e, 0x90, 0x71, 0x14, 0x90, 0x8c, 0xa7, 0xba, 0x26, 0xed, 0xf7, 0xae, 0xda, 0x3f,
|
||||
0x2a, 0xa4, 0xf2, 0xd7, 0x1e, 0xfc, 0x08, 0xb6, 0x26, 0x34, 0x15, 0x11, 0x8f, 0xf5, 0xa6, 0xb4,
|
||||
0x9b, 0xd7, 0xd8, 0x4b, 0xa0, 0x32, 0x2b, 0xde, 0x7a, 0x05, 0x9d, 0xa5, 0x3c, 0xf8, 0x2e, 0xb4,
|
||||
0x19, 0x99, 0x7a, 0xfe, 0x2c, 0xa3, 0x42, 0x36, 0xa0, 0xb9, 0x2d, 0x46, 0xa6, 0xc3, 0xe2, 0x1b,
|
||||
0xdf, 0x86, 0xad, 0x42, 0x0c, 0x89, 0x90, 0x21, 0x35, 0x77, 0x93, 0x91, 0xe9, 0x11, 0x11, 0xaf,
|
||||
0x9b, 0x2d, 0xad, 0xdf, 0xb4, 0xbe, 0x23, 0xd8, 0x5e, 0xcd, 0x88, 0xf7, 0x01, 0x17, 0x0e, 0x12,
|
||||
0x52, 0x2f, 0xce, 0x99, 0x27, 0xcb, 0x52, 0xe7, 0xf6, 0x18, 0x99, 0x3e, 0x0d, 0xe9, 0xdb, 0x9c,
|
||||
0xc9, 0x1f, 0x10, 0xf8, 0x18, 0xfa, 0x0a, 0x56, 0xef, 0x54, 0x95, 0x79, 0xc7, 0x2e, 0x1f, 0xd2,
|
||||
0x56, 0x0f, 0x69, 0x3f, 0xaf, 0x80, 0x61, 0xeb, 0xe2, 0x97, 0xd9, 0xf8, 0xfa, 0xdb, 0x44, 0xee,
|
||||
0x76, 0x79, 0x9e, 0x52, 0x56, 0xa3, 0x68, 0xab, 0x51, 0xac, 0x43, 0xe8, 0xad, 0xf5, 0x89, 0x2d,
|
||||
0xe8, 0x26, 0xb9, 0xef, 0x9d, 0xd1, 0x99, 0x27, 0x1b, 0xd3, 0xd1, 0x40, 0xdb, 0x6b, 0xbb, 0x9d,
|
||||
0x24, 0xf7, 0xdf, 0xd0, 0xd9, 0xfb, 0x62, 0xeb, 0x71, 0xeb, 0xc7, 0xb9, 0x89, 0xfe, 0x9e, 0x9b,
|
||||
0xc8, 0xda, 0x87, 0xee, 0x4a, 0xa3, 0xb8, 0x0f, 0x1a, 0x49, 0x12, 0x99, 0xad, 0xe9, 0x16, 0xcb,
|
||||
0x25, 0xf8, 0x04, 0x6e, 0xbe, 0x24, 0xe2, 0x94, 0x06, 0x15, 0x7b, 0x1f, 0x7a, 0xb2, 0x0a, 0x6f,
|
||||
0xbd, 0xeb, 0xae, 0xdc, 0x3e, 0x56, 0x85, 0x5b, 0xd0, 0xad, 0xb9, 0xba, 0xf6, 0x8e, 0xa2, 0x8e,
|
||||
0x88, 0x18, 0x7e, 0xf8, 0x36, 0x37, 0xd0, 0xc5, 0xdc, 0x40, 0x97, 0x73, 0x03, 0xfd, 0x99, 0x1b,
|
||||
0xe8, 0xcb, 0xc2, 0x68, 0x5c, 0x2e, 0x8c, 0xc6, 0xcf, 0x85, 0xd1, 0x38, 0x79, 0x18, 0x46, 0xd9,
|
||||
0x69, 0xee, 0xdb, 0x23, 0xce, 0x9c, 0xe5, 0x99, 0xaa, 0x97, 0xe5, 0xd0, 0xac, 0xcf, 0x9b, 0xbf,
|
||||
0x29, 0xf7, 0x0f, 0xfe, 0x05, 0x00, 0x00, 0xff, 0xff, 0x48, 0xd2, 0x61, 0x14, 0x8a, 0x03, 0x00,
|
||||
0x00,
|
||||
// 569 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x93, 0x3f, 0x6f, 0xd3, 0x40,
|
||||
0x14, 0xc0, 0x73, 0x75, 0xda, 0x26, 0x2f, 0xa4, 0x89, 0x4e, 0x48, 0x98, 0x40, 0x9c, 0xe0, 0x01,
|
||||
0x55, 0xaa, 0x64, 0x23, 0x3a, 0x20, 0x10, 0x52, 0x95, 0x94, 0x88, 0x16, 0x54, 0x40, 0x16, 0x30,
|
||||
0x74, 0xb1, 0xce, 0xc9, 0xe1, 0x58, 0x8d, 0x7d, 0x96, 0xef, 0x1c, 0x25, 0xdf, 0x82, 0x91, 0xb1,
|
||||
0x23, 0xac, 0x4c, 0x7c, 0x84, 0x8e, 0x1d, 0x99, 0x00, 0x25, 0x0b, 0x1f, 0x03, 0xf9, 0x6c, 0x37,
|
||||
0xff, 0xd8, 0xce, 0xef, 0xfd, 0x7e, 0xef, 0x7c, 0xef, 0xdd, 0x41, 0x53, 0xd0, 0x60, 0x40, 0x23,
|
||||
0xdf, 0x0b, 0x84, 0x29, 0xa6, 0x21, 0xe5, 0x66, 0x48, 0x22, 0xe2, 0x73, 0x23, 0x8c, 0x98, 0x60,
|
||||
0xb8, 0xbe, 0x48, 0x1b, 0x32, 0xdd, 0xb8, 0xed, 0x32, 0x97, 0xc9, 0xa4, 0x99, 0xac, 0x52, 0xae,
|
||||
0xa1, 0xb9, 0x8c, 0xb9, 0x23, 0x6a, 0xca, 0x2f, 0x27, 0xfe, 0x64, 0x0e, 0xe2, 0x88, 0x08, 0x8f,
|
||||
0x05, 0x69, 0x5e, 0xff, 0xbe, 0x05, 0xb5, 0x63, 0x16, 0x70, 0x1a, 0xf0, 0x98, 0xbf, 0x93, 0x3b,
|
||||
0xe0, 0x43, 0xd8, 0x76, 0x46, 0xac, 0x7f, 0xa1, 0xa2, 0x36, 0xda, 0xaf, 0x3c, 0x6e, 0x1a, 0xeb,
|
||||
0x7b, 0x19, 0xdd, 0x24, 0x9d, 0xd2, 0x56, 0xca, 0xe2, 0xe7, 0x50, 0xa2, 0x63, 0x6f, 0x40, 0x83,
|
||||
0x3e, 0x55, 0xb7, 0xa4, 0xd7, 0xde, 0xf4, 0x7a, 0x19, 0x91, 0xa9, 0x37, 0x06, 0x3e, 0x82, 0xf2,
|
||||
0x98, 0x8c, 0xbc, 0x01, 0x11, 0x2c, 0x52, 0x15, 0xa9, 0x3f, 0xd8, 0xd4, 0x3f, 0xe6, 0x48, 0xe6,
|
||||
0x2f, 0x1c, 0xfc, 0x14, 0x76, 0xc7, 0x34, 0xe2, 0x1e, 0x0b, 0xd4, 0xa2, 0xd4, 0x5b, 0xff, 0xd1,
|
||||
0x53, 0x20, 0x93, 0x73, 0x1e, 0x3f, 0x82, 0x22, 0x71, 0xfa, 0x9e, 0xba, 0x2d, 0xbd, 0xfb, 0x9b,
|
||||
0x5e, 0xa7, 0x7b, 0x7c, 0x9a, 0x49, 0x92, 0xd4, 0xcf, 0xe1, 0xd6, 0x09, 0xe1, 0x43, 0x3a, 0xc8,
|
||||
0x1a, 0xf6, 0x10, 0x6a, 0xb2, 0x09, 0xb6, 0x4f, 0x26, 0xb6, 0x33, 0x15, 0x94, 0xcb, 0xd6, 0x29,
|
||||
0x56, 0x55, 0x86, 0xcf, 0xc8, 0xa4, 0x9b, 0x04, 0xb1, 0x0e, 0xd5, 0x05, 0xe7, 0x12, 0x2e, 0x1b,
|
||||
0xa5, 0x58, 0x95, 0x9c, 0x7a, 0x49, 0xb8, 0x7e, 0x0a, 0x95, 0xa5, 0xee, 0xe2, 0x7b, 0x50, 0x5e,
|
||||
0x2f, 0x5a, 0xf2, 0xf3, 0x7a, 0x77, 0x60, 0x77, 0xb5, 0xd2, 0x8e, 0x2f, 0x8b, 0xbc, 0x2a, 0x96,
|
||||
0x94, 0x7a, 0x51, 0xff, 0x86, 0x60, 0x6f, 0xb5, 0xe3, 0xf8, 0x00, 0x70, 0x62, 0x10, 0x97, 0xda,
|
||||
0x41, 0xec, 0xdb, 0x72, 0xe3, 0xbc, 0x6e, 0xcd, 0x27, 0x93, 0x8e, 0x4b, 0xdf, 0xc4, 0xbe, 0xfc,
|
||||
0x01, 0x8e, 0xcf, 0xa0, 0x9e, 0xc3, 0xf9, 0xad, 0xc9, 0x46, 0x7b, 0xd7, 0x48, 0xaf, 0x95, 0x91,
|
||||
0x5f, 0x2b, 0xe3, 0x45, 0x06, 0x74, 0x4b, 0x57, 0xbf, 0x5a, 0x85, 0x2f, 0xbf, 0x5b, 0xc8, 0xda,
|
||||
0x4b, 0xeb, 0xe5, 0x99, 0xd5, 0xa3, 0x28, 0xab, 0x47, 0xd1, 0x8f, 0xa0, 0xb6, 0x36, 0xdd, 0xa4,
|
||||
0x5b, 0x61, 0xec, 0xd8, 0x17, 0x74, 0x6a, 0xcb, 0x39, 0xa8, 0xa8, 0xad, 0xec, 0x97, 0xad, 0x4a,
|
||||
0x18, 0x3b, 0xaf, 0xe9, 0xf4, 0x7d, 0x12, 0x7a, 0x56, 0xfa, 0x71, 0xd9, 0x42, 0x7f, 0x2f, 0x5b,
|
||||
0x48, 0x3f, 0x80, 0xea, 0xca, 0x7c, 0x71, 0x1d, 0x14, 0x12, 0x86, 0xf2, 0x6c, 0x45, 0x2b, 0x59,
|
||||
0x2e, 0xc1, 0x6f, 0x01, 0x16, 0x43, 0xc5, 0x1d, 0x68, 0x8e, 0x99, 0xa0, 0x36, 0x9d, 0x08, 0x1a,
|
||||
0x24, 0x15, 0xb8, 0x4d, 0x03, 0xe2, 0x8c, 0xa8, 0x3d, 0xa4, 0x9e, 0x3b, 0x14, 0x59, 0x7f, 0x1a,
|
||||
0x09, 0xd4, 0xbb, 0x61, 0x7a, 0x12, 0x39, 0x91, 0x44, 0xf7, 0xc3, 0xd7, 0x99, 0x86, 0xae, 0x66,
|
||||
0x1a, 0xba, 0x9e, 0x69, 0xe8, 0xcf, 0x4c, 0x43, 0x9f, 0xe7, 0x5a, 0xe1, 0x7a, 0xae, 0x15, 0x7e,
|
||||
0xce, 0xb5, 0xc2, 0xf9, 0x13, 0xd7, 0x13, 0xc3, 0xd8, 0x31, 0xfa, 0xcc, 0x37, 0x97, 0x9f, 0xf5,
|
||||
0x62, 0x99, 0xbe, 0xdb, 0xf5, 0x27, 0xef, 0xec, 0xc8, 0xf8, 0xe1, 0xbf, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xda, 0x5f, 0x18, 0x9a, 0x0d, 0x04, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (this *ConsensusParams) Equal(that interface{}) bool {
|
||||
@@ -452,6 +518,36 @@ func (this *ConsensusParams) Equal(that interface{}) bool {
|
||||
if !this.Version.Equal(that1.Version) {
|
||||
return false
|
||||
}
|
||||
if !this.Abci.Equal(that1.Abci) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (this *HashedParams) Equal(that interface{}) bool {
|
||||
if that == nil {
|
||||
return this == nil
|
||||
}
|
||||
|
||||
that1, ok := that.(*HashedParams)
|
||||
if !ok {
|
||||
that2, ok := that.(HashedParams)
|
||||
if ok {
|
||||
that1 = &that2
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if that1 == nil {
|
||||
return this == nil
|
||||
} else if this == nil {
|
||||
return false
|
||||
}
|
||||
if this.BlockMaxBytes != that1.BlockMaxBytes {
|
||||
return false
|
||||
}
|
||||
if this.BlockMaxGas != that1.BlockMaxGas {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (this *BlockParams) Equal(that interface{}) bool {
|
||||
@@ -564,14 +660,14 @@ func (this *VersionParams) Equal(that interface{}) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (this *HashedParams) Equal(that interface{}) bool {
|
||||
func (this *ABCIParams) Equal(that interface{}) bool {
|
||||
if that == nil {
|
||||
return this == nil
|
||||
}
|
||||
|
||||
that1, ok := that.(*HashedParams)
|
||||
that1, ok := that.(*ABCIParams)
|
||||
if !ok {
|
||||
that2, ok := that.(HashedParams)
|
||||
that2, ok := that.(ABCIParams)
|
||||
if ok {
|
||||
that1 = &that2
|
||||
} else {
|
||||
@@ -583,10 +679,7 @@ func (this *HashedParams) Equal(that interface{}) bool {
|
||||
} else if this == nil {
|
||||
return false
|
||||
}
|
||||
if this.BlockMaxBytes != that1.BlockMaxBytes {
|
||||
return false
|
||||
}
|
||||
if this.BlockMaxGas != that1.BlockMaxGas {
|
||||
if this.VoteExtensionsEnableHeight != that1.VoteExtensionsEnableHeight {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -611,6 +704,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] = 0x2a
|
||||
}
|
||||
if m.Version != nil {
|
||||
{
|
||||
size, err := m.Version.MarshalToSizedBuffer(dAtA[:i])
|
||||
@@ -662,6 +767,39 @@ func (m *ConsensusParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *HashedParams) 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 *HashedParams) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *HashedParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.BlockMaxGas != 0 {
|
||||
i = encodeVarintParams(dAtA, i, uint64(m.BlockMaxGas))
|
||||
i--
|
||||
dAtA[i] = 0x10
|
||||
}
|
||||
if m.BlockMaxBytes != 0 {
|
||||
i = encodeVarintParams(dAtA, i, uint64(m.BlockMaxBytes))
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *BlockParams) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
@@ -720,12 +858,12 @@ func (m *EvidenceParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0x18
|
||||
}
|
||||
n5, err5 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.MaxAgeDuration, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.MaxAgeDuration):])
|
||||
if err5 != nil {
|
||||
return 0, err5
|
||||
n6, err6 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.MaxAgeDuration, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.MaxAgeDuration):])
|
||||
if err6 != nil {
|
||||
return 0, err6
|
||||
}
|
||||
i -= n5
|
||||
i = encodeVarintParams(dAtA, i, uint64(n5))
|
||||
i -= n6
|
||||
i = encodeVarintParams(dAtA, i, uint64(n6))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
if m.MaxAgeNumBlocks != 0 {
|
||||
@@ -796,7 +934,7 @@ func (m *VersionParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *HashedParams) Marshal() (dAtA []byte, err error) {
|
||||
func (m *ABCIParams) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
@@ -806,23 +944,18 @@ func (m *HashedParams) Marshal() (dAtA []byte, err error) {
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *HashedParams) MarshalTo(dAtA []byte) (int, error) {
|
||||
func (m *ABCIParams) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *HashedParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
func (m *ABCIParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.BlockMaxGas != 0 {
|
||||
i = encodeVarintParams(dAtA, i, uint64(m.BlockMaxGas))
|
||||
i--
|
||||
dAtA[i] = 0x10
|
||||
}
|
||||
if m.BlockMaxBytes != 0 {
|
||||
i = encodeVarintParams(dAtA, i, uint64(m.BlockMaxBytes))
|
||||
if m.VoteExtensionsEnableHeight != 0 {
|
||||
i = encodeVarintParams(dAtA, i, uint64(m.VoteExtensionsEnableHeight))
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
@@ -954,6 +1087,25 @@ func (m *ConsensusParams) Size() (n int) {
|
||||
l = m.Version.Size()
|
||||
n += 1 + l + sovParams(uint64(l))
|
||||
}
|
||||
if m.Abci != nil {
|
||||
l = m.Abci.Size()
|
||||
n += 1 + l + sovParams(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *HashedParams) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.BlockMaxBytes != 0 {
|
||||
n += 1 + sovParams(uint64(m.BlockMaxBytes))
|
||||
}
|
||||
if m.BlockMaxGas != 0 {
|
||||
n += 1 + sovParams(uint64(m.BlockMaxGas))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -1016,17 +1168,14 @@ func (m *VersionParams) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *HashedParams) Size() (n int) {
|
||||
func (m *ABCIParams) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.BlockMaxBytes != 0 {
|
||||
n += 1 + sovParams(uint64(m.BlockMaxBytes))
|
||||
}
|
||||
if m.BlockMaxGas != 0 {
|
||||
n += 1 + sovParams(uint64(m.BlockMaxGas))
|
||||
if m.VoteExtensionsEnableHeight != 0 {
|
||||
n += 1 + sovParams(uint64(m.VoteExtensionsEnableHeight))
|
||||
}
|
||||
return n
|
||||
}
|
||||
@@ -1210,6 +1359,130 @@ func (m *ConsensusParams) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 5:
|
||||
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:])
|
||||
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 (m *HashedParams) 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: HashedParams: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: HashedParams: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field BlockMaxBytes", wireType)
|
||||
}
|
||||
m.BlockMaxBytes = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowParams
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.BlockMaxBytes |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field BlockMaxGas", wireType)
|
||||
}
|
||||
m.BlockMaxGas = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowParams
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.BlockMaxGas |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipParams(dAtA[iNdEx:])
|
||||
@@ -1591,7 +1864,7 @@ func (m *VersionParams) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *HashedParams) Unmarshal(dAtA []byte) error {
|
||||
func (m *ABCIParams) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
@@ -1614,17 +1887,17 @@ func (m *HashedParams) Unmarshal(dAtA []byte) error {
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: HashedParams: wiretype end group for non-group")
|
||||
return fmt.Errorf("proto: ABCIParams: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: HashedParams: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
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 BlockMaxBytes", wireType)
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field VoteExtensionsEnableHeight", wireType)
|
||||
}
|
||||
m.BlockMaxBytes = 0
|
||||
m.VoteExtensionsEnableHeight = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowParams
|
||||
@@ -1634,26 +1907,7 @@ func (m *HashedParams) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.BlockMaxBytes |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field BlockMaxGas", wireType)
|
||||
}
|
||||
m.BlockMaxGas = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowParams
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.BlockMaxGas |= int64(b&0x7F) << shift
|
||||
m.VoteExtensionsEnableHeight |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -15,6 +15,15 @@ message ConsensusParams {
|
||||
EvidenceParams evidence = 2;
|
||||
ValidatorParams validator = 3;
|
||||
VersionParams version = 4;
|
||||
ABCIParams abci = 5;
|
||||
}
|
||||
|
||||
// HashedParams is a subset of ConsensusParams.
|
||||
//
|
||||
// It is hashed into the Header.ConsensusHash.
|
||||
message HashedParams {
|
||||
int64 block_max_bytes = 1;
|
||||
int64 block_max_gas = 2;
|
||||
}
|
||||
|
||||
// BlockParams contains limits on the block size.
|
||||
@@ -68,10 +77,16 @@ message VersionParams {
|
||||
uint64 app = 1;
|
||||
}
|
||||
|
||||
// HashedParams is a subset of ConsensusParams.
|
||||
//
|
||||
// It is hashed into the Header.ConsensusHash.
|
||||
message HashedParams {
|
||||
int64 block_max_bytes = 1;
|
||||
int64 block_max_gas = 2;
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ func (m *Data) GetTxs() [][]byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Vote represents a prevote, precommit, or commit vote from validators for
|
||||
// Vote represents a prevote or precommit vote from validators for
|
||||
// consensus.
|
||||
type Vote struct {
|
||||
Type SignedMsgType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.SignedMsgType" json:"type,omitempty"`
|
||||
@@ -473,7 +473,14 @@ type Vote struct {
|
||||
Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"`
|
||||
ValidatorAddress []byte `protobuf:"bytes,6,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"`
|
||||
ValidatorIndex int32 `protobuf:"varint,7,opt,name=validator_index,json=validatorIndex,proto3" json:"validator_index,omitempty"`
|
||||
Signature []byte `protobuf:"bytes,8,opt,name=signature,proto3" json:"signature,omitempty"`
|
||||
// signature of
|
||||
Signature []byte `protobuf:"bytes,8,opt,name=signature,proto3" json:"signature,omitempty"`
|
||||
// Vote extension provided by the application. Only valid for precommit
|
||||
// messages.
|
||||
Extension []byte `protobuf:"bytes,9,opt,name=extension,proto3" json:"extension,omitempty"`
|
||||
// separate signature over the extension bytes. This enables backwards compatibility.
|
||||
// Only valid for precommit messages.
|
||||
ExtensionSignature []byte `protobuf:"bytes,10,opt,name=extension_signature,json=extensionSignature,proto3" json:"extension_signature,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Vote) Reset() { *m = Vote{} }
|
||||
@@ -565,6 +572,20 @@ func (m *Vote) GetSignature() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Vote) GetExtension() []byte {
|
||||
if m != nil {
|
||||
return m.Extension
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Vote) GetExtensionSignature() []byte {
|
||||
if m != nil {
|
||||
return m.ExtensionSignature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Commit contains the evidence that a block was committed by a set of validators.
|
||||
type Commit struct {
|
||||
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
|
||||
@@ -1208,94 +1229,95 @@ func init() {
|
||||
func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) }
|
||||
|
||||
var fileDescriptor_d3a6e55e2345de56 = []byte{
|
||||
// 1387 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0x4f, 0x6f, 0x1a, 0xd7,
|
||||
0x16, 0xf7, 0xc0, 0x60, 0xe0, 0x00, 0x36, 0xbe, 0xcf, 0x49, 0x08, 0x89, 0x31, 0x22, 0x7a, 0xef,
|
||||
0x39, 0x79, 0x4f, 0x38, 0x75, 0xaa, 0xfe, 0x59, 0x74, 0x01, 0x98, 0x24, 0x28, 0x36, 0xa6, 0x03,
|
||||
0x49, 0xd5, 0x6c, 0x46, 0x03, 0x73, 0x03, 0xd3, 0xc0, 0xcc, 0x68, 0xe6, 0xe2, 0xda, 0xf9, 0x04,
|
||||
0x95, 0x57, 0x59, 0x75, 0xe7, 0x55, 0xbb, 0xe8, 0xbe, 0xfd, 0x00, 0x55, 0x57, 0x59, 0x66, 0xd7,
|
||||
0x6e, 0x9a, 0xb6, 0x8e, 0x54, 0xf5, 0x63, 0x54, 0xf7, 0xdc, 0xcb, 0x30, 0x18, 0xbb, 0x8d, 0xa2,
|
||||
0xa8, 0x95, 0xba, 0x41, 0x73, 0xcf, 0xf9, 0x9d, 0x7b, 0xcf, 0xfd, 0x9d, 0xdf, 0x1c, 0xce, 0xc0,
|
||||
0x55, 0x46, 0x6d, 0x93, 0x7a, 0x23, 0xcb, 0x66, 0x9b, 0xec, 0xd0, 0xa5, 0xbe, 0xf8, 0x2d, 0xbb,
|
||||
0x9e, 0xc3, 0x1c, 0x92, 0x9d, 0x7a, 0xcb, 0x68, 0xcf, 0xaf, 0xf6, 0x9d, 0xbe, 0x83, 0xce, 0x4d,
|
||||
0xfe, 0x24, 0x70, 0xf9, 0xf5, 0xbe, 0xe3, 0xf4, 0x87, 0x74, 0x13, 0x57, 0xdd, 0xf1, 0xa3, 0x4d,
|
||||
0x66, 0x8d, 0xa8, 0xcf, 0x8c, 0x91, 0x2b, 0x01, 0x6b, 0xa1, 0x63, 0x7a, 0xde, 0xa1, 0xcb, 0x1c,
|
||||
0x8e, 0x75, 0x1e, 0x49, 0x77, 0x21, 0xe4, 0xde, 0xa7, 0x9e, 0x6f, 0x39, 0x76, 0x38, 0x8f, 0x7c,
|
||||
0x71, 0x2e, 0xcb, 0x7d, 0x63, 0x68, 0x99, 0x06, 0x73, 0x3c, 0x81, 0x28, 0xbd, 0x0f, 0x99, 0x96,
|
||||
0xe1, 0xb1, 0x36, 0x65, 0x77, 0xa9, 0x61, 0x52, 0x8f, 0xac, 0x42, 0x8c, 0x39, 0xcc, 0x18, 0xe6,
|
||||
0x94, 0xa2, 0xb2, 0x91, 0xd1, 0xc4, 0x82, 0x10, 0x50, 0x07, 0x86, 0x3f, 0xc8, 0x45, 0x8a, 0xca,
|
||||
0x46, 0x5a, 0xc3, 0xe7, 0xd2, 0x00, 0x54, 0x1e, 0xca, 0x23, 0x2c, 0xdb, 0xa4, 0x07, 0x93, 0x08,
|
||||
0x5c, 0x70, 0x6b, 0xf7, 0x90, 0x51, 0x5f, 0x86, 0x88, 0x05, 0x79, 0x1b, 0x62, 0x98, 0x7f, 0x2e,
|
||||
0x5a, 0x54, 0x36, 0x52, 0x5b, 0xb9, 0x72, 0x88, 0x28, 0x71, 0xbf, 0x72, 0x8b, 0xfb, 0xab, 0xea,
|
||||
0xb3, 0x17, 0xeb, 0x0b, 0x9a, 0x00, 0x97, 0x86, 0x10, 0xaf, 0x0e, 0x9d, 0xde, 0xe3, 0xc6, 0x76,
|
||||
0x90, 0x88, 0x32, 0x4d, 0x84, 0xec, 0xc2, 0xb2, 0x6b, 0x78, 0x4c, 0xf7, 0x29, 0xd3, 0x07, 0x78,
|
||||
0x0b, 0x3c, 0x34, 0xb5, 0xb5, 0x5e, 0x3e, 0x5d, 0x87, 0xf2, 0xcc, 0x65, 0xe5, 0x29, 0x19, 0x37,
|
||||
0x6c, 0x2c, 0xfd, 0xaa, 0xc2, 0xa2, 0x24, 0xe3, 0x03, 0x88, 0x4b, 0x5a, 0xf1, 0xc0, 0xd4, 0xd6,
|
||||
0x5a, 0x78, 0x47, 0xe9, 0x2a, 0xd7, 0x1c, 0xdb, 0xa7, 0xb6, 0x3f, 0xf6, 0xe5, 0x7e, 0x93, 0x18,
|
||||
0xf2, 0x1f, 0x48, 0xf4, 0x06, 0x86, 0x65, 0xeb, 0x96, 0x89, 0x19, 0x25, 0xab, 0xa9, 0x93, 0x17,
|
||||
0xeb, 0xf1, 0x1a, 0xb7, 0x35, 0xb6, 0xb5, 0x38, 0x3a, 0x1b, 0x26, 0xb9, 0x08, 0x8b, 0x03, 0x6a,
|
||||
0xf5, 0x07, 0x0c, 0x69, 0x89, 0x6a, 0x72, 0x45, 0xde, 0x03, 0x95, 0x0b, 0x22, 0xa7, 0xe2, 0xd9,
|
||||
0xf9, 0xb2, 0x50, 0x4b, 0x79, 0xa2, 0x96, 0x72, 0x67, 0xa2, 0x96, 0x6a, 0x82, 0x1f, 0xfc, 0xf4,
|
||||
0xa7, 0x75, 0x45, 0xc3, 0x08, 0x52, 0x83, 0xcc, 0xd0, 0xf0, 0x99, 0xde, 0xe5, 0xb4, 0xf1, 0xe3,
|
||||
0x63, 0xb8, 0xc5, 0xe5, 0x79, 0x42, 0x24, 0xb1, 0x32, 0xf5, 0x14, 0x8f, 0x12, 0x26, 0x93, 0x6c,
|
||||
0x40, 0x16, 0x37, 0xe9, 0x39, 0xa3, 0x91, 0xc5, 0x74, 0xe4, 0x7d, 0x11, 0x79, 0x5f, 0xe2, 0xf6,
|
||||
0x1a, 0x9a, 0xef, 0xf2, 0x0a, 0x5c, 0x81, 0xa4, 0x69, 0x30, 0x43, 0x40, 0xe2, 0x08, 0x49, 0x70,
|
||||
0x03, 0x3a, 0xff, 0x0b, 0xcb, 0x81, 0xea, 0x7c, 0x01, 0x49, 0x88, 0x5d, 0xa6, 0x66, 0x04, 0xde,
|
||||
0x84, 0x55, 0x9b, 0x1e, 0x30, 0xfd, 0x34, 0x3a, 0x89, 0x68, 0xc2, 0x7d, 0x0f, 0x66, 0x23, 0xfe,
|
||||
0x0d, 0x4b, 0xbd, 0x09, 0xf9, 0x02, 0x0b, 0x88, 0xcd, 0x04, 0x56, 0x84, 0x5d, 0x86, 0x84, 0xe1,
|
||||
0xba, 0x02, 0x90, 0x42, 0x40, 0xdc, 0x70, 0x5d, 0x74, 0xdd, 0x80, 0x15, 0xbc, 0xa3, 0x47, 0xfd,
|
||||
0xf1, 0x90, 0xc9, 0x4d, 0xd2, 0x88, 0x59, 0xe6, 0x0e, 0x4d, 0xd8, 0x11, 0x7b, 0x0d, 0x32, 0x74,
|
||||
0xdf, 0x32, 0xa9, 0xdd, 0xa3, 0x02, 0x97, 0x41, 0x5c, 0x7a, 0x62, 0x44, 0xd0, 0x75, 0xc8, 0xba,
|
||||
0x9e, 0xe3, 0x3a, 0x3e, 0xf5, 0x74, 0xc3, 0x34, 0x3d, 0xea, 0xfb, 0xb9, 0x25, 0xb1, 0xdf, 0xc4,
|
||||
0x5e, 0x11, 0xe6, 0x52, 0x0e, 0xd4, 0x6d, 0x83, 0x19, 0x24, 0x0b, 0x51, 0x76, 0xe0, 0xe7, 0x94,
|
||||
0x62, 0x74, 0x23, 0xad, 0xf1, 0xc7, 0xd2, 0x6f, 0x11, 0x50, 0x1f, 0x38, 0x8c, 0x92, 0x5b, 0xa0,
|
||||
0xf2, 0x32, 0xa1, 0xfa, 0x96, 0xce, 0xd2, 0x73, 0xdb, 0xea, 0xdb, 0xd4, 0xdc, 0xf5, 0xfb, 0x9d,
|
||||
0x43, 0x97, 0x6a, 0x08, 0x0e, 0xc9, 0x29, 0x32, 0x23, 0xa7, 0x55, 0x88, 0x79, 0xce, 0xd8, 0x36,
|
||||
0x51, 0x65, 0x31, 0x4d, 0x2c, 0x48, 0x1d, 0x12, 0x81, 0x4a, 0xd4, 0x3f, 0x53, 0xc9, 0x32, 0x57,
|
||||
0x09, 0xd7, 0xb0, 0x34, 0x68, 0xf1, 0xae, 0x14, 0x4b, 0x15, 0x92, 0x41, 0xf3, 0x92, 0x6a, 0x7b,
|
||||
0x35, 0xc1, 0x4e, 0xc3, 0xc8, 0xff, 0x60, 0x25, 0xa8, 0x7d, 0x40, 0x9e, 0x50, 0x5c, 0x36, 0x70,
|
||||
0x48, 0xf6, 0x66, 0x64, 0xa5, 0x8b, 0x06, 0x14, 0xc7, 0x7b, 0x4d, 0x65, 0xd5, 0xc0, 0x4e, 0x74,
|
||||
0x15, 0x92, 0xbe, 0xd5, 0xb7, 0x0d, 0x36, 0xf6, 0xa8, 0x54, 0xde, 0xd4, 0x50, 0xfa, 0x56, 0x81,
|
||||
0x45, 0xa1, 0xe4, 0x10, 0x6f, 0xca, 0xd9, 0xbc, 0x45, 0xce, 0xe3, 0x2d, 0xfa, 0xfa, 0xbc, 0x55,
|
||||
0x00, 0x82, 0x64, 0xfc, 0x9c, 0x5a, 0x8c, 0x6e, 0xa4, 0xb6, 0xae, 0xcc, 0x6f, 0x24, 0x52, 0x6c,
|
||||
0x5b, 0x7d, 0xf9, 0xa2, 0x86, 0x82, 0x4a, 0x3f, 0x2a, 0x90, 0x0c, 0xfc, 0xa4, 0x02, 0x99, 0x49,
|
||||
0x5e, 0xfa, 0xa3, 0xa1, 0xd1, 0x97, 0xda, 0x59, 0x3b, 0x37, 0xb9, 0xdb, 0x43, 0xa3, 0xaf, 0xa5,
|
||||
0x64, 0x3e, 0x7c, 0x71, 0x76, 0x1d, 0x22, 0xe7, 0xd4, 0x61, 0xa6, 0xf0, 0xd1, 0xd7, 0x2b, 0xfc,
|
||||
0x4c, 0x89, 0xd4, 0xd3, 0x25, 0xfa, 0x45, 0x81, 0xa5, 0xfa, 0x01, 0xa6, 0x6f, 0xfe, 0x9d, 0xa5,
|
||||
0x7a, 0x08, 0xff, 0xa2, 0x32, 0x0d, 0x7d, 0xae, 0x66, 0xd7, 0xe6, 0x77, 0x9c, 0xcd, 0x79, 0x5a,
|
||||
0x3b, 0x32, 0xd9, 0xa5, 0x3d, 0xad, 0xe1, 0x37, 0x11, 0x58, 0x99, 0xc3, 0xff, 0xf3, 0x6a, 0xc9,
|
||||
0xbd, 0x78, 0x7b, 0xfc, 0x4f, 0x8d, 0x09, 0x6f, 0x60, 0x20, 0x9b, 0x92, 0x61, 0xbe, 0x98, 0x52,
|
||||
0x2c, 0x5b, 0x00, 0x09, 0x5c, 0x01, 0x6f, 0xa5, 0xaf, 0x23, 0x90, 0x68, 0x61, 0x5b, 0x35, 0x86,
|
||||
0x7f, 0x45, 0xb3, 0xbc, 0x02, 0x49, 0xd7, 0x19, 0xea, 0xc2, 0xa3, 0xa2, 0x27, 0xe1, 0x3a, 0x43,
|
||||
0x6d, 0x4e, 0x66, 0xb1, 0x37, 0xd4, 0x49, 0x17, 0xdf, 0x40, 0x11, 0xe2, 0xa7, 0x5f, 0x28, 0x0f,
|
||||
0xd2, 0x82, 0x0a, 0x39, 0xe6, 0xdc, 0xe4, 0x1c, 0xe0, 0xdc, 0xa4, 0xcc, 0x8f, 0x65, 0x22, 0x6d,
|
||||
0x81, 0xd4, 0x24, 0x8e, 0x47, 0x88, 0xa9, 0x40, 0x4e, 0x5a, 0xb9, 0xf3, 0x3a, 0x96, 0x26, 0x71,
|
||||
0xa5, 0xcf, 0x15, 0x80, 0x1d, 0xce, 0x2c, 0xde, 0x97, 0x0f, 0x28, 0x3e, 0xa6, 0xa0, 0xcf, 0x9c,
|
||||
0x5c, 0x38, 0xaf, 0x68, 0xf2, 0xfc, 0xb4, 0x1f, 0xce, 0xbb, 0x06, 0x99, 0xa9, 0xb6, 0x7d, 0x3a,
|
||||
0x49, 0xe6, 0x8c, 0x4d, 0x82, 0xb9, 0xa1, 0x4d, 0x99, 0x96, 0xde, 0x0f, 0xad, 0x4a, 0xdf, 0x29,
|
||||
0x90, 0xc4, 0x9c, 0x76, 0x29, 0x33, 0x66, 0x6a, 0xa8, 0xbc, 0x7e, 0x0d, 0xd7, 0x00, 0xc4, 0x36,
|
||||
0xbe, 0xf5, 0x84, 0x4a, 0x65, 0x25, 0xd1, 0xd2, 0xb6, 0x9e, 0x50, 0xf2, 0x4e, 0x40, 0x78, 0xf4,
|
||||
0x8f, 0x09, 0x97, 0x1d, 0x63, 0x42, 0xfb, 0x25, 0x88, 0xdb, 0xe3, 0x91, 0xce, 0xa7, 0x05, 0x55,
|
||||
0xa8, 0xd5, 0x1e, 0x8f, 0x3a, 0x07, 0x7e, 0xe9, 0x13, 0x88, 0x77, 0x0e, 0x70, 0x72, 0xe6, 0x12,
|
||||
0xf5, 0x1c, 0x47, 0x8e, 0x6b, 0x62, 0x4c, 0x4e, 0x70, 0x03, 0x4e, 0x27, 0x04, 0x54, 0x3e, 0x97,
|
||||
0x4d, 0xe6, 0x78, 0xfe, 0x4c, 0xca, 0xaf, 0x38, 0x93, 0xcb, 0x69, 0xfc, 0xc6, 0xf7, 0x0a, 0xa4,
|
||||
0x42, 0xed, 0x86, 0xbc, 0x05, 0x17, 0xaa, 0x3b, 0x7b, 0xb5, 0x7b, 0x7a, 0x63, 0x5b, 0xbf, 0xbd,
|
||||
0x53, 0xb9, 0xa3, 0xdf, 0x6f, 0xde, 0x6b, 0xee, 0x7d, 0xd4, 0xcc, 0x2e, 0xe4, 0x2f, 0x1e, 0x1d,
|
||||
0x17, 0x49, 0x08, 0x7b, 0xdf, 0x7e, 0x6c, 0x3b, 0x9f, 0xf2, 0xf7, 0x7c, 0x75, 0x36, 0xa4, 0x52,
|
||||
0x6d, 0xd7, 0x9b, 0x9d, 0xac, 0x92, 0xbf, 0x70, 0x74, 0x5c, 0x5c, 0x09, 0x45, 0x54, 0xba, 0x3e,
|
||||
0xb5, 0xd9, 0x7c, 0x40, 0x6d, 0x6f, 0x77, 0xb7, 0xd1, 0xc9, 0x46, 0xe6, 0x02, 0xe4, 0x1f, 0xc4,
|
||||
0x75, 0x58, 0x99, 0x0d, 0x68, 0x36, 0x76, 0xb2, 0xd1, 0x3c, 0x39, 0x3a, 0x2e, 0x2e, 0x85, 0xd0,
|
||||
0x4d, 0x6b, 0x98, 0x4f, 0x7c, 0xf6, 0x45, 0x61, 0xe1, 0xab, 0x2f, 0x0b, 0x0a, 0xbf, 0x59, 0x66,
|
||||
0xa6, 0x47, 0x90, 0xff, 0xc3, 0xa5, 0x76, 0xe3, 0x4e, 0xb3, 0xbe, 0xad, 0xef, 0xb6, 0xef, 0xe8,
|
||||
0x9d, 0x8f, 0x5b, 0xf5, 0xd0, 0xed, 0x96, 0x8f, 0x8e, 0x8b, 0x29, 0x79, 0xa5, 0xf3, 0xd0, 0x2d,
|
||||
0xad, 0xfe, 0x60, 0xaf, 0x53, 0xcf, 0x2a, 0x02, 0xdd, 0xf2, 0xe8, 0xbe, 0xc3, 0x28, 0xa2, 0x6f,
|
||||
0xc2, 0xe5, 0x33, 0xd0, 0xc1, 0xc5, 0x56, 0x8e, 0x8e, 0x8b, 0x99, 0x96, 0x47, 0xc5, 0xfb, 0x83,
|
||||
0x11, 0x65, 0xc8, 0xcd, 0x47, 0xec, 0xb5, 0xf6, 0xda, 0x95, 0x9d, 0x6c, 0x31, 0x9f, 0x3d, 0x3a,
|
||||
0x2e, 0xa6, 0x27, 0xcd, 0x90, 0xe3, 0xa7, 0x37, 0xab, 0x7e, 0xf8, 0xec, 0xa4, 0xa0, 0x3c, 0x3f,
|
||||
0x29, 0x28, 0x3f, 0x9f, 0x14, 0x94, 0xa7, 0x2f, 0x0b, 0x0b, 0xcf, 0x5f, 0x16, 0x16, 0x7e, 0x78,
|
||||
0x59, 0x58, 0x78, 0xf8, 0x6e, 0xdf, 0x62, 0x83, 0x71, 0xb7, 0xdc, 0x73, 0x46, 0x9b, 0xe1, 0xaf,
|
||||
0xc5, 0xe9, 0xa3, 0xf8, 0x6a, 0x3d, 0xfd, 0x25, 0xd9, 0x5d, 0x44, 0xfb, 0xad, 0xdf, 0x03, 0x00,
|
||||
0x00, 0xff, 0xff, 0x47, 0xd6, 0xc3, 0xba, 0x0a, 0x0f, 0x00, 0x00,
|
||||
// 1396 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0x4b, 0x6f, 0x1b, 0xd5,
|
||||
0x17, 0xcf, 0xd8, 0xe3, 0xd7, 0xb1, 0x9d, 0x38, 0xf7, 0x9f, 0xb6, 0xae, 0xdb, 0x38, 0x96, 0xab,
|
||||
0x3f, 0xa4, 0x05, 0x39, 0x25, 0x45, 0x3c, 0x16, 0x2c, 0x6c, 0xc7, 0x6d, 0xad, 0x26, 0x8e, 0x19,
|
||||
0xbb, 0x45, 0x74, 0x33, 0x1a, 0x7b, 0x6e, 0xed, 0xa1, 0xf6, 0xcc, 0x68, 0xe6, 0x3a, 0x38, 0xfd,
|
||||
0x04, 0x28, 0xab, 0xae, 0xd8, 0x65, 0x05, 0x0b, 0xf6, 0x20, 0xb1, 0x45, 0xac, 0xba, 0xec, 0x0e,
|
||||
0x36, 0x14, 0x48, 0x25, 0x3e, 0x07, 0xba, 0x8f, 0x19, 0xcf, 0xc4, 0x31, 0x54, 0x51, 0x05, 0x12,
|
||||
0x9b, 0x68, 0xee, 0x39, 0xbf, 0x73, 0xee, 0x79, 0xfc, 0xee, 0xc9, 0x31, 0x5c, 0x25, 0xd8, 0xd4,
|
||||
0xb1, 0x33, 0x36, 0x4c, 0xb2, 0x45, 0x0e, 0x6d, 0xec, 0xf2, 0xbf, 0x15, 0xdb, 0xb1, 0x88, 0x85,
|
||||
0x72, 0x33, 0x6d, 0x85, 0xc9, 0x0b, 0x6b, 0x03, 0x6b, 0x60, 0x31, 0xe5, 0x16, 0xfd, 0xe2, 0xb8,
|
||||
0xc2, 0xc6, 0xc0, 0xb2, 0x06, 0x23, 0xbc, 0xc5, 0x4e, 0xbd, 0xc9, 0xa3, 0x2d, 0x62, 0x8c, 0xb1,
|
||||
0x4b, 0xb4, 0xb1, 0x2d, 0x00, 0xeb, 0x81, 0x6b, 0xfa, 0xce, 0xa1, 0x4d, 0x2c, 0x8a, 0xb5, 0x1e,
|
||||
0x09, 0x75, 0x31, 0xa0, 0x3e, 0xc0, 0x8e, 0x6b, 0x58, 0x66, 0x30, 0x8e, 0x42, 0x69, 0x2e, 0xca,
|
||||
0x03, 0x6d, 0x64, 0xe8, 0x1a, 0xb1, 0x1c, 0x8e, 0x28, 0x7f, 0x08, 0xd9, 0xb6, 0xe6, 0x90, 0x0e,
|
||||
0x26, 0x77, 0xb1, 0xa6, 0x63, 0x07, 0xad, 0x41, 0x8c, 0x58, 0x44, 0x1b, 0xe5, 0xa5, 0x92, 0xb4,
|
||||
0x99, 0x55, 0xf8, 0x01, 0x21, 0x90, 0x87, 0x9a, 0x3b, 0xcc, 0x47, 0x4a, 0xd2, 0x66, 0x46, 0x61,
|
||||
0xdf, 0xe5, 0x21, 0xc8, 0xd4, 0x94, 0x5a, 0x18, 0xa6, 0x8e, 0xa7, 0x9e, 0x05, 0x3b, 0x50, 0x69,
|
||||
0xef, 0x90, 0x60, 0x57, 0x98, 0xf0, 0x03, 0x7a, 0x17, 0x62, 0x2c, 0xfe, 0x7c, 0xb4, 0x24, 0x6d,
|
||||
0xa6, 0xb7, 0xf3, 0x95, 0x40, 0xa1, 0x78, 0x7e, 0x95, 0x36, 0xd5, 0xd7, 0xe4, 0x67, 0x2f, 0x36,
|
||||
0x96, 0x14, 0x0e, 0x2e, 0x8f, 0x20, 0x51, 0x1b, 0x59, 0xfd, 0xc7, 0xcd, 0x1d, 0x3f, 0x10, 0x69,
|
||||
0x16, 0x08, 0xda, 0x83, 0x15, 0x5b, 0x73, 0x88, 0xea, 0x62, 0xa2, 0x0e, 0x59, 0x16, 0xec, 0xd2,
|
||||
0xf4, 0xf6, 0x46, 0xe5, 0x74, 0x1f, 0x2a, 0xa1, 0x64, 0xc5, 0x2d, 0x59, 0x3b, 0x28, 0x2c, 0xff,
|
||||
0x21, 0x43, 0x5c, 0x14, 0xe3, 0x23, 0x48, 0x88, 0xb2, 0xb2, 0x0b, 0xd3, 0xdb, 0xeb, 0x41, 0x8f,
|
||||
0x42, 0x55, 0xa9, 0x5b, 0xa6, 0x8b, 0x4d, 0x77, 0xe2, 0x0a, 0x7f, 0x9e, 0x0d, 0x7a, 0x03, 0x92,
|
||||
0xfd, 0xa1, 0x66, 0x98, 0xaa, 0xa1, 0xb3, 0x88, 0x52, 0xb5, 0xf4, 0xc9, 0x8b, 0x8d, 0x44, 0x9d,
|
||||
0xca, 0x9a, 0x3b, 0x4a, 0x82, 0x29, 0x9b, 0x3a, 0xba, 0x08, 0xf1, 0x21, 0x36, 0x06, 0x43, 0xc2,
|
||||
0xca, 0x12, 0x55, 0xc4, 0x09, 0x7d, 0x00, 0x32, 0x25, 0x44, 0x5e, 0x66, 0x77, 0x17, 0x2a, 0x9c,
|
||||
0x2d, 0x15, 0x8f, 0x2d, 0x95, 0xae, 0xc7, 0x96, 0x5a, 0x92, 0x5e, 0xfc, 0xf4, 0xd7, 0x0d, 0x49,
|
||||
0x61, 0x16, 0xa8, 0x0e, 0xd9, 0x91, 0xe6, 0x12, 0xb5, 0x47, 0xcb, 0x46, 0xaf, 0x8f, 0x31, 0x17,
|
||||
0x97, 0xe7, 0x0b, 0x22, 0x0a, 0x2b, 0x42, 0x4f, 0x53, 0x2b, 0x2e, 0xd2, 0xd1, 0x26, 0xe4, 0x98,
|
||||
0x93, 0xbe, 0x35, 0x1e, 0x1b, 0x44, 0x65, 0x75, 0x8f, 0xb3, 0xba, 0x2f, 0x53, 0x79, 0x9d, 0x89,
|
||||
0xef, 0xd2, 0x0e, 0x5c, 0x81, 0x94, 0xae, 0x11, 0x8d, 0x43, 0x12, 0x0c, 0x92, 0xa4, 0x02, 0xa6,
|
||||
0x7c, 0x13, 0x56, 0x7c, 0xd6, 0xb9, 0x1c, 0x92, 0xe4, 0x5e, 0x66, 0x62, 0x06, 0xbc, 0x09, 0x6b,
|
||||
0x26, 0x9e, 0x12, 0xf5, 0x34, 0x3a, 0xc5, 0xd0, 0x88, 0xea, 0x1e, 0x84, 0x2d, 0xfe, 0x0f, 0xcb,
|
||||
0x7d, 0xaf, 0xf8, 0x1c, 0x0b, 0x0c, 0x9b, 0xf5, 0xa5, 0x0c, 0x76, 0x19, 0x92, 0x9a, 0x6d, 0x73,
|
||||
0x40, 0x9a, 0x01, 0x12, 0x9a, 0x6d, 0x33, 0xd5, 0x0d, 0x58, 0x65, 0x39, 0x3a, 0xd8, 0x9d, 0x8c,
|
||||
0x88, 0x70, 0x92, 0x61, 0x98, 0x15, 0xaa, 0x50, 0xb8, 0x9c, 0x61, 0xaf, 0x41, 0x16, 0x1f, 0x18,
|
||||
0x3a, 0x36, 0xfb, 0x98, 0xe3, 0xb2, 0x0c, 0x97, 0xf1, 0x84, 0x0c, 0x74, 0x1d, 0x72, 0xb6, 0x63,
|
||||
0xd9, 0x96, 0x8b, 0x1d, 0x55, 0xd3, 0x75, 0x07, 0xbb, 0x6e, 0x7e, 0x99, 0xfb, 0xf3, 0xe4, 0x55,
|
||||
0x2e, 0x2e, 0xe7, 0x41, 0xde, 0xd1, 0x88, 0x86, 0x72, 0x10, 0x25, 0x53, 0x37, 0x2f, 0x95, 0xa2,
|
||||
0x9b, 0x19, 0x85, 0x7e, 0x96, 0xbf, 0x8f, 0x82, 0xfc, 0xc0, 0x22, 0x18, 0xdd, 0x02, 0x99, 0xb6,
|
||||
0x89, 0xb1, 0x6f, 0xf9, 0x2c, 0x3e, 0x77, 0x8c, 0x81, 0x89, 0xf5, 0x3d, 0x77, 0xd0, 0x3d, 0xb4,
|
||||
0xb1, 0xc2, 0xc0, 0x01, 0x3a, 0x45, 0x42, 0x74, 0x5a, 0x83, 0x98, 0x63, 0x4d, 0x4c, 0x9d, 0xb1,
|
||||
0x2c, 0xa6, 0xf0, 0x03, 0x6a, 0x40, 0xd2, 0x67, 0x89, 0xfc, 0x77, 0x2c, 0x59, 0xa1, 0x2c, 0xa1,
|
||||
0x1c, 0x16, 0x02, 0x25, 0xd1, 0x13, 0x64, 0xa9, 0x41, 0xca, 0x1f, 0x5e, 0x82, 0x6d, 0xaf, 0x46,
|
||||
0xd8, 0x99, 0x19, 0x7a, 0x0b, 0x56, 0xfd, 0xde, 0xfb, 0xc5, 0xe3, 0x8c, 0xcb, 0xf9, 0x0a, 0x51,
|
||||
0xbd, 0x10, 0xad, 0x54, 0x3e, 0x80, 0x12, 0x2c, 0xaf, 0x19, 0xad, 0x9a, 0x6c, 0x12, 0x5d, 0x85,
|
||||
0x94, 0x6b, 0x0c, 0x4c, 0x8d, 0x4c, 0x1c, 0x2c, 0x98, 0x37, 0x13, 0x50, 0x2d, 0x9e, 0x12, 0x6c,
|
||||
0xb2, 0x47, 0xce, 0x99, 0x36, 0x13, 0xa0, 0x2d, 0xf8, 0x9f, 0x7f, 0x50, 0x67, 0x5e, 0x38, 0xcb,
|
||||
0x90, 0xaf, 0xea, 0x78, 0x9a, 0xf2, 0x0f, 0x12, 0xc4, 0xf9, 0xc3, 0x08, 0xb4, 0x41, 0x3a, 0xbb,
|
||||
0x0d, 0x91, 0x45, 0x6d, 0x88, 0x9e, 0xbf, 0x0d, 0x55, 0x00, 0x3f, 0x4c, 0x37, 0x2f, 0x97, 0xa2,
|
||||
0x9b, 0xe9, 0xed, 0x2b, 0xf3, 0x8e, 0x78, 0x88, 0x1d, 0x63, 0x20, 0xde, 0x7d, 0xc0, 0xa8, 0xfc,
|
||||
0x8b, 0x04, 0x29, 0x5f, 0x8f, 0xaa, 0x90, 0xf5, 0xe2, 0x52, 0x1f, 0x8d, 0xb4, 0x81, 0xa0, 0xe2,
|
||||
0xfa, 0xc2, 0xe0, 0x6e, 0x8f, 0xb4, 0x81, 0x92, 0x16, 0xf1, 0xd0, 0xc3, 0xd9, 0x6d, 0x8d, 0x2c,
|
||||
0x68, 0x6b, 0x88, 0x47, 0xd1, 0xf3, 0xf1, 0x28, 0xd4, 0x71, 0xf9, 0x54, 0xc7, 0xcb, 0xbf, 0x4b,
|
||||
0xb0, 0xdc, 0x98, 0xb2, 0xf0, 0xf5, 0x7f, 0xb3, 0x55, 0x0f, 0x05, 0xb7, 0x74, 0xac, 0xab, 0x73,
|
||||
0x3d, 0xbb, 0x36, 0xef, 0x31, 0x1c, 0xf3, 0xac, 0x77, 0xc8, 0xf3, 0xd2, 0x99, 0xf5, 0xf0, 0xbb,
|
||||
0x08, 0xac, 0xce, 0xe1, 0xff, 0x7b, 0xbd, 0x0c, 0xbf, 0xde, 0xd8, 0x2b, 0xbe, 0xde, 0xf8, 0xc2,
|
||||
0xd7, 0xfb, 0x6d, 0x04, 0x92, 0x6d, 0x36, 0xa5, 0xb5, 0xd1, 0x3f, 0x31, 0x7b, 0xaf, 0x40, 0xca,
|
||||
0xb6, 0x46, 0x2a, 0xd7, 0xc8, 0x4c, 0x93, 0xb4, 0xad, 0x91, 0x32, 0x47, 0xb3, 0xd8, 0x6b, 0x1a,
|
||||
0xcc, 0xf1, 0xd7, 0xd0, 0x84, 0xc4, 0xe9, 0x07, 0xe5, 0x40, 0x86, 0x97, 0x42, 0x6c, 0x4d, 0x37,
|
||||
0x69, 0x0d, 0xd8, 0x1a, 0x26, 0xcd, 0x6f, 0x79, 0x3c, 0x6c, 0x8e, 0x54, 0x04, 0x8e, 0x5a, 0xf0,
|
||||
0x25, 0x43, 0x2c, 0x6e, 0xf9, 0x45, 0x13, 0x4b, 0x11, 0xb8, 0xf2, 0x97, 0x12, 0xc0, 0x2e, 0xad,
|
||||
0x2c, 0xcb, 0x97, 0xee, 0x3b, 0x2e, 0x0b, 0x41, 0x0d, 0xdd, 0x5c, 0x5c, 0xd4, 0x34, 0x71, 0x7f,
|
||||
0xc6, 0x0d, 0xc6, 0x5d, 0x87, 0xec, 0x8c, 0xdb, 0x2e, 0xf6, 0x82, 0x39, 0xc3, 0x89, 0xbf, 0x86,
|
||||
0x74, 0x30, 0x51, 0x32, 0x07, 0x81, 0x53, 0xf9, 0x47, 0x09, 0x52, 0x2c, 0xa6, 0x3d, 0x4c, 0xb4,
|
||||
0x50, 0x0f, 0xa5, 0xf3, 0xf7, 0x70, 0x1d, 0x80, 0xbb, 0x71, 0x8d, 0x27, 0x58, 0x30, 0x2b, 0xc5,
|
||||
0x24, 0x1d, 0xe3, 0x09, 0x46, 0xef, 0xf9, 0x05, 0x8f, 0xfe, 0x75, 0xc1, 0xc5, 0xc4, 0xf0, 0xca,
|
||||
0x7e, 0x09, 0x12, 0xe6, 0x64, 0xac, 0xd2, 0xe5, 0x43, 0xe6, 0x6c, 0x35, 0x27, 0xe3, 0xee, 0xd4,
|
||||
0x2d, 0x7f, 0x06, 0x89, 0xee, 0x94, 0x2d, 0xe2, 0x94, 0xa2, 0x8e, 0x65, 0x89, 0xed, 0x8f, 0x6f,
|
||||
0xdd, 0x49, 0x2a, 0x60, 0xcb, 0x0e, 0x02, 0x99, 0xae, 0x79, 0xde, 0xcf, 0x02, 0xfa, 0x8d, 0x2a,
|
||||
0xaf, 0xb8, 0xe2, 0x8b, 0xe5, 0xfe, 0xc6, 0x4f, 0x12, 0xa4, 0x03, 0xe3, 0x06, 0xbd, 0x03, 0x17,
|
||||
0x6a, 0xbb, 0xfb, 0xf5, 0x7b, 0x6a, 0x73, 0x47, 0xbd, 0xbd, 0x5b, 0xbd, 0xa3, 0xde, 0x6f, 0xdd,
|
||||
0x6b, 0xed, 0x7f, 0xd2, 0xca, 0x2d, 0x15, 0x2e, 0x1e, 0x1d, 0x97, 0x50, 0x00, 0x7b, 0xdf, 0x7c,
|
||||
0x6c, 0x5a, 0x9f, 0xd3, 0x77, 0xbe, 0x16, 0x36, 0xa9, 0xd6, 0x3a, 0x8d, 0x56, 0x37, 0x27, 0x15,
|
||||
0x2e, 0x1c, 0x1d, 0x97, 0x56, 0x03, 0x16, 0xd5, 0x9e, 0x8b, 0x4d, 0x32, 0x6f, 0x50, 0xdf, 0xdf,
|
||||
0xdb, 0x6b, 0x76, 0x73, 0x91, 0x39, 0x03, 0xf1, 0x0f, 0xe2, 0x3a, 0xac, 0x86, 0x0d, 0x5a, 0xcd,
|
||||
0xdd, 0x5c, 0xb4, 0x80, 0x8e, 0x8e, 0x4b, 0xcb, 0x01, 0x74, 0xcb, 0x18, 0x15, 0x92, 0x5f, 0x7c,
|
||||
0x55, 0x5c, 0xfa, 0xe6, 0xeb, 0xa2, 0x44, 0x33, 0xcb, 0x86, 0x66, 0x04, 0x7a, 0x1b, 0x2e, 0x75,
|
||||
0x9a, 0x77, 0x5a, 0x8d, 0x1d, 0x75, 0xaf, 0x73, 0x47, 0xed, 0x7e, 0xda, 0x6e, 0x04, 0xb2, 0x5b,
|
||||
0x39, 0x3a, 0x2e, 0xa5, 0x45, 0x4a, 0x8b, 0xd0, 0x6d, 0xa5, 0xf1, 0x60, 0xbf, 0xdb, 0xc8, 0x49,
|
||||
0x1c, 0xdd, 0x76, 0xf0, 0x81, 0x45, 0x30, 0x43, 0xdf, 0x84, 0xcb, 0x67, 0xa0, 0xfd, 0xc4, 0x56,
|
||||
0x8f, 0x8e, 0x4b, 0xd9, 0xb6, 0x83, 0xf9, 0xfb, 0x61, 0x16, 0x15, 0xc8, 0xcf, 0x5b, 0xec, 0xb7,
|
||||
0xf7, 0x3b, 0xd5, 0xdd, 0x5c, 0xa9, 0x90, 0x3b, 0x3a, 0x2e, 0x65, 0xbc, 0x61, 0x48, 0xf1, 0xb3,
|
||||
0xcc, 0x6a, 0x1f, 0x3f, 0x3b, 0x29, 0x4a, 0xcf, 0x4f, 0x8a, 0xd2, 0x6f, 0x27, 0x45, 0xe9, 0xe9,
|
||||
0xcb, 0xe2, 0xd2, 0xf3, 0x97, 0xc5, 0xa5, 0x9f, 0x5f, 0x16, 0x97, 0x1e, 0xbe, 0x3f, 0x30, 0xc8,
|
||||
0x70, 0xd2, 0xab, 0xf4, 0xad, 0xf1, 0x56, 0xf0, 0xc7, 0xe7, 0xec, 0x93, 0xff, 0x08, 0x3e, 0xfd,
|
||||
0xc3, 0xb4, 0x17, 0x67, 0xf2, 0x5b, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x46, 0xcf, 0x37, 0x28,
|
||||
0x59, 0x0f, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *PartSetHeader) Marshal() (dAtA []byte, err error) {
|
||||
@@ -1596,6 +1618,20 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.ExtensionSignature) > 0 {
|
||||
i -= len(m.ExtensionSignature)
|
||||
copy(dAtA[i:], m.ExtensionSignature)
|
||||
i = encodeVarintTypes(dAtA, i, uint64(len(m.ExtensionSignature)))
|
||||
i--
|
||||
dAtA[i] = 0x52
|
||||
}
|
||||
if len(m.Extension) > 0 {
|
||||
i -= len(m.Extension)
|
||||
copy(dAtA[i:], m.Extension)
|
||||
i = encodeVarintTypes(dAtA, i, uint64(len(m.Extension)))
|
||||
i--
|
||||
dAtA[i] = 0x4a
|
||||
}
|
||||
if len(m.Signature) > 0 {
|
||||
i -= len(m.Signature)
|
||||
copy(dAtA[i:], m.Signature)
|
||||
@@ -2306,6 +2342,14 @@ func (m *Vote) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
}
|
||||
l = len(m.Extension)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
}
|
||||
l = len(m.ExtensionSignature)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -3699,6 +3743,74 @@ func (m *Vote) Unmarshal(dAtA []byte) error {
|
||||
m.Signature = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 9:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Extension", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTypes
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthTypes
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTypes
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Extension = append(m.Extension[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Extension == nil {
|
||||
m.Extension = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 10:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ExtensionSignature", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTypes
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthTypes
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTypes
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ExtensionSignature = append(m.ExtensionSignature[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.ExtensionSignature == nil {
|
||||
m.ExtensionSignature = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTypes(dAtA[iNdEx:])
|
||||
|
||||
@@ -89,7 +89,7 @@ message Data {
|
||||
repeated bytes txs = 1;
|
||||
}
|
||||
|
||||
// Vote represents a prevote, precommit, or commit vote from validators for
|
||||
// Vote represents a prevote or precommit vote from validators for
|
||||
// consensus.
|
||||
message Vote {
|
||||
SignedMsgType type = 1;
|
||||
@@ -101,7 +101,14 @@ message Vote {
|
||||
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
bytes validator_address = 6;
|
||||
int32 validator_index = 7;
|
||||
bytes signature = 8;
|
||||
// signature of
|
||||
bytes signature = 8;
|
||||
// Vote extension provided by the application. Only valid for precommit
|
||||
// messages.
|
||||
bytes extension = 9;
|
||||
// separate signature over the extension bytes. This enables backwards compatibility.
|
||||
// Only valid for precommit messages.
|
||||
bytes extension_signature = 10;
|
||||
}
|
||||
|
||||
// Commit contains the evidence that a block was committed by a set of validators.
|
||||
|
||||
@@ -52,6 +52,29 @@ func (_m *AppConnConsensus) Error() error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// ExtendVote provides a mock function with given fields: _a0, _a1
|
||||
func (_m *AppConnConsensus) ExtendVote(_a0 context.Context, _a1 *types.RequestExtendVote) (*types.ResponseExtendVote, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *types.ResponseExtendVote
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.RequestExtendVote) *types.ResponseExtendVote); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseExtendVote)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.RequestExtendVote) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FinalizeBlock provides a mock function with given fields: _a0, _a1
|
||||
func (_m *AppConnConsensus) FinalizeBlock(_a0 context.Context, _a1 *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
@@ -144,6 +167,29 @@ func (_m *AppConnConsensus) ProcessProposal(_a0 context.Context, _a1 *types.Requ
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// VerifyVoteExtension provides a mock function with given fields: _a0, _a1
|
||||
func (_m *AppConnConsensus) VerifyVoteExtension(_a0 context.Context, _a1 *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *types.ResponseVerifyVoteExtension
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.RequestVerifyVoteExtension) *types.ResponseVerifyVoteExtension); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseVerifyVoteExtension)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.RequestVerifyVoteExtension) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewAppConnConsensus interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
|
||||
+100
-15
@@ -1,7 +1,9 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -94,7 +96,7 @@ func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher)
|
||||
func (blockExec *BlockExecutor) CreateProposalBlock(
|
||||
height int64,
|
||||
state State,
|
||||
commit *types.Commit,
|
||||
lastExtCommit *types.ExtendedCommit,
|
||||
proposerAddr []byte,
|
||||
votes []*types.Vote,
|
||||
) (*types.Block, error) {
|
||||
@@ -108,14 +110,14 @@ func (blockExec *BlockExecutor) CreateProposalBlock(
|
||||
maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size())
|
||||
|
||||
txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)
|
||||
commit := lastExtCommit.ToCommit()
|
||||
block := state.MakeBlock(height, txs, commit, evidence, proposerAddr)
|
||||
|
||||
localLastCommit := buildLastCommitInfo(block, blockExec.store, state.InitialHeight)
|
||||
rpp, err := blockExec.proxyApp.PrepareProposal(context.TODO(),
|
||||
&abci.RequestPrepareProposal{
|
||||
MaxTxBytes: maxDataBytes,
|
||||
Txs: block.Txs.ToSliceOfBytes(),
|
||||
LocalLastCommit: extendedCommitInfo(localLastCommit, votes),
|
||||
LocalLastCommit: buildExtendedCommitInfo(lastExtCommit, blockExec.store, state.InitialHeight, state.ConsensusParams.ABCI),
|
||||
Misbehavior: block.Evidence.Evidence.ToABCI(),
|
||||
Height: block.Height,
|
||||
Time: block.Time,
|
||||
@@ -309,6 +311,35 @@ func (blockExec *BlockExecutor) Commit(
|
||||
return res.RetainHeight, err
|
||||
}
|
||||
|
||||
func (blockExec *BlockExecutor) ExtendVote(ctx context.Context, vote *types.Vote) ([]byte, error) {
|
||||
resp, err := blockExec.proxyApp.ExtendVote(ctx, &abci.RequestExtendVote{
|
||||
BlockHash: vote.BlockID.Hash,
|
||||
Height: vote.Height,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("ExtendVote call failed: %w", err))
|
||||
}
|
||||
return resp.VoteExtension, nil
|
||||
}
|
||||
|
||||
func (blockExec *BlockExecutor) VerifyVoteExtension(ctx context.Context, vote *types.Vote) error {
|
||||
resp, err := blockExec.proxyApp.VerifyVoteExtension(ctx, &abci.RequestVerifyVoteExtension{
|
||||
BlockHash: vote.BlockID.Hash,
|
||||
ValidatorAddress: vote.ValidatorAddress,
|
||||
Height: vote.Height,
|
||||
VoteExtension: vote.Extension,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("VerifyVoteExtension call failed: %w", err))
|
||||
}
|
||||
|
||||
if !resp.IsOK() {
|
||||
return errors.New("invalid vote extension")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Helper functions for executing blocks and updating state
|
||||
|
||||
@@ -387,21 +418,75 @@ func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) a
|
||||
}
|
||||
}
|
||||
|
||||
func extendedCommitInfo(c abci.CommitInfo, votes []*types.Vote) abci.ExtendedCommitInfo {
|
||||
vs := make([]abci.ExtendedVoteInfo, len(c.Votes))
|
||||
for i := range vs {
|
||||
vs[i] = abci.ExtendedVoteInfo{
|
||||
Validator: c.Votes[i].Validator,
|
||||
SignedLastBlock: c.Votes[i].SignedLastBlock,
|
||||
/*
|
||||
TODO: Include vote extensions information when implementing vote extensions.
|
||||
VoteExtension: []byte{},
|
||||
*/
|
||||
// buildExtendedCommitInfo populates an ABCI extended commit from the
|
||||
// corresponding Tendermint extended commit ec, using the stored validator set
|
||||
// from ec. It requires ec to include the original precommit votes along with
|
||||
// the vote extensions from the last commit.
|
||||
//
|
||||
// For heights below the initial height, for which we do not have the required
|
||||
// data, it returns an empty record.
|
||||
//
|
||||
// Assumes that the commit signatures are sorted according to validator index.
|
||||
func buildExtendedCommitInfo(ec *types.ExtendedCommit, store Store, initialHeight int64, ap types.ABCIParams) abci.ExtendedCommitInfo {
|
||||
if ec.Height < initialHeight {
|
||||
// There are no extended commits for heights below the initial height.
|
||||
return abci.ExtendedCommitInfo{}
|
||||
}
|
||||
|
||||
valSet, err := store.LoadValidators(ec.Height)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to load validator set at height %d, initial height %d: %w", ec.Height, initialHeight, err))
|
||||
}
|
||||
|
||||
var (
|
||||
ecSize = ec.Size()
|
||||
valSetLen = len(valSet.Validators)
|
||||
)
|
||||
|
||||
// Ensure that the size of the validator set in the extended commit matches
|
||||
// the size of the validator set in the state store.
|
||||
if ecSize != valSetLen {
|
||||
panic(fmt.Errorf(
|
||||
"extended commit size (%d) does not match validator set length (%d) at height %d\n\n%v\n\n%v",
|
||||
ecSize, valSetLen, ec.Height, ec.ExtendedSignatures, valSet.Validators,
|
||||
))
|
||||
}
|
||||
|
||||
votes := make([]abci.ExtendedVoteInfo, ecSize)
|
||||
for i, val := range valSet.Validators {
|
||||
ecs := ec.ExtendedSignatures[i]
|
||||
|
||||
// Absent signatures have empty validator addresses, but otherwise we
|
||||
// expect the validator addresses to be the same.
|
||||
if ecs.BlockIDFlag != types.BlockIDFlagAbsent && !bytes.Equal(ecs.ValidatorAddress, val.Address) {
|
||||
panic(fmt.Errorf("validator address of extended commit signature in position %d (%s) does not match the corresponding validator's at height %d (%s)",
|
||||
i, ecs.ValidatorAddress, ec.Height, val.Address,
|
||||
))
|
||||
}
|
||||
|
||||
var ext []byte
|
||||
// Check if vote extensions were enabled during the commit's height: ec.Height.
|
||||
// ec is the commit from the previous height, so if extensions were enabled
|
||||
// during that height, we ensure they are present and deliver the data to
|
||||
// the proposer. If they were not enabled during this previous height, we
|
||||
// will not deliver extension data.
|
||||
if ap.VoteExtensionsEnabled(ec.Height) && ecs.BlockIDFlag == types.BlockIDFlagCommit {
|
||||
if err := ecs.EnsureExtension(); err != nil {
|
||||
panic(fmt.Errorf("commit at height %d received with missing vote extensions data", ec.Height))
|
||||
}
|
||||
ext = ecs.Extension
|
||||
}
|
||||
|
||||
votes[i] = abci.ExtendedVoteInfo{
|
||||
Validator: types.TM2PB.Validator(val),
|
||||
SignedLastBlock: ecs.BlockIDFlag != types.BlockIDFlagAbsent,
|
||||
VoteExtension: ext,
|
||||
}
|
||||
}
|
||||
|
||||
return abci.ExtendedCommitInfo{
|
||||
Round: c.Round,
|
||||
Votes: vs,
|
||||
Round: ec.Round,
|
||||
Votes: votes,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-10
@@ -622,8 +622,7 @@ func TestEmptyPrepareProposal(t *testing.T) {
|
||||
sm.EmptyEvidencePool{},
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
commit, _ := makeValidExtendedCommit(t, height, types.BlockID{}, state.Validators, privVals)
|
||||
_, err = blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
@@ -663,8 +662,7 @@ func TestPrepareProposalTxsAllIncluded(t *testing.T) {
|
||||
evpool,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
commit, _ := makeValidExtendedCommit(t, height, types.BlockID{}, state.Validators, privVals)
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -714,8 +712,7 @@ func TestPrepareProposalReorderTxs(t *testing.T) {
|
||||
evpool,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
commit, _ := makeValidExtendedCommit(t, height, types.BlockID{}, state.Validators, privVals)
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
require.NoError(t, err)
|
||||
for i, tx := range block.Data.Txs {
|
||||
@@ -767,8 +764,7 @@ func TestPrepareProposalErrorOnTooManyTxs(t *testing.T) {
|
||||
evpool,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
commit, _ := makeValidExtendedCommit(t, height, types.BlockID{}, state.Validators, privVals)
|
||||
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
require.Nil(t, block)
|
||||
@@ -815,8 +811,7 @@ func TestPrepareProposalErrorOnPrepareProposalError(t *testing.T) {
|
||||
evpool,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
commit, _ := makeValidExtendedCommit(t, height, types.BlockID{}, state.Validators, privVals)
|
||||
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
require.Nil(t, block)
|
||||
|
||||
+26
-18
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
@@ -32,25 +33,25 @@ func newTestApp() proxy.AppConns {
|
||||
}
|
||||
|
||||
func makeAndCommitGoodBlock(
|
||||
t *testing.T,
|
||||
state sm.State,
|
||||
height int64,
|
||||
lastCommit *types.Commit,
|
||||
proposerAddr []byte,
|
||||
blockExec *sm.BlockExecutor,
|
||||
privVals map[string]types.PrivValidator,
|
||||
evidence []types.Evidence) (sm.State, types.BlockID, *types.Commit, error) {
|
||||
evidence []types.Evidence) (sm.State, types.BlockID, *types.ExtendedCommit) {
|
||||
t.Helper()
|
||||
|
||||
// A good block passes
|
||||
state, blockID, err := makeAndApplyGoodBlock(state, height, lastCommit, proposerAddr, blockExec, evidence)
|
||||
if err != nil {
|
||||
return state, types.BlockID{}, nil, err
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// Simulate a lastCommit for this block from all validators for the next height
|
||||
commit, err := makeValidCommit(height, blockID, state.Validators, privVals)
|
||||
if err != nil {
|
||||
return state, types.BlockID{}, nil, err
|
||||
}
|
||||
return state, blockID, commit, nil
|
||||
extCommit, _ := makeValidExtendedCommit(t, height, blockID, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
|
||||
return state, blockID, extCommit
|
||||
}
|
||||
|
||||
func makeAndApplyGoodBlock(state sm.State, height int64, lastCommit *types.Commit, proposerAddr []byte,
|
||||
@@ -83,22 +84,29 @@ func makeBlock(state sm.State, height int64, c *types.Commit) *types.Block {
|
||||
)
|
||||
}
|
||||
|
||||
func makeValidCommit(
|
||||
func makeValidExtendedCommit(
|
||||
t *testing.T,
|
||||
height int64,
|
||||
blockID types.BlockID,
|
||||
vals *types.ValidatorSet,
|
||||
privVals map[string]types.PrivValidator,
|
||||
) (*types.Commit, error) {
|
||||
sigs := make([]types.CommitSig, 0)
|
||||
) (*types.ExtendedCommit, []*types.Vote) {
|
||||
t.Helper()
|
||||
sigs := make([]types.ExtendedCommitSig, vals.Size())
|
||||
votes := make([]*types.Vote, vals.Size())
|
||||
for i := 0; i < vals.Size(); i++ {
|
||||
_, val := vals.GetByIndex(int32(i))
|
||||
vote, err := types.MakeVote(height, blockID, vals, privVals[val.Address.String()], chainID, time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigs = append(sigs, vote.CommitSig())
|
||||
vote, err := test.MakeVote(privVals[val.Address.String()], chainID, int32(i), height, 0, 2, blockID, time.Now())
|
||||
require.NoError(t, err)
|
||||
sigs[i] = vote.ExtendedCommitSig()
|
||||
votes[i] = vote
|
||||
}
|
||||
return types.NewCommit(height, 0, blockID, sigs), nil
|
||||
|
||||
return &types.ExtendedCommit{
|
||||
Height: height,
|
||||
BlockID: blockID,
|
||||
ExtendedSignatures: sigs,
|
||||
}, votes
|
||||
}
|
||||
|
||||
func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) {
|
||||
|
||||
@@ -195,6 +195,11 @@ func (_m *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
|
||||
_m.Called(block, blockParts, seenCommit)
|
||||
}
|
||||
|
||||
// SaveBlockWithExtendedCommit provides a mock function with given fields: block, blockParts, seenExtendedCommit
|
||||
func (_m *BlockStore) SaveBlockWithExtendedCommit(block *types.Block, blockParts *types.PartSet, seenExtendedCommit *types.ExtendedCommit) {
|
||||
_m.Called(block, blockParts, seenExtendedCommit)
|
||||
}
|
||||
|
||||
// Size provides a mock function with given fields:
|
||||
func (_m *BlockStore) Size() int64 {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -25,6 +25,7 @@ type BlockStore interface {
|
||||
LoadBlock(height int64) *types.Block
|
||||
|
||||
SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit)
|
||||
SaveBlockWithExtendedCommit(block *types.Block, blockParts *types.PartSet, seenExtendedCommit *types.ExtendedCommit)
|
||||
|
||||
PruneBlocks(height int64) (uint64, error)
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ func TestValidateBlockHeader(t *testing.T) {
|
||||
sm.EmptyEvidencePool{},
|
||||
)
|
||||
lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
|
||||
var lastExtCommit *types.ExtendedCommit
|
||||
|
||||
// some bad values
|
||||
wrongHash := tmhash.Sum([]byte("this hash is wrong"))
|
||||
@@ -101,11 +102,17 @@ func TestValidateBlockHeader(t *testing.T) {
|
||||
/*
|
||||
A good block passes
|
||||
*/
|
||||
var err error
|
||||
state, _, lastCommit, err = makeAndCommitGoodBlock(
|
||||
state, _, lastExtCommit = makeAndCommitGoodBlock(t,
|
||||
state, height, lastCommit, state.Validators.GetProposer().Address, blockExec, privVals, nil)
|
||||
require.NoError(t, err, "height %d", height)
|
||||
lastCommit = lastExtCommit.ToCommit()
|
||||
}
|
||||
|
||||
nextHeight := validationTestsStopHeight
|
||||
block := makeBlock(state, nextHeight, lastCommit)
|
||||
state.InitialHeight = nextHeight + 1
|
||||
err := blockExec.ValidateBlock(state, block)
|
||||
require.Error(t, err, "expected an error when state is ahead of block")
|
||||
assert.Contains(t, err.Error(), "lower than initial height")
|
||||
}
|
||||
|
||||
func TestValidateBlockCommit(t *testing.T) {
|
||||
@@ -137,6 +144,7 @@ func TestValidateBlockCommit(t *testing.T) {
|
||||
sm.EmptyEvidencePool{},
|
||||
)
|
||||
lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
|
||||
var lastExtCommit *types.ExtendedCommit
|
||||
wrongSigsCommit := types.NewCommit(1, 0, types.BlockID{}, nil)
|
||||
badPrivVal := types.NewMockPV()
|
||||
|
||||
@@ -188,7 +196,8 @@ func TestValidateBlockCommit(t *testing.T) {
|
||||
*/
|
||||
var err error
|
||||
var blockID types.BlockID
|
||||
state, blockID, lastCommit, err = makeAndCommitGoodBlock(
|
||||
state, blockID, lastExtCommit = makeAndCommitGoodBlock(
|
||||
t,
|
||||
state,
|
||||
height,
|
||||
lastCommit,
|
||||
@@ -197,7 +206,7 @@ func TestValidateBlockCommit(t *testing.T) {
|
||||
privVals,
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err, "height %d", height)
|
||||
lastCommit = lastExtCommit.ToCommit()
|
||||
|
||||
/*
|
||||
wrongSigsCommit is fine except for the extra bad precommit
|
||||
@@ -276,6 +285,7 @@ func TestValidateBlockEvidence(t *testing.T) {
|
||||
evpool,
|
||||
)
|
||||
lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
|
||||
var lastExtCommit *types.ExtendedCommit
|
||||
|
||||
for height := int64(1); height < validationTestsStopHeight; height++ {
|
||||
proposerAddr := state.Validators.GetProposer().Address
|
||||
@@ -320,8 +330,8 @@ func TestValidateBlockEvidence(t *testing.T) {
|
||||
evidence = append(evidence, newEv)
|
||||
}
|
||||
|
||||
var err error
|
||||
state, _, lastCommit, err = makeAndCommitGoodBlock(
|
||||
state, _, lastExtCommit = makeAndCommitGoodBlock(
|
||||
t,
|
||||
state,
|
||||
height,
|
||||
lastCommit,
|
||||
@@ -330,6 +340,6 @@ func TestValidateBlockEvidence(t *testing.T) {
|
||||
privVals,
|
||||
evidence,
|
||||
)
|
||||
require.NoError(t, err, "height %d", height)
|
||||
lastCommit = lastExtCommit.ToCommit()
|
||||
}
|
||||
}
|
||||
|
||||
+99
-27
@@ -1,6 +1,7 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
@@ -240,6 +241,29 @@ func (bs *BlockStore) LoadBlockCommit(height int64) *types.Commit {
|
||||
return commit
|
||||
}
|
||||
|
||||
// LoadExtendedCommit returns the ExtendedCommit for the given height.
|
||||
// The extended commit is not guaranteed to contain the same +2/3 precommits data
|
||||
// as the commit in the block.
|
||||
func (bs *BlockStore) LoadBlockExtendedCommit(height int64) *types.ExtendedCommit {
|
||||
pbec := new(tmproto.ExtendedCommit)
|
||||
bz, err := bs.db.Get(calcExtCommitKey(height))
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("fetching extended commit: %w", err))
|
||||
}
|
||||
if len(bz) == 0 {
|
||||
return nil
|
||||
}
|
||||
err = proto.Unmarshal(bz, pbec)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("decoding extended commit: %w", err))
|
||||
}
|
||||
extCommit, err := types.ExtendedCommitFromProto(pbec)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("converting extended commit: %w", err))
|
||||
}
|
||||
return extCommit
|
||||
}
|
||||
|
||||
// LoadSeenCommit returns the locally seen Commit for the given height.
|
||||
// This is useful when we've seen a commit, but there has not yet been
|
||||
// a new block at `height + 1` that includes this commit in its block.LastCommit.
|
||||
@@ -353,15 +377,69 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
|
||||
if block == nil {
|
||||
panic("BlockStore can only save a non-nil block")
|
||||
}
|
||||
batch := bs.db.NewBatch()
|
||||
if err := bs.saveBlockToBatch(batch, block, blockParts, seenCommit); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := batch.WriteSync(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := batch.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// SaveBlockWithExtendedCommit persists the given block, blockParts, and
|
||||
// seenExtendedCommit to the underlying db. seenExtendedCommit is stored under
|
||||
// two keys in the database: as the seenCommit and as the ExtendedCommit data for the
|
||||
// height. This allows the vote extension data to be persisted for all blocks
|
||||
// that are saved.
|
||||
func (bs *BlockStore) SaveBlockWithExtendedCommit(block *types.Block, blockParts *types.PartSet, seenExtendedCommit *types.ExtendedCommit) {
|
||||
if block == nil {
|
||||
panic("BlockStore can only save a non-nil block")
|
||||
}
|
||||
if err := seenExtendedCommit.EnsureExtensions(); err != nil {
|
||||
panic(fmt.Errorf("saving block with extensions: %w", err))
|
||||
}
|
||||
batch := bs.db.NewBatch()
|
||||
if err := bs.saveBlockToBatch(batch, block, blockParts, seenExtendedCommit.ToCommit()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
height := block.Height
|
||||
|
||||
pbec := seenExtendedCommit.ToProto()
|
||||
extCommitBytes := mustEncode(pbec)
|
||||
if err := batch.Set(calcExtCommitKey(height), extCommitBytes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := batch.WriteSync(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := batch.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (bs *BlockStore) saveBlockToBatch(batch dbm.Batch, block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) error {
|
||||
if block == nil {
|
||||
panic("BlockStore can only save a non-nil block")
|
||||
}
|
||||
|
||||
height := block.Height
|
||||
hash := block.Hash()
|
||||
|
||||
if g, w := height, bs.Height()+1; bs.Base() > 0 && g != w {
|
||||
panic(fmt.Sprintf("BlockStore can only save contiguous blocks. Wanted %v, got %v", w, g))
|
||||
return fmt.Errorf("BlockStore can only save contiguous blocks. Wanted %v, got %v", w, g)
|
||||
}
|
||||
if !blockParts.IsComplete() {
|
||||
panic("BlockStore can only save complete block part sets")
|
||||
return errors.New("BlockStore can only save complete block part sets")
|
||||
}
|
||||
if height != seenCommit.Height {
|
||||
return fmt.Errorf("BlockStore cannot save seen commit of a different height (block: %d, commit: %d)", height, seenCommit.Height)
|
||||
}
|
||||
|
||||
// Save block parts. This must be done before the block meta, since callers
|
||||
@@ -370,57 +448,47 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
|
||||
// complete as soon as the block meta is written.
|
||||
for i := 0; i < int(blockParts.Total()); i++ {
|
||||
part := blockParts.GetPart(i)
|
||||
bs.saveBlockPart(height, i, part)
|
||||
bs.saveBlockPart(height, i, part, batch)
|
||||
}
|
||||
|
||||
// Save block meta
|
||||
blockMeta := types.NewBlockMeta(block, blockParts)
|
||||
pbm := blockMeta.ToProto()
|
||||
if pbm == nil {
|
||||
panic("nil blockmeta")
|
||||
return errors.New("nil blockmeta")
|
||||
}
|
||||
|
||||
metaBytes := mustEncode(pbm)
|
||||
if err := bs.db.Set(calcBlockMetaKey(height), metaBytes); err != nil {
|
||||
panic(err)
|
||||
if err := batch.Set(calcBlockMetaKey(height), metaBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := bs.db.Set(calcBlockHashKey(hash), []byte(fmt.Sprintf("%d", height))); err != nil {
|
||||
panic(err)
|
||||
|
||||
if err := batch.Set(calcBlockHashKey(hash), []byte(fmt.Sprintf("%d", height))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save block commit (duplicate and separate from the Block)
|
||||
pbc := block.LastCommit.ToProto()
|
||||
blockCommitBytes := mustEncode(pbc)
|
||||
if err := bs.db.Set(calcBlockCommitKey(height-1), blockCommitBytes); err != nil {
|
||||
panic(err)
|
||||
if err := batch.Set(calcBlockCommitKey(height-1), blockCommitBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save seen commit (seen +2/3 precommits for block)
|
||||
// NOTE: we can delete this at a later height
|
||||
pbsc := seenCommit.ToProto()
|
||||
seenCommitBytes := mustEncode(pbsc)
|
||||
if err := bs.db.Set(calcSeenCommitKey(height), seenCommitBytes); err != nil {
|
||||
panic(err)
|
||||
if err := batch.Set(calcSeenCommitKey(height), seenCommitBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Done!
|
||||
bs.mtx.Lock()
|
||||
bs.height = height
|
||||
if bs.base == 0 {
|
||||
bs.base = height
|
||||
}
|
||||
bs.mtx.Unlock()
|
||||
|
||||
// Save new BlockStoreState descriptor. This also flushes the database.
|
||||
bs.saveState()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *BlockStore) saveBlockPart(height int64, index int, part *types.Part) {
|
||||
func (bs *BlockStore) saveBlockPart(height int64, index int, part *types.Part, batch dbm.Batch) {
|
||||
pbp, err := part.ToProto()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unable to make part into proto: %w", err))
|
||||
}
|
||||
partBytes := mustEncode(pbp)
|
||||
if err := bs.db.Set(calcBlockPartKey(height, index), partBytes); err != nil {
|
||||
if err := batch.Set(calcBlockPartKey(height, index), partBytes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -471,6 +539,10 @@ func calcBlockHashKey(hash []byte) []byte {
|
||||
return []byte(fmt.Sprintf("BH:%x", hash))
|
||||
}
|
||||
|
||||
func calcExtCommitKey(height int64) []byte {
|
||||
return []byte(fmt.Sprintf("EC:%v", height))
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
var blockStoreKey = []byte("blockStore")
|
||||
|
||||
+142
-57
@@ -1,9 +1,7 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
stdlog "log"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
@@ -18,7 +16,6 @@ import (
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/internal/test"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
tmstore "github.com/tendermint/tendermint/proto/tendermint/store"
|
||||
tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
|
||||
@@ -32,22 +29,32 @@ import (
|
||||
// test.
|
||||
type cleanupFunc func()
|
||||
|
||||
// make a Commit with a single vote containing just the height and a timestamp
|
||||
func makeTestCommit(height int64, timestamp time.Time) *types.Commit {
|
||||
commitSigs := []types.CommitSig{{
|
||||
BlockIDFlag: types.BlockIDFlagCommit,
|
||||
ValidatorAddress: tmrand.Bytes(crypto.AddressSize),
|
||||
Timestamp: timestamp,
|
||||
Signature: []byte("Signature"),
|
||||
// make an extended commit with a single vote containing just the height and a
|
||||
// timestamp
|
||||
func makeTestExtCommit(height int64, timestamp time.Time) *types.ExtendedCommit {
|
||||
extCommitSigs := []types.ExtendedCommitSig{{
|
||||
CommitSig: types.CommitSig{
|
||||
BlockIDFlag: types.BlockIDFlagCommit,
|
||||
ValidatorAddress: tmrand.Bytes(crypto.AddressSize),
|
||||
Timestamp: timestamp,
|
||||
Signature: []byte("Signature"),
|
||||
},
|
||||
ExtensionSignature: []byte("ExtensionSignature"),
|
||||
}}
|
||||
return types.NewCommit(height, 0,
|
||||
types.BlockID{Hash: []byte(""), PartSetHeader: types.PartSetHeader{Hash: []byte(""), Total: 2}}, commitSigs)
|
||||
return &types.ExtendedCommit{
|
||||
Height: height,
|
||||
BlockID: types.BlockID{
|
||||
Hash: crypto.CRandBytes(32),
|
||||
PartSetHeader: types.PartSetHeader{Hash: crypto.CRandBytes(32), Total: 2},
|
||||
},
|
||||
ExtendedSignatures: extCommitSigs,
|
||||
}
|
||||
}
|
||||
|
||||
func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore, cleanupFunc) {
|
||||
func makeStateAndBlockStore(t *testing.T) (sm.State, *BlockStore) {
|
||||
config := cfg.ResetTestRoot("blockchain_reactor_test")
|
||||
// blockDB := dbm.NewDebugDB("blockDB", dbm.NewMemDB())
|
||||
// stateDB := dbm.NewDebugDB("stateDB", dbm.NewMemDB())
|
||||
t.Cleanup(func() { os.RemoveAll(config.RootDir) })
|
||||
|
||||
blockDB := dbm.NewMemDB()
|
||||
stateDB := dbm.NewMemDB()
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
@@ -57,7 +64,7 @@ func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore, cleanupFu
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error constructing state from genesis file: %w", err))
|
||||
}
|
||||
return state, NewBlockStore(blockDB), func() { os.RemoveAll(config.RootDir) }
|
||||
return state, NewBlockStore(blockDB)
|
||||
}
|
||||
|
||||
func TestLoadBlockStoreState(t *testing.T) {
|
||||
@@ -134,29 +141,28 @@ var (
|
||||
seenCommit1 *types.Commit
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var cleanup cleanupFunc
|
||||
var err error
|
||||
state, _, cleanup = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
|
||||
block = state.MakeBlock(state.LastBlockHeight+1, test.MakeNTxs(state.LastBlockHeight+1, 10), new(types.Commit), nil, state.Validators.GetProposer().Address)
|
||||
// func TestMain(m *testing.M) {
|
||||
// var cleanup cleanupFunc
|
||||
// var err error
|
||||
// state, _, cleanup = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
|
||||
// block = state.MakeBlock(state.LastBlockHeight+1, test.MakeNTxs(state.LastBlockHeight+1, 10), new(types.Commit), nil, state.Validators.GetProposer().Address)
|
||||
|
||||
partSet, err = block.MakePartSet(2)
|
||||
if err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
part1 = partSet.GetPart(0)
|
||||
part2 = partSet.GetPart(1)
|
||||
seenCommit1 = makeTestCommit(10, tmtime.Now())
|
||||
code := m.Run()
|
||||
cleanup()
|
||||
os.Exit(code)
|
||||
}
|
||||
// partSet, err = block.MakePartSet(2)
|
||||
// if err != nil {
|
||||
// stdlog.Fatal(err)
|
||||
// }
|
||||
// part1 = partSet.GetPart(0)
|
||||
// part2 = partSet.GetPart(1)
|
||||
// seenCommit1 = makeTestExtCommit(10, tmtime.Now())
|
||||
// code := m.Run()
|
||||
// cleanup()
|
||||
// os.Exit(code)
|
||||
// }
|
||||
|
||||
// TODO: This test should be simplified ...
|
||||
|
||||
func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
state, bs, cleanup := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
|
||||
defer cleanup()
|
||||
state, bs := makeStateAndBlockStore(t)
|
||||
require.Equal(t, bs.Base(), int64(0), "initially the base should be zero")
|
||||
require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
|
||||
|
||||
@@ -172,8 +178,8 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
block := state.MakeBlock(bs.Height()+1, nil, new(types.Commit), nil, state.Validators.GetProposer().Address)
|
||||
validPartSet, err := block.MakePartSet(2)
|
||||
require.NoError(t, err)
|
||||
seenCommit := makeTestCommit(10, tmtime.Now())
|
||||
bs.SaveBlock(block, partSet, seenCommit)
|
||||
seenCommit := makeTestExtCommit(10, tmtime.Now())
|
||||
bs.SaveBlockWithExtendedCommit(block, partSet, seenCommit)
|
||||
require.EqualValues(t, 1, bs.Base(), "expecting the new height to be changed")
|
||||
require.EqualValues(t, block.Header.Height, bs.Height(), "expecting the new height to be changed")
|
||||
|
||||
@@ -192,11 +198,11 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
|
||||
// End of setup, test data
|
||||
|
||||
commitAtH10 := makeTestCommit(10, tmtime.Now())
|
||||
commitAtH10 := makeTestExtCommit(10, tmtime.Now()).ToCommit()
|
||||
tuples := []struct {
|
||||
block *types.Block
|
||||
parts *types.PartSet
|
||||
seenCommit *types.Commit
|
||||
seenCommit *types.ExtendedCommit
|
||||
wantPanic string
|
||||
wantErr bool
|
||||
|
||||
@@ -209,7 +215,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
{
|
||||
block: newBlock(header1, commitAtH10),
|
||||
parts: validPartSet,
|
||||
seenCommit: seenCommit1,
|
||||
seenCommit: seenCommit,
|
||||
},
|
||||
|
||||
{
|
||||
@@ -225,10 +231,10 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
ChainID: "block_test",
|
||||
Time: tmtime.Now(),
|
||||
ProposerAddress: tmrand.Bytes(crypto.AddressSize)},
|
||||
makeTestCommit(5, tmtime.Now()),
|
||||
makeTestExtCommit(5, tmtime.Now()).ToCommit(),
|
||||
),
|
||||
parts: validPartSet,
|
||||
seenCommit: makeTestCommit(5, tmtime.Now()),
|
||||
seenCommit: makeTestExtCommit(5, tmtime.Now()),
|
||||
},
|
||||
|
||||
{
|
||||
@@ -240,7 +246,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
{
|
||||
block: newBlock(header1, commitAtH10),
|
||||
parts: validPartSet,
|
||||
seenCommit: seenCommit1,
|
||||
seenCommit: seenCommit,
|
||||
corruptCommitInDB: true, // Corrupt the DB's commit entry
|
||||
wantPanic: "error reading block commit",
|
||||
},
|
||||
@@ -248,7 +254,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
{
|
||||
block: newBlock(header1, commitAtH10),
|
||||
parts: validPartSet,
|
||||
seenCommit: seenCommit1,
|
||||
seenCommit: seenCommit,
|
||||
wantPanic: "unmarshal to tmproto.BlockMeta",
|
||||
corruptBlockInDB: true, // Corrupt the DB's block entry
|
||||
},
|
||||
@@ -256,7 +262,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
{
|
||||
block: newBlock(header1, commitAtH10),
|
||||
parts: validPartSet,
|
||||
seenCommit: seenCommit1,
|
||||
seenCommit: seenCommit,
|
||||
|
||||
// Expecting no error and we want a nil back
|
||||
eraseSeenCommitInDB: true,
|
||||
@@ -265,7 +271,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
{
|
||||
block: newBlock(header1, commitAtH10),
|
||||
parts: validPartSet,
|
||||
seenCommit: seenCommit1,
|
||||
seenCommit: seenCommit,
|
||||
|
||||
corruptSeenCommitInDB: true,
|
||||
wantPanic: "error reading block seen commit",
|
||||
@@ -274,7 +280,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
{
|
||||
block: newBlock(header1, commitAtH10),
|
||||
parts: validPartSet,
|
||||
seenCommit: seenCommit1,
|
||||
seenCommit: seenCommit,
|
||||
|
||||
// Expecting no error and we want a nil back
|
||||
eraseCommitInDB: true,
|
||||
@@ -294,7 +300,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
bs, db := freshBlockStore()
|
||||
// SaveBlock
|
||||
res, err, panicErr := doFn(func() (interface{}, error) {
|
||||
bs.SaveBlock(tuple.block, tuple.parts, tuple.seenCommit)
|
||||
bs.SaveBlockWithExtendedCommit(tuple.block, tuple.parts, tuple.seenCommit)
|
||||
if tuple.block == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -364,6 +370,86 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSaveBlockWithExtendedCommitPanicOnAbsentExtension tests that saving a
|
||||
// block with an extended commit panics when the extension data is absent.
|
||||
func TestSaveBlockWithExtendedCommitPanicOnAbsentExtension(t *testing.T) {
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
malleateCommit func(*types.ExtendedCommit)
|
||||
shouldPanic bool
|
||||
}{
|
||||
{
|
||||
name: "basic save",
|
||||
malleateCommit: func(_ *types.ExtendedCommit) {},
|
||||
shouldPanic: false,
|
||||
},
|
||||
{
|
||||
name: "save commit with no extensions",
|
||||
malleateCommit: func(c *types.ExtendedCommit) {
|
||||
c.StripExtensions()
|
||||
},
|
||||
shouldPanic: true,
|
||||
},
|
||||
} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
state, bs := makeStateAndBlockStore(t)
|
||||
block := test.MakeBlock(state)
|
||||
seenCommit := makeTestExtCommit(block.Header.Height, tmtime.Now())
|
||||
ps, err := block.MakePartSet(2)
|
||||
require.NoError(t, err)
|
||||
testCase.malleateCommit(seenCommit)
|
||||
if testCase.shouldPanic {
|
||||
require.Panics(t, func() {
|
||||
bs.SaveBlockWithExtendedCommit(block, ps, seenCommit)
|
||||
})
|
||||
} else {
|
||||
bs.SaveBlockWithExtendedCommit(block, ps, seenCommit)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadBlockExtendedCommit tests loading the extended commit for a previously
|
||||
// saved block. The load method should return nil when only a commit was saved and
|
||||
// return the extended commit otherwise.
|
||||
func TestLoadBlockExtendedCommit(t *testing.T) {
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
saveExtended bool
|
||||
expectResult bool
|
||||
}{
|
||||
{
|
||||
name: "save commit",
|
||||
saveExtended: false,
|
||||
expectResult: false,
|
||||
},
|
||||
{
|
||||
name: "save extended commit",
|
||||
saveExtended: true,
|
||||
expectResult: true,
|
||||
},
|
||||
} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
state, bs := makeStateAndBlockStore(t)
|
||||
block := test.MakeBlock(state)
|
||||
seenCommit := makeTestExtCommit(block.Header.Height, tmtime.Now())
|
||||
ps, err := block.MakePartSet(2)
|
||||
require.NoError(t, err)
|
||||
if testCase.saveExtended {
|
||||
bs.SaveBlockWithExtendedCommit(block, ps, seenCommit)
|
||||
} else {
|
||||
bs.SaveBlock(block, ps, seenCommit.ToCommit())
|
||||
}
|
||||
res := bs.LoadBlockExtendedCommit(block.Height)
|
||||
if testCase.expectResult {
|
||||
require.Equal(t, seenCommit, res)
|
||||
} else {
|
||||
require.Nil(t, res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadBaseMeta(t *testing.T) {
|
||||
config := cfg.ResetTestRoot("blockchain_reactor_test")
|
||||
defer os.RemoveAll(config.RootDir)
|
||||
@@ -378,8 +464,8 @@ func TestLoadBaseMeta(t *testing.T) {
|
||||
block := state.MakeBlock(h, test.MakeNTxs(h, 10), new(types.Commit), nil, state.Validators.GetProposer().Address)
|
||||
partSet, err := block.MakePartSet(2)
|
||||
require.NoError(t, err)
|
||||
seenCommit := makeTestCommit(h, tmtime.Now())
|
||||
bs.SaveBlock(block, partSet, seenCommit)
|
||||
seenCommit := makeTestExtCommit(h, tmtime.Now())
|
||||
bs.SaveBlockWithExtendedCommit(block, partSet, seenCommit)
|
||||
}
|
||||
|
||||
_, err = bs.PruneBlocks(4)
|
||||
@@ -449,8 +535,8 @@ func TestPruneBlocks(t *testing.T) {
|
||||
block := state.MakeBlock(h, test.MakeNTxs(h, 10), new(types.Commit), nil, state.Validators.GetProposer().Address)
|
||||
partSet, err := block.MakePartSet(2)
|
||||
require.NoError(t, err)
|
||||
seenCommit := makeTestCommit(h, tmtime.Now())
|
||||
bs.SaveBlock(block, partSet, seenCommit)
|
||||
seenCommit := makeTestExtCommit(h, tmtime.Now())
|
||||
bs.SaveBlockWithExtendedCommit(block, partSet, seenCommit)
|
||||
}
|
||||
|
||||
assert.EqualValues(t, 1, bs.Base())
|
||||
@@ -566,8 +652,8 @@ func TestLoadBlockMetaByHash(t *testing.T) {
|
||||
b1 := state.MakeBlock(state.LastBlockHeight+1, test.MakeNTxs(state.LastBlockHeight+1, 10), new(types.Commit), nil, state.Validators.GetProposer().Address)
|
||||
partSet, err := b1.MakePartSet(2)
|
||||
require.NoError(t, err)
|
||||
seenCommit := makeTestCommit(1, tmtime.Now())
|
||||
bs.SaveBlock(b1, partSet, seenCommit)
|
||||
seenCommit := makeTestExtCommit(1, tmtime.Now())
|
||||
bs.SaveBlockWithExtendedCommit(b1, partSet, seenCommit)
|
||||
|
||||
baseBlock := bs.LoadBlockMetaByHash(b1.Hash())
|
||||
assert.EqualValues(t, b1.Header.Height, baseBlock.Header.Height)
|
||||
@@ -576,15 +662,14 @@ func TestLoadBlockMetaByHash(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBlockFetchAtHeight(t *testing.T) {
|
||||
state, bs, cleanup := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer)))
|
||||
defer cleanup()
|
||||
state, bs := makeStateAndBlockStore(t)
|
||||
require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
|
||||
block := state.MakeBlock(bs.Height()+1, nil, new(types.Commit), nil, state.Validators.GetProposer().Address)
|
||||
|
||||
partSet, err := block.MakePartSet(2)
|
||||
require.NoError(t, err)
|
||||
seenCommit := makeTestCommit(10, tmtime.Now())
|
||||
bs.SaveBlock(block, partSet, seenCommit)
|
||||
seenCommit := makeTestExtCommit(10, tmtime.Now())
|
||||
bs.SaveBlockWithExtendedCommit(block, partSet, seenCommit)
|
||||
require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed")
|
||||
|
||||
blockAtHeight := bs.LoadBlock(bs.Height())
|
||||
|
||||
@@ -91,11 +91,11 @@ func InjectEvidence(ctx context.Context, r *rand.Rand, testnet *e2e.Testnet, amo
|
||||
for i := 1; i <= amount; i++ {
|
||||
if i%lightClientEvidenceRatio == 0 {
|
||||
ev, err = generateLightClientAttackEvidence(
|
||||
ctx, privVals, evidenceHeight, valSet, testnet.Name, blockRes.Block.Time,
|
||||
privVals, evidenceHeight, valSet, testnet.Name, blockRes.Block.Time,
|
||||
)
|
||||
} else {
|
||||
ev, err = generateDuplicateVoteEvidence(
|
||||
ctx, privVals, evidenceHeight, valSet, testnet.Name, blockRes.Block.Time,
|
||||
privVals, evidenceHeight, valSet, testnet.Name, blockRes.Block.Time,
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
@@ -142,7 +142,6 @@ func getPrivateValidatorKeys(testnet *e2e.Testnet) ([]types.MockPV, error) {
|
||||
// creates evidence of a lunatic attack. The height provided is the common height.
|
||||
// The forged height happens 2 blocks later.
|
||||
func generateLightClientAttackEvidence(
|
||||
ctx context.Context,
|
||||
privVals []types.MockPV,
|
||||
height int64,
|
||||
vals *types.ValidatorSet,
|
||||
@@ -157,7 +156,7 @@ func generateLightClientAttackEvidence(
|
||||
|
||||
// add a new bogus validator and remove an existing one to
|
||||
// vary the validator set slightly
|
||||
pv, conflictingVals, err := mutateValidatorSet(ctx, privVals, vals)
|
||||
pv, conflictingVals, err := mutateValidatorSet(privVals, vals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -193,7 +192,6 @@ func generateLightClientAttackEvidence(
|
||||
// generateDuplicateVoteEvidence picks a random validator from the val set and
|
||||
// returns duplicate vote evidence against the validator
|
||||
func generateDuplicateVoteEvidence(
|
||||
ctx context.Context,
|
||||
privVals []types.MockPV,
|
||||
height int64,
|
||||
vals *types.ValidatorSet,
|
||||
@@ -286,9 +284,9 @@ func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.Bloc
|
||||
}
|
||||
}
|
||||
|
||||
func mutateValidatorSet(ctx context.Context, privVals []types.MockPV, vals *types.ValidatorSet,
|
||||
func mutateValidatorSet(privVals []types.MockPV, vals *types.ValidatorSet,
|
||||
) ([]types.PrivValidator, *types.ValidatorSet, error) {
|
||||
newVal, newPrivVal, err := test.Validator(ctx, 10)
|
||||
newVal, newPrivVal, err := test.Validator(10)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
+374
-3
@@ -875,7 +875,7 @@ func (commit *Commit) ValidateBasic() error {
|
||||
}
|
||||
|
||||
if commit.Height >= 1 {
|
||||
if commit.BlockID.IsZero() {
|
||||
if commit.BlockID.IsNil() {
|
||||
return errors.New("commit cannot be for nil block")
|
||||
}
|
||||
|
||||
@@ -987,6 +987,360 @@ func CommitFromProto(cp *tmproto.Commit) (*Commit, error) {
|
||||
return commit, commit.ValidateBasic()
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
// ExtendedCommitSig contains a commit signature along with its corresponding
|
||||
// vote extension and vote extension signature.
|
||||
type ExtendedCommitSig struct {
|
||||
CommitSig // Commit signature
|
||||
Extension []byte // Vote extension
|
||||
ExtensionSignature []byte // Vote extension signature
|
||||
}
|
||||
|
||||
// NewExtendedCommitSigAbsent returns new ExtendedCommitSig with
|
||||
// BlockIDFlagAbsent. Other fields are all empty.
|
||||
func NewExtendedCommitSigAbsent() ExtendedCommitSig {
|
||||
return ExtendedCommitSig{CommitSig: NewCommitSigAbsent()}
|
||||
}
|
||||
|
||||
// String returns a string representation of an ExtendedCommitSig.
|
||||
//
|
||||
// 1. commit sig
|
||||
// 2. first 6 bytes of vote extension
|
||||
// 3. first 6 bytes of vote extension signature
|
||||
func (ecs ExtendedCommitSig) String() string {
|
||||
return fmt.Sprintf("ExtendedCommitSig{%s with %X %X}",
|
||||
ecs.CommitSig,
|
||||
tmbytes.Fingerprint(ecs.Extension),
|
||||
tmbytes.Fingerprint(ecs.ExtensionSignature),
|
||||
)
|
||||
}
|
||||
|
||||
// ValidateBasic checks whether the structure is well-formed.
|
||||
func (ecs ExtendedCommitSig) ValidateBasic() error {
|
||||
if err := ecs.CommitSig.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ecs.BlockIDFlag == BlockIDFlagCommit {
|
||||
if len(ecs.Extension) > MaxVoteExtensionSize {
|
||||
return fmt.Errorf("vote extension is too big (max: %d)", MaxVoteExtensionSize)
|
||||
}
|
||||
if len(ecs.ExtensionSignature) > MaxSignatureSize {
|
||||
return fmt.Errorf("vote extension signature is too big (max: %d)", MaxSignatureSize)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(ecs.ExtensionSignature) == 0 && len(ecs.Extension) != 0 {
|
||||
return errors.New("vote extension signature absent on vote with extension")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureExtensions validates that a vote extensions signature is present for
|
||||
// this ExtendedCommitSig.
|
||||
func (ecs ExtendedCommitSig) EnsureExtension() error {
|
||||
if ecs.BlockIDFlag == BlockIDFlagCommit && len(ecs.ExtensionSignature) == 0 {
|
||||
return errors.New("vote extension data is missing")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToProto converts the ExtendedCommitSig to its Protobuf representation.
|
||||
func (ecs *ExtendedCommitSig) ToProto() *tmproto.ExtendedCommitSig {
|
||||
if ecs == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &tmproto.ExtendedCommitSig{
|
||||
BlockIdFlag: tmproto.BlockIDFlag(ecs.BlockIDFlag),
|
||||
ValidatorAddress: ecs.ValidatorAddress,
|
||||
Timestamp: ecs.Timestamp,
|
||||
Signature: ecs.Signature,
|
||||
Extension: ecs.Extension,
|
||||
ExtensionSignature: ecs.ExtensionSignature,
|
||||
}
|
||||
}
|
||||
|
||||
// FromProto populates the ExtendedCommitSig with values from the given
|
||||
// Protobuf representation. Returns an error if the ExtendedCommitSig is
|
||||
// invalid.
|
||||
func (ecs *ExtendedCommitSig) FromProto(ecsp tmproto.ExtendedCommitSig) error {
|
||||
ecs.BlockIDFlag = BlockIDFlag(ecsp.BlockIdFlag)
|
||||
ecs.ValidatorAddress = ecsp.ValidatorAddress
|
||||
ecs.Timestamp = ecsp.Timestamp
|
||||
ecs.Signature = ecsp.Signature
|
||||
ecs.Extension = ecsp.Extension
|
||||
ecs.ExtensionSignature = ecsp.ExtensionSignature
|
||||
|
||||
return ecs.ValidateBasic()
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
// ExtendedCommit is similar to Commit, except that its signatures also retain
|
||||
// their corresponding vote extensions and vote extension signatures.
|
||||
type ExtendedCommit struct {
|
||||
Height int64
|
||||
Round int32
|
||||
BlockID BlockID
|
||||
ExtendedSignatures []ExtendedCommitSig
|
||||
|
||||
bitArray *bits.BitArray
|
||||
}
|
||||
|
||||
// Clone creates a deep copy of this extended commit.
|
||||
func (ec *ExtendedCommit) Clone() *ExtendedCommit {
|
||||
sigs := make([]ExtendedCommitSig, len(ec.ExtendedSignatures))
|
||||
copy(sigs, ec.ExtendedSignatures)
|
||||
ecc := *ec
|
||||
ecc.ExtendedSignatures = sigs
|
||||
return &ecc
|
||||
}
|
||||
|
||||
// ToExtendedVoteSet constructs a VoteSet from the Commit and validator set.
|
||||
// Panics if signatures from the ExtendedCommit can't be added to the voteset.
|
||||
// Panics if any of the votes have invalid or absent vote extension data.
|
||||
// Inverse of VoteSet.MakeExtendedCommit().
|
||||
func (ec *ExtendedCommit) ToExtendedVoteSet(chainID string, vals *ValidatorSet) *VoteSet {
|
||||
voteSet := NewExtendedVoteSet(chainID, ec.Height, ec.Round, tmproto.PrecommitType, vals)
|
||||
ec.addSigsToVoteSet(voteSet)
|
||||
return voteSet
|
||||
}
|
||||
|
||||
// ToVoteSet constructs a VoteSet from the Commit and validator set.
|
||||
// Panics if signatures from the ExtendedCommit can't be added to the voteset.
|
||||
// Inverse of VoteSet.MakeExtendedCommit().
|
||||
func (ec *ExtendedCommit) ToVoteSet(chainID string, vals *ValidatorSet) *VoteSet {
|
||||
voteSet := NewVoteSet(chainID, ec.Height, ec.Round, tmproto.PrecommitType, vals)
|
||||
ec.addSigsToVoteSet(voteSet)
|
||||
return voteSet
|
||||
}
|
||||
|
||||
// addSigsToVoteSet adds all of the signature to voteSet.
|
||||
func (ec *ExtendedCommit) addSigsToVoteSet(voteSet *VoteSet) {
|
||||
for idx, ecs := range ec.ExtendedSignatures {
|
||||
if ecs.BlockIDFlag == BlockIDFlagAbsent {
|
||||
continue // OK, some precommits can be missing.
|
||||
}
|
||||
vote := ec.GetExtendedVote(int32(idx))
|
||||
if err := vote.ValidateBasic(); err != nil {
|
||||
panic(fmt.Errorf("failed to validate vote reconstructed from LastCommit: %w", err))
|
||||
}
|
||||
added, err := voteSet.AddVote(vote)
|
||||
if !added || err != nil {
|
||||
panic(fmt.Errorf("failed to reconstruct vote set from extended commit: %w", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToVoteSet constructs a VoteSet from the Commit and validator set.
|
||||
// Panics if signatures from the commit can't be added to the voteset.
|
||||
// Inverse of VoteSet.MakeCommit().
|
||||
func (commit *Commit) ToVoteSet(chainID string, vals *ValidatorSet) *VoteSet {
|
||||
voteSet := NewVoteSet(chainID, commit.Height, commit.Round, tmproto.PrecommitType, vals)
|
||||
for idx, cs := range commit.Signatures {
|
||||
if cs.BlockIDFlag == BlockIDFlagAbsent {
|
||||
continue // OK, some precommits can be missing.
|
||||
}
|
||||
vote := commit.GetVote(int32(idx))
|
||||
if err := vote.ValidateBasic(); err != nil {
|
||||
panic(fmt.Errorf("failed to validate vote reconstructed from commit: %w", err))
|
||||
}
|
||||
added, err := voteSet.AddVote(vote)
|
||||
if !added || err != nil {
|
||||
panic(fmt.Errorf("failed to reconstruct vote set from commit: %w", err))
|
||||
}
|
||||
}
|
||||
return voteSet
|
||||
}
|
||||
|
||||
// EnsureExtensions validates that a vote extensions signature is present for
|
||||
// every ExtendedCommitSig in the ExtendedCommit.
|
||||
func (ec *ExtendedCommit) EnsureExtensions() error {
|
||||
for _, ecs := range ec.ExtendedSignatures {
|
||||
if err := ecs.EnsureExtension(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StripExtensions removes all VoteExtension data from an ExtendedCommit. This
|
||||
// is useful when dealing with an ExendedCommit but vote extension data is
|
||||
// expected to be absent.
|
||||
func (ec *ExtendedCommit) StripExtensions() bool {
|
||||
stripped := false
|
||||
for idx := range ec.ExtendedSignatures {
|
||||
if len(ec.ExtendedSignatures[idx].Extension) > 0 || len(ec.ExtendedSignatures[idx].ExtensionSignature) > 0 {
|
||||
stripped = true
|
||||
}
|
||||
ec.ExtendedSignatures[idx].Extension = nil
|
||||
ec.ExtendedSignatures[idx].ExtensionSignature = nil
|
||||
}
|
||||
return stripped
|
||||
}
|
||||
|
||||
// ToCommit converts an ExtendedCommit to a Commit by removing all vote
|
||||
// extension-related fields.
|
||||
func (ec *ExtendedCommit) ToCommit() *Commit {
|
||||
cs := make([]CommitSig, len(ec.ExtendedSignatures))
|
||||
for idx, ecs := range ec.ExtendedSignatures {
|
||||
cs[idx] = ecs.CommitSig
|
||||
}
|
||||
return &Commit{
|
||||
Height: ec.Height,
|
||||
Round: ec.Round,
|
||||
BlockID: ec.BlockID,
|
||||
Signatures: cs,
|
||||
}
|
||||
}
|
||||
|
||||
// GetExtendedVote converts the ExtendedCommitSig for the given validator
|
||||
// index to a Vote with a vote extensions.
|
||||
// It panics if valIndex is out of range.
|
||||
func (ec *ExtendedCommit) GetExtendedVote(valIndex int32) *Vote {
|
||||
ecs := ec.ExtendedSignatures[valIndex]
|
||||
return &Vote{
|
||||
Type: tmproto.PrecommitType,
|
||||
Height: ec.Height,
|
||||
Round: ec.Round,
|
||||
BlockID: ecs.BlockID(ec.BlockID),
|
||||
Timestamp: ecs.Timestamp,
|
||||
ValidatorAddress: ecs.ValidatorAddress,
|
||||
ValidatorIndex: valIndex,
|
||||
Signature: ecs.Signature,
|
||||
Extension: ecs.Extension,
|
||||
ExtensionSignature: ecs.ExtensionSignature,
|
||||
}
|
||||
}
|
||||
|
||||
// Type returns the vote type of the extended commit, which is always
|
||||
// VoteTypePrecommit
|
||||
// Implements VoteSetReader.
|
||||
func (ec *ExtendedCommit) Type() byte { return byte(tmproto.PrecommitType) }
|
||||
|
||||
// GetHeight returns height of the extended commit.
|
||||
// Implements VoteSetReader.
|
||||
func (ec *ExtendedCommit) GetHeight() int64 { return ec.Height }
|
||||
|
||||
// GetRound returns height of the extended commit.
|
||||
// Implements VoteSetReader.
|
||||
func (ec *ExtendedCommit) GetRound() int32 { return ec.Round }
|
||||
|
||||
// Size returns the number of signatures in the extended commit.
|
||||
// Implements VoteSetReader.
|
||||
func (ec *ExtendedCommit) Size() int {
|
||||
if ec == nil {
|
||||
return 0
|
||||
}
|
||||
return len(ec.ExtendedSignatures)
|
||||
}
|
||||
|
||||
// BitArray returns a BitArray of which validators voted for BlockID or nil in
|
||||
// this extended commit.
|
||||
// Implements VoteSetReader.
|
||||
func (ec *ExtendedCommit) BitArray() *bits.BitArray {
|
||||
if ec.bitArray == nil {
|
||||
ec.bitArray = bits.NewBitArray(len(ec.ExtendedSignatures))
|
||||
for i, extCommitSig := range ec.ExtendedSignatures {
|
||||
// TODO: need to check the BlockID otherwise we could be counting conflicts,
|
||||
// not just the one with +2/3 !
|
||||
ec.bitArray.SetIndex(i, extCommitSig.BlockIDFlag != BlockIDFlagAbsent)
|
||||
}
|
||||
}
|
||||
return ec.bitArray
|
||||
}
|
||||
|
||||
// GetByIndex returns the vote corresponding to a given validator index.
|
||||
// Panics if `index >= extCommit.Size()`.
|
||||
// Implements VoteSetReader.
|
||||
func (ec *ExtendedCommit) GetByIndex(valIdx int32) *Vote {
|
||||
return ec.GetExtendedVote(valIdx)
|
||||
}
|
||||
|
||||
// IsCommit returns true if there is at least one signature.
|
||||
// Implements VoteSetReader.
|
||||
func (ec *ExtendedCommit) IsCommit() bool {
|
||||
return len(ec.ExtendedSignatures) != 0
|
||||
}
|
||||
|
||||
// ValidateBasic checks whether the extended commit is well-formed. Does not
|
||||
// actually check the cryptographic signatures.
|
||||
func (ec *ExtendedCommit) ValidateBasic() error {
|
||||
if ec.Height < 0 {
|
||||
return errors.New("negative Height")
|
||||
}
|
||||
if ec.Round < 0 {
|
||||
return errors.New("negative Round")
|
||||
}
|
||||
|
||||
if ec.Height >= 1 {
|
||||
if ec.BlockID.IsNil() {
|
||||
return errors.New("commit cannot be for nil block")
|
||||
}
|
||||
|
||||
if len(ec.ExtendedSignatures) == 0 {
|
||||
return errors.New("no signatures in commit")
|
||||
}
|
||||
for i, extCommitSig := range ec.ExtendedSignatures {
|
||||
if err := extCommitSig.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("wrong ExtendedCommitSig #%d: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToProto converts ExtendedCommit to protobuf
|
||||
func (ec *ExtendedCommit) ToProto() *tmproto.ExtendedCommit {
|
||||
if ec == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := new(tmproto.ExtendedCommit)
|
||||
sigs := make([]tmproto.ExtendedCommitSig, len(ec.ExtendedSignatures))
|
||||
for i := range ec.ExtendedSignatures {
|
||||
sigs[i] = *ec.ExtendedSignatures[i].ToProto()
|
||||
}
|
||||
c.ExtendedSignatures = sigs
|
||||
|
||||
c.Height = ec.Height
|
||||
c.Round = ec.Round
|
||||
c.BlockID = ec.BlockID.ToProto()
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// ExtendedCommitFromProto constructs an ExtendedCommit from the given Protobuf
|
||||
// representation. It returns an error if the extended commit is invalid.
|
||||
func ExtendedCommitFromProto(ecp *tmproto.ExtendedCommit) (*ExtendedCommit, error) {
|
||||
if ecp == nil {
|
||||
return nil, errors.New("nil ExtendedCommit")
|
||||
}
|
||||
|
||||
extCommit := new(ExtendedCommit)
|
||||
|
||||
bi, err := BlockIDFromProto(&ecp.BlockID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sigs := make([]ExtendedCommitSig, len(ecp.ExtendedSignatures))
|
||||
for i := range ecp.ExtendedSignatures {
|
||||
if err := sigs[i].FromProto(ecp.ExtendedSignatures[i]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
extCommit.ExtendedSignatures = sigs
|
||||
extCommit.Height = ecp.Height
|
||||
extCommit.Round = ecp.Round
|
||||
extCommit.BlockID = *bi
|
||||
|
||||
return extCommit, extCommit.ValidateBasic()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Data contains the set of transactions included in the block
|
||||
@@ -1167,6 +1521,17 @@ type BlockID struct {
|
||||
PartSetHeader PartSetHeader `json:"parts"`
|
||||
}
|
||||
|
||||
func NewBlockID(hash []byte, header PartSetHeader) BlockID {
|
||||
return BlockID{
|
||||
Hash: hash,
|
||||
PartSetHeader: header,
|
||||
}
|
||||
}
|
||||
|
||||
func NilBlockID() BlockID {
|
||||
return NewBlockID(nil, PartSetHeader{})
|
||||
}
|
||||
|
||||
// Equals returns true if the BlockID matches the given BlockID
|
||||
func (blockID BlockID) Equals(other BlockID) bool {
|
||||
return bytes.Equal(blockID.Hash, other.Hash) &&
|
||||
@@ -1196,8 +1561,8 @@ func (blockID BlockID) ValidateBasic() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsZero returns true if this is the BlockID of a nil block.
|
||||
func (blockID BlockID) IsZero() bool {
|
||||
// IsNil returns true if this is the BlockID of a nil block.
|
||||
func (blockID BlockID) IsNil() bool {
|
||||
return len(blockID.Hash) == 0 &&
|
||||
blockID.PartSetHeader.IsZero()
|
||||
}
|
||||
@@ -1249,3 +1614,9 @@ func BlockIDFromProto(bID *tmproto.BlockID) (*BlockID, error) {
|
||||
|
||||
return blockID, blockID.ValidateBasic()
|
||||
}
|
||||
|
||||
// IsProtoBlockIDNil is similar to the IsNil function on BlockID, but for the
|
||||
// Protobuf representation.
|
||||
func IsProtoBlockIDNil(bID *tmproto.BlockID) bool {
|
||||
return len(bID.Hash) == 0 && IsProtoPartSetHeaderZero(&bID.PartSetHeader)
|
||||
}
|
||||
|
||||
+147
-15
@@ -38,14 +38,14 @@ func TestBlockAddEvidence(t *testing.T) {
|
||||
h := int64(3)
|
||||
|
||||
voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
extCommit, err := makeExtCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
require.NoError(t, err)
|
||||
|
||||
ev, err := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
|
||||
require.NoError(t, err)
|
||||
evList := []Evidence{ev}
|
||||
|
||||
block := MakeBlock(h, txs, commit, evList)
|
||||
block := MakeBlock(h, txs, extCommit.ToCommit(), evList)
|
||||
require.NotNil(t, block)
|
||||
require.Equal(t, 1, len(block.Evidence.Evidence))
|
||||
require.NotNil(t, block.EvidenceHash)
|
||||
@@ -59,8 +59,9 @@ func TestBlockValidateBasic(t *testing.T) {
|
||||
h := int64(3)
|
||||
|
||||
voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
extCommit, err := makeExtCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
require.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
|
||||
ev, err := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
|
||||
require.NoError(t, err)
|
||||
@@ -131,14 +132,14 @@ func TestBlockMakePartSetWithEvidence(t *testing.T) {
|
||||
h := int64(3)
|
||||
|
||||
voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
extCommit, err := makeExtCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
require.NoError(t, err)
|
||||
|
||||
ev, err := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
|
||||
require.NoError(t, err)
|
||||
evList := []Evidence{ev}
|
||||
|
||||
partSet, err := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(512)
|
||||
partSet, err := MakeBlock(h, []Tx{Tx("Hello World")}, extCommit.ToCommit(), evList).MakePartSet(512)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, partSet)
|
||||
@@ -151,14 +152,14 @@ func TestBlockHashesTo(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
h := int64(3)
|
||||
voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
extCommit, err := makeExtCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
require.NoError(t, err)
|
||||
|
||||
ev, err := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain")
|
||||
require.NoError(t, err)
|
||||
evList := []Evidence{ev}
|
||||
|
||||
block := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList)
|
||||
block := MakeBlock(h, []Tx{Tx("Hello World")}, extCommit.ToCommit(), evList)
|
||||
block.ValidatorsHash = valSet.Hash()
|
||||
assert.False(t, block.HashesTo([]byte{}))
|
||||
assert.False(t, block.HashesTo([]byte("something else")))
|
||||
@@ -230,7 +231,7 @@ func TestCommit(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
h := int64(3)
|
||||
voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
commit, err := makeExtCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, h-1, commit.Height)
|
||||
@@ -438,11 +439,11 @@ func randCommit(now time.Time) *Commit {
|
||||
lastID := makeBlockIDRandom()
|
||||
h := int64(3)
|
||||
voteSet, _, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, now)
|
||||
extCommit, err := makeExtCommit(lastID, h-1, 1, voteSet, vals, now)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return commit
|
||||
return extCommit.ToCommit()
|
||||
}
|
||||
|
||||
func hexBytesFromString(s string) bytes.HexBytes {
|
||||
@@ -514,13 +515,144 @@ func TestBlockMaxDataBytesNoEvidence(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestVoteSetToExtendedCommit tests that the extended commit produced from a
|
||||
// vote set contains the same vote information as the vote set. The test ensures
|
||||
// that the MakeExtendedCommit method behaves as expected, whether vote extensions
|
||||
// are present in the original votes or not.
|
||||
func TestVoteSetToExtendedCommit(t *testing.T) {
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
includeExtension bool
|
||||
}{
|
||||
{
|
||||
name: "no extensions",
|
||||
includeExtension: false,
|
||||
},
|
||||
{
|
||||
name: "with extensions",
|
||||
includeExtension: true,
|
||||
},
|
||||
} {
|
||||
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
blockID := makeBlockIDRandom()
|
||||
|
||||
_, valSet, vals := randVoteSet(10, 1, tmproto.PrecommitType, 10, 1)
|
||||
var voteSet *VoteSet
|
||||
if testCase.includeExtension {
|
||||
voteSet = NewExtendedVoteSet("test_chain_id", 3, 1, tmproto.PrecommitType, valSet)
|
||||
} else {
|
||||
voteSet = NewVoteSet("test_chain_id", 3, 1, tmproto.PrecommitType, valSet)
|
||||
}
|
||||
for i := 0; i < len(vals); i++ {
|
||||
pubKey, err := vals[i].GetPubKey()
|
||||
require.NoError(t, err)
|
||||
vote := &Vote{
|
||||
ValidatorAddress: pubKey.Address(),
|
||||
ValidatorIndex: int32(i),
|
||||
Height: 3,
|
||||
Round: 1,
|
||||
Type: tmproto.PrecommitType,
|
||||
BlockID: blockID,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
v := vote.ToProto()
|
||||
err = vals[i].SignVote(voteSet.ChainID(), v)
|
||||
require.NoError(t, err)
|
||||
vote.Signature = v.Signature
|
||||
if testCase.includeExtension {
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
}
|
||||
added, err := voteSet.AddVote(vote)
|
||||
require.NoError(t, err)
|
||||
require.True(t, added)
|
||||
}
|
||||
ec := voteSet.MakeExtendedCommit()
|
||||
|
||||
for i := int32(0); int(i) < len(vals); i++ {
|
||||
vote1 := voteSet.GetByIndex(i)
|
||||
vote2 := ec.GetExtendedVote(i)
|
||||
|
||||
vote1bz, err := vote1.ToProto().Marshal()
|
||||
require.NoError(t, err)
|
||||
vote2bz, err := vote2.ToProto().Marshal()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, vote1bz, vote2bz)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestExtendedCommitToVoteSet tests that the vote set produced from an extended commit
|
||||
// contains the same vote information as the extended commit. The test ensures
|
||||
// that the ToVoteSet method behaves as expected, whether vote extensions
|
||||
// are present in the original votes or not.
|
||||
func TestExtendedCommitToVoteSet(t *testing.T) {
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
includeExtension bool
|
||||
}{
|
||||
{
|
||||
name: "no extensions",
|
||||
includeExtension: false,
|
||||
},
|
||||
{
|
||||
name: "with extensions",
|
||||
includeExtension: true,
|
||||
},
|
||||
} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
h := int64(3)
|
||||
|
||||
voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
|
||||
extCommit, err := makeExtCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
assert.NoError(t, err)
|
||||
|
||||
if !testCase.includeExtension {
|
||||
for i := 0; i < len(vals); i++ {
|
||||
v := voteSet.GetByIndex(int32(i))
|
||||
v.Extension = nil
|
||||
v.ExtensionSignature = nil
|
||||
extCommit.ExtendedSignatures[i].Extension = nil
|
||||
extCommit.ExtendedSignatures[i].ExtensionSignature = nil
|
||||
}
|
||||
}
|
||||
|
||||
chainID := voteSet.ChainID()
|
||||
var voteSet2 *VoteSet
|
||||
if testCase.includeExtension {
|
||||
voteSet2 = extCommit.ToExtendedVoteSet(chainID, valSet)
|
||||
} else {
|
||||
voteSet2 = extCommit.ToVoteSet(chainID, valSet)
|
||||
}
|
||||
|
||||
for i := int32(0); int(i) < len(vals); i++ {
|
||||
vote1 := voteSet.GetByIndex(i)
|
||||
vote2 := voteSet2.GetByIndex(i)
|
||||
vote3 := extCommit.GetExtendedVote(i)
|
||||
|
||||
vote1bz, err := vote1.ToProto().Marshal()
|
||||
require.NoError(t, err)
|
||||
vote2bz, err := vote2.ToProto().Marshal()
|
||||
require.NoError(t, err)
|
||||
vote3bz, err := vote3.ToProto().Marshal()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, vote1bz, vote2bz)
|
||||
assert.Equal(t, vote1bz, vote3bz)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitToVoteSet(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
h := int64(3)
|
||||
|
||||
voteSet, valSet, vals := randVoteSet(h-1, 1, tmproto.PrecommitType, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
extCommit, err := makeExtCommit(lastID, h-1, 1, voteSet, vals, time.Now())
|
||||
assert.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
|
||||
chainID := voteSet.ChainID()
|
||||
voteSet2 := CommitToVoteSet(chainID, commit, valSet)
|
||||
@@ -587,12 +719,12 @@ func TestCommitToVoteSetWithVotesForNilBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
if tc.valid {
|
||||
commit := voteSet.MakeCommit() // panics without > 2/3 valid votes
|
||||
assert.NotNil(t, commit)
|
||||
err := valSet.VerifyCommit(voteSet.ChainID(), blockID, height-1, commit)
|
||||
extCommit := voteSet.MakeExtendedCommit() // panics without > 2/3 valid votes
|
||||
assert.NotNil(t, extCommit)
|
||||
err := valSet.VerifyCommit(voteSet.ChainID(), blockID, height-1, extCommit.ToCommit())
|
||||
assert.Nil(t, err)
|
||||
} else {
|
||||
assert.Panics(t, func() { voteSet.MakeCommit() })
|
||||
assert.Panics(t, func() { voteSet.MakeExtendedCommit() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -21,7 +21,7 @@ func CanonicalizeBlockID(bid tmproto.BlockID) *tmproto.CanonicalBlockID {
|
||||
panic(err)
|
||||
}
|
||||
var cbid *tmproto.CanonicalBlockID
|
||||
if rbid == nil || rbid.IsZero() {
|
||||
if rbid == nil || rbid.IsNil() {
|
||||
cbid = nil
|
||||
} else {
|
||||
cbid = &tmproto.CanonicalBlockID{
|
||||
@@ -64,6 +64,18 @@ func CanonicalizeVote(chainID string, vote *tmproto.Vote) tmproto.CanonicalVote
|
||||
}
|
||||
}
|
||||
|
||||
// CanonicalizeVoteExtension extracts the vote extension from the given vote
|
||||
// and constructs a CanonicalizeVoteExtension struct, whose representation in
|
||||
// bytes is what is signed in order to produce the vote extension's signature.
|
||||
func CanonicalizeVoteExtension(chainID string, vote *tmproto.Vote) tmproto.CanonicalVoteExtension {
|
||||
return tmproto.CanonicalVoteExtension{
|
||||
Extension: vote.Extension,
|
||||
Height: vote.Height,
|
||||
Round: int64(vote.Round),
|
||||
ChainId: chainID,
|
||||
}
|
||||
}
|
||||
|
||||
// CanonicalTime can be used to stringify time in a canonical way.
|
||||
func CanonicalTime(t time.Time) string {
|
||||
// Note that sending time over amino resets it to
|
||||
|
||||
@@ -99,8 +99,9 @@ func TestLightClientAttackEvidenceBasic(t *testing.T) {
|
||||
header := makeHeaderRandom()
|
||||
header.Height = height
|
||||
blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
|
||||
commit, err := MakeCommit(blockID, height, 1, voteSet, privVals, defaultVoteTime)
|
||||
extCommit, err := makeExtCommit(blockID, height, 1, voteSet, privVals, defaultVoteTime)
|
||||
require.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
lcae := &LightClientAttackEvidence{
|
||||
ConflictingBlock: &LightBlock{
|
||||
SignedHeader: &SignedHeader{
|
||||
@@ -159,13 +160,13 @@ func TestLightClientAttackEvidenceValidation(t *testing.T) {
|
||||
header.Height = height
|
||||
header.ValidatorsHash = valSet.Hash()
|
||||
blockID := makeBlockID(header.Hash(), math.MaxInt32, tmhash.Sum([]byte("partshash")))
|
||||
commit, err := MakeCommit(blockID, height, 1, voteSet, privVals, time.Now())
|
||||
extCommit, err := makeExtCommit(blockID, height, 1, voteSet, privVals, time.Now())
|
||||
require.NoError(t, err)
|
||||
lcae := &LightClientAttackEvidence{
|
||||
ConflictingBlock: &LightBlock{
|
||||
SignedHeader: &SignedHeader{
|
||||
Header: header,
|
||||
Commit: commit,
|
||||
Commit: extCommit.ToCommit(),
|
||||
},
|
||||
ValidatorSet: valSet,
|
||||
},
|
||||
@@ -205,7 +206,7 @@ func TestLightClientAttackEvidenceValidation(t *testing.T) {
|
||||
ConflictingBlock: &LightBlock{
|
||||
SignedHeader: &SignedHeader{
|
||||
Header: header,
|
||||
Commit: commit,
|
||||
Commit: extCommit.ToCommit(),
|
||||
},
|
||||
ValidatorSet: valSet,
|
||||
},
|
||||
|
||||
+73
-1
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
tmstrings "github.com/tendermint/tendermint/libs/strings"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
)
|
||||
|
||||
@@ -37,6 +38,7 @@ type ConsensusParams struct {
|
||||
Evidence EvidenceParams `json:"evidence"`
|
||||
Validator ValidatorParams `json:"validator"`
|
||||
Version VersionParams `json:"version"`
|
||||
ABCI ABCIParams `json:"abci"`
|
||||
}
|
||||
|
||||
// BlockParams define limits on the block size and gas plus minimum time
|
||||
@@ -63,6 +65,22 @@ type VersionParams struct {
|
||||
App uint64 `json:"app"`
|
||||
}
|
||||
|
||||
// ABCIParams configure ABCI functionality specific to the Application Blockchain
|
||||
// Interface.
|
||||
type ABCIParams struct {
|
||||
VoteExtensionsEnableHeight int64 `json:"vote_extensions_enable_height"`
|
||||
RecheckTx bool `json:"recheck_tx"`
|
||||
}
|
||||
|
||||
// VoteExtensionsEnabled returns true if vote extensions are enabled at height h
|
||||
// and false otherwise.
|
||||
func (a ABCIParams) VoteExtensionsEnabled(h int64) bool {
|
||||
if a.VoteExtensionsEnableHeight == 0 {
|
||||
return false
|
||||
}
|
||||
return a.VoteExtensionsEnableHeight <= h
|
||||
}
|
||||
|
||||
// DefaultConsensusParams returns a default ConsensusParams.
|
||||
func DefaultConsensusParams() *ConsensusParams {
|
||||
return &ConsensusParams{
|
||||
@@ -70,6 +88,7 @@ func DefaultConsensusParams() *ConsensusParams {
|
||||
Evidence: DefaultEvidenceParams(),
|
||||
Validator: DefaultValidatorParams(),
|
||||
Version: DefaultVersionParams(),
|
||||
ABCI: DefaultABCIParams(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +123,13 @@ func DefaultVersionParams() VersionParams {
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultABCIParams() ABCIParams {
|
||||
return ABCIParams{
|
||||
// When set to 0, vote extensions are not required.
|
||||
VoteExtensionsEnableHeight: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func IsValidPubkeyType(params ValidatorParams, pubkeyType string) bool {
|
||||
for i := 0; i < len(params.PubKeyTypes); i++ {
|
||||
if params.PubKeyTypes[i] == pubkeyType {
|
||||
@@ -150,6 +176,10 @@ func (params ConsensusParams) ValidateBasic() error {
|
||||
params.Evidence.MaxBytes)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
@@ -166,6 +196,30 @@ func (params ConsensusParams) ValidateBasic() 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
|
||||
@@ -190,6 +244,14 @@ func (params ConsensusParams) Hash() []byte {
|
||||
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.ABCI == params2.ABCI &&
|
||||
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) Update(params2 *tmproto.ConsensusParams) ConsensusParams {
|
||||
@@ -217,6 +279,9 @@ func (params ConsensusParams) Update(params2 *tmproto.ConsensusParams) Consensus
|
||||
if params2.Version != nil {
|
||||
res.Version.App = params2.Version.App
|
||||
}
|
||||
if params2.Abci != nil {
|
||||
res.ABCI.VoteExtensionsEnableHeight = params2.Abci.GetVoteExtensionsEnableHeight()
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -237,11 +302,14 @@ func (params *ConsensusParams) ToProto() tmproto.ConsensusParams {
|
||||
Version: &tmproto.VersionParams{
|
||||
App: params.Version.App,
|
||||
},
|
||||
Abci: &tmproto.ABCIParams{
|
||||
VoteExtensionsEnableHeight: params.ABCI.VoteExtensionsEnableHeight,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ConsensusParamsFromProto(pbParams tmproto.ConsensusParams) ConsensusParams {
|
||||
return ConsensusParams{
|
||||
c := ConsensusParams{
|
||||
Block: BlockParams{
|
||||
MaxBytes: pbParams.Block.MaxBytes,
|
||||
MaxGas: pbParams.Block.MaxGas,
|
||||
@@ -258,4 +326,8 @@ func ConsensusParamsFromProto(pbParams tmproto.ConsensusParams) ConsensusParams
|
||||
App: pbParams.Version.App,
|
||||
},
|
||||
}
|
||||
if pbParams.Abci != nil {
|
||||
c.ABCI.VoteExtensionsEnableHeight = pbParams.Abci.GetVoteExtensionsEnableHeight()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -145,6 +145,12 @@ func PartSetHeaderFromProto(ppsh *tmproto.PartSetHeader) (*PartSetHeader, error)
|
||||
return psh, psh.ValidateBasic()
|
||||
}
|
||||
|
||||
// IsProtoPartSetHeaderZero is similar to the IsZero function for
|
||||
// PartSetHeader, but for the Protobuf representation.
|
||||
func IsProtoPartSetHeaderZero(ppsh *tmproto.PartSetHeader) bool {
|
||||
return ppsh.Total == 0 && len(ppsh.Hash) == 0
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
type PartSet struct {
|
||||
|
||||
@@ -82,6 +82,20 @@ func (pv MockPV) SignVote(chainID string, vote *tmproto.Vote) error {
|
||||
return err
|
||||
}
|
||||
vote.Signature = sig
|
||||
|
||||
var extSig []byte
|
||||
// We only sign vote extensions for non-nil precommits
|
||||
// We always sign extensions, even if they are empty
|
||||
if vote.Type == tmproto.PrecommitType && !IsProtoBlockIDNil(&vote.BlockID) {
|
||||
extSignBytes := VoteExtensionSignBytes(useChainID, vote)
|
||||
extSig, err = pv.PrivKey.Sign(extSignBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(vote.Extension) > 0 {
|
||||
return errors.New("unexpected vote extension - vote extensions are only allowed in non-nil precommits")
|
||||
}
|
||||
vote.ExtensionSignature = extSig
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
func MakeCommit(blockID BlockID, height int64, round int32,
|
||||
voteSet *VoteSet, validators []PrivValidator, now time.Time) (*Commit, error) {
|
||||
func makeExtCommit(blockID BlockID, height int64, round int32,
|
||||
voteSet *VoteSet, validators []PrivValidator, now time.Time) (*ExtendedCommit, error) {
|
||||
|
||||
// all sign
|
||||
for i := 0; i < len(validators); i++ {
|
||||
@@ -34,7 +34,7 @@ func MakeCommit(blockID BlockID, height int64, round int32,
|
||||
}
|
||||
}
|
||||
|
||||
return voteSet.MakeCommit(), nil
|
||||
return voteSet.MakeExtendedCommit(), nil
|
||||
}
|
||||
|
||||
func signAddVote(privVal PrivValidator, vote *Vote, voteSet *VoteSet) (signed bool, err error) {
|
||||
|
||||
@@ -751,8 +751,9 @@ func TestValidatorSet_VerifyCommit_CheckAllSignatures(t *testing.T) {
|
||||
)
|
||||
|
||||
voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
|
||||
commit, err := MakeCommit(blockID, h, 0, voteSet, vals, time.Now())
|
||||
extCommit, err := makeExtCommit(blockID, h, 0, voteSet, vals, time.Now())
|
||||
require.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
|
||||
// malleate 4th signature
|
||||
vote := voteSet.GetByIndex(3)
|
||||
@@ -776,8 +777,9 @@ func TestValidatorSet_VerifyCommitLight_ReturnsAsSoonAsMajorityOfVotingPowerSign
|
||||
)
|
||||
|
||||
voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
|
||||
commit, err := MakeCommit(blockID, h, 0, voteSet, vals, time.Now())
|
||||
extCommit, err := makeExtCommit(blockID, h, 0, voteSet, vals, time.Now())
|
||||
require.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
|
||||
// malleate 4th signature (3 signatures are enough for 2/3+)
|
||||
vote := voteSet.GetByIndex(3)
|
||||
@@ -799,8 +801,9 @@ func TestValidatorSet_VerifyCommitLightTrusting_ReturnsAsSoonAsTrustLevelOfVotin
|
||||
)
|
||||
|
||||
voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10)
|
||||
commit, err := MakeCommit(blockID, h, 0, voteSet, vals, time.Now())
|
||||
extCommit, err := makeExtCommit(blockID, h, 0, voteSet, vals, time.Now())
|
||||
require.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
|
||||
// malleate 3rd signature (2 signatures are enough for 1/3+ trust level)
|
||||
vote := voteSet.GetByIndex(2)
|
||||
@@ -1521,10 +1524,11 @@ func TestValidatorSet_VerifyCommitLightTrusting(t *testing.T) {
|
||||
var (
|
||||
blockID = makeBlockIDRandom()
|
||||
voteSet, originalValset, vals = randVoteSet(1, 1, tmproto.PrecommitType, 6, 1)
|
||||
commit, err = MakeCommit(blockID, 1, 1, voteSet, vals, time.Now())
|
||||
extCommit, err = makeExtCommit(blockID, 1, 1, voteSet, vals, time.Now())
|
||||
newValSet, _ = RandValidatorSet(2, 1)
|
||||
)
|
||||
require.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
|
||||
testCases := []struct {
|
||||
valSet *ValidatorSet
|
||||
@@ -1562,9 +1566,10 @@ func TestValidatorSet_VerifyCommitLightTrustingErrorsOnOverflow(t *testing.T) {
|
||||
var (
|
||||
blockID = makeBlockIDRandom()
|
||||
voteSet, valSet, vals = randVoteSet(1, 1, tmproto.PrecommitType, 1, MaxTotalVotingPower)
|
||||
commit, err = MakeCommit(blockID, 1, 1, voteSet, vals, time.Now())
|
||||
extCommit, err = makeExtCommit(blockID, 1, 1, voteSet, vals, time.Now())
|
||||
)
|
||||
require.NoError(t, err)
|
||||
commit := extCommit.ToCommit()
|
||||
|
||||
err = valSet.VerifyCommitLightTrusting("test_chain_id", commit,
|
||||
tmmath.Fraction{Numerator: 25, Denominator: 55})
|
||||
|
||||
+196
-49
@@ -13,7 +13,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
nilVoteStr string = "nil-Vote"
|
||||
absentVoteStr string = "Vote{absent}"
|
||||
nilVoteStr string = "nil"
|
||||
|
||||
// The maximum supported number of bytes in a vote extension.
|
||||
MaxVoteExtensionSize int = 1024 * 1024
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -24,6 +28,7 @@ var (
|
||||
ErrVoteInvalidBlockHash = errors.New("invalid block hash")
|
||||
ErrVoteNonDeterministicSignature = errors.New("non-deterministic signature")
|
||||
ErrVoteNil = errors.New("nil vote")
|
||||
ErrVoteExtensionAbsent = errors.New("expected vote extension is absent")
|
||||
)
|
||||
|
||||
type ErrVoteConflictingVotes struct {
|
||||
@@ -48,14 +53,16 @@ type Address = crypto.Address
|
||||
// Vote represents a prevote, precommit, or commit vote from validators for
|
||||
// consensus.
|
||||
type Vote struct {
|
||||
Type tmproto.SignedMsgType `json:"type"`
|
||||
Height int64 `json:"height"`
|
||||
Round int32 `json:"round"` // assume there will not be greater than 2_147_483_647 rounds
|
||||
BlockID BlockID `json:"block_id"` // zero if vote is nil.
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
ValidatorAddress Address `json:"validator_address"`
|
||||
ValidatorIndex int32 `json:"validator_index"`
|
||||
Signature []byte `json:"signature"`
|
||||
Type tmproto.SignedMsgType `json:"type"`
|
||||
Height int64 `json:"height"`
|
||||
Round int32 `json:"round"` // assume there will not be greater than 2_147_483_647 rounds
|
||||
BlockID BlockID `json:"block_id"` // zero if vote is nil.
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
ValidatorAddress Address `json:"validator_address"`
|
||||
ValidatorIndex int32 `json:"validator_index"`
|
||||
Signature []byte `json:"signature"`
|
||||
Extension []byte `json:"extension"`
|
||||
ExtensionSignature []byte `json:"extension_signature"`
|
||||
}
|
||||
|
||||
// CommitSig converts the Vote to a CommitSig.
|
||||
@@ -68,7 +75,7 @@ func (vote *Vote) CommitSig() CommitSig {
|
||||
switch {
|
||||
case vote.BlockID.IsComplete():
|
||||
blockIDFlag = BlockIDFlagCommit
|
||||
case vote.BlockID.IsZero():
|
||||
case vote.BlockID.IsNil():
|
||||
blockIDFlag = BlockIDFlagNil
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid vote %v - expected BlockID to be either empty or complete", vote))
|
||||
@@ -82,6 +89,31 @@ func (vote *Vote) CommitSig() CommitSig {
|
||||
}
|
||||
}
|
||||
|
||||
// StripExtension removes any extension data from the vote. Useful if the
|
||||
// chain has not enabled vote extensions.
|
||||
// Returns true if extension data was present before stripping and false otherwise.
|
||||
func (vote *Vote) StripExtension() bool {
|
||||
stripped := len(vote.Extension) > 0 || len(vote.ExtensionSignature) > 0
|
||||
vote.Extension = nil
|
||||
vote.ExtensionSignature = nil
|
||||
return stripped
|
||||
}
|
||||
|
||||
// ExtendedCommitSig attempts to construct an ExtendedCommitSig from this vote.
|
||||
// Panics if either the vote extension signature is missing or if the block ID
|
||||
// is not either empty or complete.
|
||||
func (vote *Vote) ExtendedCommitSig() ExtendedCommitSig {
|
||||
if vote == nil {
|
||||
return NewExtendedCommitSigAbsent()
|
||||
}
|
||||
|
||||
return ExtendedCommitSig{
|
||||
CommitSig: vote.CommitSig(),
|
||||
Extension: vote.Extension,
|
||||
ExtensionSignature: vote.ExtensionSignature,
|
||||
}
|
||||
}
|
||||
|
||||
// VoteSignBytes returns the proto-encoding of the canonicalized Vote, for
|
||||
// signing. Panics is the marshaling fails.
|
||||
//
|
||||
@@ -100,6 +132,21 @@ func VoteSignBytes(chainID string, vote *tmproto.Vote) []byte {
|
||||
return bz
|
||||
}
|
||||
|
||||
// VoteExtensionSignBytes returns the proto-encoding of the canonicalized vote
|
||||
// extension for signing. Panics if the marshaling fails.
|
||||
//
|
||||
// Similar to VoteSignBytes, the encoded Protobuf message is varint
|
||||
// length-prefixed for backwards-compatibility with the Amino encoding.
|
||||
func VoteExtensionSignBytes(chainID string, vote *tmproto.Vote) []byte {
|
||||
pb := CanonicalizeVoteExtension(chainID, vote)
|
||||
bz, err := protoio.MarshalDelimited(&pb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return bz
|
||||
}
|
||||
|
||||
func (vote *Vote) Copy() *Vote {
|
||||
voteCopy := *vote
|
||||
return &voteCopy
|
||||
@@ -118,38 +165,91 @@ func (vote *Vote) Copy() *Vote {
|
||||
// 9. timestamp
|
||||
func (vote *Vote) String() string {
|
||||
if vote == nil {
|
||||
return nilVoteStr
|
||||
return absentVoteStr
|
||||
}
|
||||
|
||||
var blockHashString string
|
||||
if len(vote.BlockID.Hash) > 0 {
|
||||
blockHashString = fmt.Sprintf("%X", tmbytes.Fingerprint(vote.BlockID.Hash))
|
||||
} else {
|
||||
blockHashString = nilVoteStr
|
||||
}
|
||||
|
||||
var typeString string
|
||||
switch vote.Type {
|
||||
case tmproto.PrevoteType:
|
||||
typeString = "Prevote"
|
||||
return fmt.Sprintf("Prevote{%v/%02d by %v:%X for %X <%X> @ %s}",
|
||||
vote.Height,
|
||||
vote.Round,
|
||||
vote.ValidatorIndex,
|
||||
tmbytes.Fingerprint(vote.ValidatorAddress),
|
||||
blockHashString,
|
||||
tmbytes.Fingerprint(vote.Signature),
|
||||
CanonicalTime(vote.Timestamp),
|
||||
)
|
||||
case tmproto.PrecommitType:
|
||||
typeString = "Precommit"
|
||||
return fmt.Sprintf("Precommit{%v/%02d by %v:%X for %X <%X> & %d <%X> @ %s}",
|
||||
vote.Height,
|
||||
vote.Round,
|
||||
vote.ValidatorIndex,
|
||||
tmbytes.Fingerprint(vote.ValidatorAddress),
|
||||
blockHashString,
|
||||
tmbytes.Fingerprint(vote.Signature),
|
||||
len(vote.Extension),
|
||||
tmbytes.Fingerprint(vote.Extension),
|
||||
CanonicalTime(vote.Timestamp),
|
||||
)
|
||||
default:
|
||||
panic("Unknown vote type")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}",
|
||||
vote.ValidatorIndex,
|
||||
tmbytes.Fingerprint(vote.ValidatorAddress),
|
||||
vote.Height,
|
||||
vote.Round,
|
||||
vote.Type,
|
||||
typeString,
|
||||
tmbytes.Fingerprint(vote.BlockID.Hash),
|
||||
tmbytes.Fingerprint(vote.Signature),
|
||||
CanonicalTime(vote.Timestamp),
|
||||
)
|
||||
}
|
||||
|
||||
func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
func (vote *Vote) verifyAndReturnProto(chainID string, pubKey crypto.PubKey) (*tmproto.Vote, error) {
|
||||
if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) {
|
||||
return ErrVoteInvalidValidatorAddress
|
||||
return nil, ErrVoteInvalidValidatorAddress
|
||||
}
|
||||
v := vote.ToProto()
|
||||
if !pubKey.VerifySignature(VoteSignBytes(chainID, v), vote.Signature) {
|
||||
return nil, ErrVoteInvalidSignature
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Verify checks whether the signature associated with this vote corresponds to
|
||||
// the given chain ID and public key. This function does not validate vote
|
||||
// extension signatures - to do so, use VerifyWithExtension instead.
|
||||
func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||
_, err := vote.verifyAndReturnProto(chainID, pubKey)
|
||||
return err
|
||||
}
|
||||
|
||||
// VerifyVoteAndExtension performs the same verification as Verify, but
|
||||
// additionally checks whether the vote extension signature corresponds to the
|
||||
// given chain ID and public key. We only verify vote extension signatures for
|
||||
// precommits.
|
||||
func (vote *Vote) VerifyVoteAndExtension(chainID string, pubKey crypto.PubKey) error {
|
||||
v, err := vote.verifyAndReturnProto(chainID, pubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// We only verify vote extension signatures for non-nil precommits.
|
||||
if vote.Type == tmproto.PrecommitType && !IsProtoBlockIDNil(&v.BlockID) {
|
||||
extSignBytes := VoteExtensionSignBytes(chainID, v)
|
||||
if !pubKey.VerifySignature(extSignBytes, vote.ExtensionSignature) {
|
||||
return ErrVoteInvalidSignature
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyExtension checks whether the vote extension signature corresponds to the
|
||||
// given chain ID and public key.
|
||||
func (vote *Vote) VerifyExtension(chainID string, pubKey crypto.PubKey) error {
|
||||
if vote.Type != tmproto.PrecommitType || vote.BlockID.IsNil() {
|
||||
return nil
|
||||
}
|
||||
v := vote.ToProto()
|
||||
extSignBytes := VoteExtensionSignBytes(chainID, v)
|
||||
if !pubKey.VerifySignature(extSignBytes, vote.ExtensionSignature) {
|
||||
return ErrVoteInvalidSignature
|
||||
}
|
||||
return nil
|
||||
@@ -161,8 +261,8 @@ func (vote *Vote) ValidateBasic() error {
|
||||
return errors.New("invalid Type")
|
||||
}
|
||||
|
||||
if vote.Height < 0 {
|
||||
return errors.New("negative Height")
|
||||
if vote.Height <= 0 {
|
||||
return errors.New("negative or zero Height")
|
||||
}
|
||||
|
||||
if vote.Round < 0 {
|
||||
@@ -177,7 +277,7 @@ func (vote *Vote) ValidateBasic() error {
|
||||
|
||||
// BlockID.ValidateBasic would not err if we for instance have an empty hash but a
|
||||
// non-empty PartsSetHeader:
|
||||
if !vote.BlockID.IsZero() && !vote.BlockID.IsComplete() {
|
||||
if !vote.BlockID.IsNil() && !vote.BlockID.IsComplete() {
|
||||
return fmt.Errorf("blockID must be either empty or complete, got: %v", vote.BlockID)
|
||||
}
|
||||
|
||||
@@ -198,9 +298,52 @@ func (vote *Vote) ValidateBasic() error {
|
||||
return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
|
||||
}
|
||||
|
||||
// We should only ever see vote extensions in non-nil precommits, otherwise
|
||||
// this is a violation of the specification.
|
||||
// https://github.com/tendermint/tendermint/issues/8487
|
||||
if vote.Type != tmproto.PrecommitType || (vote.Type == tmproto.PrecommitType && vote.BlockID.IsNil()) {
|
||||
if len(vote.Extension) > 0 {
|
||||
return errors.New("unexpected vote extension")
|
||||
}
|
||||
if len(vote.ExtensionSignature) > 0 {
|
||||
return errors.New("unexpected vote extension signature")
|
||||
}
|
||||
} else {
|
||||
// It's possible that this vote has vote extensions but
|
||||
// they could also be disabled and thus not present thus
|
||||
// we can't do all checks
|
||||
if len(vote.ExtensionSignature) > MaxSignatureSize {
|
||||
return fmt.Errorf("vote extension signature is too big (max: %d)", MaxSignatureSize)
|
||||
}
|
||||
|
||||
// NOTE: extended votes should have a signature regardless of
|
||||
// of whether there is any data in the extension or not however
|
||||
// we don't know if extensions are enabled so we can only
|
||||
// enforce the signature when extension size is no nil
|
||||
if len(vote.ExtensionSignature) == 0 && len(vote.Extension) != 0 {
|
||||
return fmt.Errorf("vote extension signature absent on vote with extension")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureExtension checks for the presence of extensions signature data
|
||||
// on precommit vote types.
|
||||
func (vote *Vote) EnsureExtension() error {
|
||||
// We should always see vote extension signatures in non-nil precommits
|
||||
if vote.Type != tmproto.PrecommitType {
|
||||
return nil
|
||||
}
|
||||
if vote.BlockID.IsNil() {
|
||||
return nil
|
||||
}
|
||||
if len(vote.ExtensionSignature) > 0 {
|
||||
return nil
|
||||
}
|
||||
return ErrVoteExtensionAbsent
|
||||
}
|
||||
|
||||
// ToProto converts the handwritten type to proto generated type
|
||||
// return type, nil if everything converts safely, otherwise nil, error
|
||||
func (vote *Vote) ToProto() *tmproto.Vote {
|
||||
@@ -209,14 +352,16 @@ func (vote *Vote) ToProto() *tmproto.Vote {
|
||||
}
|
||||
|
||||
return &tmproto.Vote{
|
||||
Type: vote.Type,
|
||||
Height: vote.Height,
|
||||
Round: vote.Round,
|
||||
BlockID: vote.BlockID.ToProto(),
|
||||
Timestamp: vote.Timestamp,
|
||||
ValidatorAddress: vote.ValidatorAddress,
|
||||
ValidatorIndex: vote.ValidatorIndex,
|
||||
Signature: vote.Signature,
|
||||
Type: vote.Type,
|
||||
Height: vote.Height,
|
||||
Round: vote.Round,
|
||||
BlockID: vote.BlockID.ToProto(),
|
||||
Timestamp: vote.Timestamp,
|
||||
ValidatorAddress: vote.ValidatorAddress,
|
||||
ValidatorIndex: vote.ValidatorIndex,
|
||||
Signature: vote.Signature,
|
||||
Extension: vote.Extension,
|
||||
ExtensionSignature: vote.ExtensionSignature,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,15 +393,17 @@ func VoteFromProto(pv *tmproto.Vote) (*Vote, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vote := new(Vote)
|
||||
vote.Type = pv.Type
|
||||
vote.Height = pv.Height
|
||||
vote.Round = pv.Round
|
||||
vote.BlockID = *blockID
|
||||
vote.Timestamp = pv.Timestamp
|
||||
vote.ValidatorAddress = pv.ValidatorAddress
|
||||
vote.ValidatorIndex = pv.ValidatorIndex
|
||||
vote.Signature = pv.Signature
|
||||
|
||||
vote := &Vote{
|
||||
Type: pv.Type,
|
||||
Height: pv.Height,
|
||||
Round: pv.Round,
|
||||
BlockID: *blockID,
|
||||
Timestamp: pv.Timestamp,
|
||||
ValidatorAddress: pv.ValidatorAddress,
|
||||
ValidatorIndex: pv.ValidatorIndex,
|
||||
Signature: pv.Signature,
|
||||
Extension: pv.Extension,
|
||||
ExtensionSignature: pv.ExtensionSignature,
|
||||
}
|
||||
return vote, vote.ValidateBasic()
|
||||
}
|
||||
|
||||
+33
-17
@@ -59,11 +59,12 @@ there's only a limited number of peers.
|
||||
NOTE: Assumes that the sum total of voting power does not exceed MaxUInt64.
|
||||
*/
|
||||
type VoteSet struct {
|
||||
chainID string
|
||||
height int64
|
||||
round int32
|
||||
signedMsgType tmproto.SignedMsgType
|
||||
valSet *ValidatorSet
|
||||
chainID string
|
||||
height int64
|
||||
round int32
|
||||
signedMsgType tmproto.SignedMsgType
|
||||
valSet *ValidatorSet
|
||||
extensionsEnabled bool
|
||||
|
||||
mtx tmsync.Mutex
|
||||
votesBitArray *bits.BitArray
|
||||
@@ -95,6 +96,16 @@ func NewVoteSet(chainID string, height int64, round int32,
|
||||
}
|
||||
}
|
||||
|
||||
// NewExtendedVoteSet constructs a vote set with additional vote verification logic.
|
||||
// The VoteSet constructed with NewExtendedVoteSet verifies the vote extension
|
||||
// data for every vote added to the set.
|
||||
func NewExtendedVoteSet(chainID string, height int64, round int32,
|
||||
signedMsgType tmproto.SignedMsgType, valSet *ValidatorSet) *VoteSet {
|
||||
vs := NewVoteSet(chainID, height, round, signedMsgType, valSet)
|
||||
vs.extensionsEnabled = true
|
||||
return vs
|
||||
}
|
||||
|
||||
func (voteSet *VoteSet) ChainID() string {
|
||||
return voteSet.chainID
|
||||
}
|
||||
@@ -611,36 +622,41 @@ func (voteSet *VoteSet) sumTotalFrac() (int64, int64, float64) {
|
||||
//--------------------------------------------------------------------------------
|
||||
// Commit
|
||||
|
||||
// MakeCommit constructs a Commit from the VoteSet. It only includes precommits
|
||||
// for the block, which has 2/3+ majority, and nil.
|
||||
// MakeExtendedCommit constructs a Commit from the VoteSet. It only includes
|
||||
// precommits for the block, which has 2/3+ majority, and nil.
|
||||
//
|
||||
// Panics if the vote type is not PrecommitType or if there's no +2/3 votes for
|
||||
// a single block.
|
||||
func (voteSet *VoteSet) MakeCommit() *Commit {
|
||||
func (voteSet *VoteSet) MakeExtendedCommit() *ExtendedCommit {
|
||||
if voteSet.signedMsgType != tmproto.PrecommitType {
|
||||
panic("Cannot MakeCommit() unless VoteSet.Type is PrecommitType")
|
||||
panic("Cannot MakeExtendCommit() unless VoteSet.Type is PrecommitType")
|
||||
}
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
|
||||
// Make sure we have a 2/3 majority
|
||||
if voteSet.maj23 == nil {
|
||||
panic("Cannot MakeCommit() unless a blockhash has +2/3")
|
||||
panic("Cannot MakeExtendCommit() unless a blockhash has +2/3")
|
||||
}
|
||||
|
||||
// For every validator, get the precommit
|
||||
commitSigs := make([]CommitSig, len(voteSet.votes))
|
||||
// For every validator, get the precommit with extensions
|
||||
sigs := make([]ExtendedCommitSig, len(voteSet.votes))
|
||||
for i, v := range voteSet.votes {
|
||||
commitSig := v.CommitSig()
|
||||
sig := v.ExtendedCommitSig()
|
||||
// if block ID exists but doesn't match, exclude sig
|
||||
if commitSig.ForBlock() && !v.BlockID.Equals(*voteSet.maj23) {
|
||||
commitSig = NewCommitSigAbsent()
|
||||
if sig.BlockIDFlag == BlockIDFlagCommit && !v.BlockID.Equals(*voteSet.maj23) {
|
||||
sig = NewExtendedCommitSigAbsent()
|
||||
}
|
||||
|
||||
commitSigs[i] = commitSig
|
||||
sigs[i] = sig
|
||||
}
|
||||
|
||||
return NewCommit(voteSet.GetHeight(), voteSet.GetRound(), *voteSet.maj23, commitSigs)
|
||||
return &ExtendedCommit{
|
||||
Height: voteSet.GetHeight(),
|
||||
Round: voteSet.GetRound(),
|
||||
BlockID: *voteSet.maj23,
|
||||
ExtendedSignatures: sigs,
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
+14
-14
@@ -25,7 +25,7 @@ func TestVoteSet_AddVote_Good(t *testing.T) {
|
||||
assert.Nil(t, voteSet.GetByAddress(val0Addr))
|
||||
assert.False(t, voteSet.BitArray().GetIndex(0))
|
||||
blockID, ok := voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
|
||||
assert.False(t, ok || !blockID.IsNil(), "there should be no 2/3 majority")
|
||||
|
||||
vote := &Vote{
|
||||
ValidatorAddress: val0Addr,
|
||||
@@ -42,7 +42,7 @@ func TestVoteSet_AddVote_Good(t *testing.T) {
|
||||
assert.NotNil(t, voteSet.GetByAddress(val0Addr))
|
||||
assert.True(t, voteSet.BitArray().GetIndex(0))
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
|
||||
assert.False(t, ok || !blockID.IsNil(), "there should be no 2/3 majority")
|
||||
}
|
||||
|
||||
func TestVoteSet_AddVote_Bad(t *testing.T) {
|
||||
@@ -143,7 +143,7 @@ func TestVoteSet_2_3Majority(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
blockID, ok := voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
|
||||
assert.False(t, ok || !blockID.IsNil(), "there should be no 2/3 majority")
|
||||
|
||||
// 7th validator voted for some blockhash
|
||||
{
|
||||
@@ -154,7 +154,7 @@ func TestVoteSet_2_3Majority(t *testing.T) {
|
||||
_, err = signAddVote(privValidators[6], withBlockHash(vote, tmrand.Bytes(32)), voteSet)
|
||||
require.NoError(t, err)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(), "there should be no 2/3 majority")
|
||||
assert.False(t, ok || !blockID.IsNil(), "there should be no 2/3 majority")
|
||||
}
|
||||
|
||||
// 8th validator voted for nil.
|
||||
@@ -166,7 +166,7 @@ func TestVoteSet_2_3Majority(t *testing.T) {
|
||||
_, err = signAddVote(privValidators[7], vote, voteSet)
|
||||
require.NoError(t, err)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
assert.True(t, ok || blockID.IsZero(), "there should be 2/3 majority for nil")
|
||||
assert.True(t, ok || blockID.IsNil(), "there should be 2/3 majority for nil")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
blockID, ok := voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(),
|
||||
assert.False(t, ok || !blockID.IsNil(),
|
||||
"there should be no 2/3 majority")
|
||||
|
||||
// 67th validator voted for nil
|
||||
@@ -210,7 +210,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
|
||||
_, err = signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet)
|
||||
require.NoError(t, err)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(),
|
||||
assert.False(t, ok || !blockID.IsNil(),
|
||||
"there should be no 2/3 majority: last vote added was nil")
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
|
||||
_, err = signAddVote(privValidators[67], withBlockPartSetHeader(vote, blockPartsHeader), voteSet)
|
||||
require.NoError(t, err)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(),
|
||||
assert.False(t, ok || !blockID.IsNil(),
|
||||
"there should be no 2/3 majority: last vote added had different PartSetHeader Hash")
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
|
||||
_, err = signAddVote(privValidators[68], withBlockPartSetHeader(vote, blockPartsHeader), voteSet)
|
||||
require.NoError(t, err)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(),
|
||||
assert.False(t, ok || !blockID.IsNil(),
|
||||
"there should be no 2/3 majority: last vote added had different PartSetHeader Total")
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ func TestVoteSet_2_3MajorityRedux(t *testing.T) {
|
||||
_, err = signAddVote(privValidators[69], withBlockHash(vote, tmrand.Bytes(32)), voteSet)
|
||||
require.NoError(t, err)
|
||||
blockID, ok = voteSet.TwoThirdsMajority()
|
||||
assert.False(t, ok || !blockID.IsZero(),
|
||||
assert.False(t, ok || !blockID.IsNil(),
|
||||
"there should be no 2/3 majority: last vote added had different BlockHash")
|
||||
}
|
||||
|
||||
@@ -426,7 +426,7 @@ func TestVoteSet_MakeCommit(t *testing.T) {
|
||||
}
|
||||
|
||||
// MakeCommit should fail.
|
||||
assert.Panics(t, func() { voteSet.MakeCommit() }, "Doesn't have +2/3 majority")
|
||||
assert.Panics(t, func() { voteSet.MakeExtendedCommit() }, "Doesn't have +2/3 majority")
|
||||
|
||||
// 7th voted for some other block.
|
||||
{
|
||||
@@ -463,13 +463,13 @@ func TestVoteSet_MakeCommit(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
commit := voteSet.MakeCommit()
|
||||
extCommit := voteSet.MakeExtendedCommit()
|
||||
|
||||
// Commit should have 10 elements
|
||||
assert.Equal(t, 10, len(commit.Signatures))
|
||||
assert.Equal(t, 10, len(extCommit.ExtendedSignatures))
|
||||
|
||||
// Ensure that Commit is good.
|
||||
if err := commit.ValidateBasic(); err != nil {
|
||||
if err := extCommit.ValidateBasic(); err != nil {
|
||||
t.Errorf("error in Commit.ValidateBasic(): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -219,13 +219,13 @@ func TestVoteVerify(t *testing.T) {
|
||||
|
||||
func TestVoteString(t *testing.T) {
|
||||
str := examplePrecommit().String()
|
||||
expected := `Vote{56789:6AF1F4111082 12345/02/SIGNED_MSG_TYPE_PRECOMMIT(Precommit) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
expected := `Precommit{12345/02 by 56789:6AF1F4111082 for 384230313032333338364333 <000000000000> & 0 <000000000000> @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
if str != expected {
|
||||
t.Errorf("got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str)
|
||||
}
|
||||
|
||||
str2 := examplePrevote().String()
|
||||
expected = `Vote{56789:6AF1F4111082 12345/02/SIGNED_MSG_TYPE_PREVOTE(Prevote) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
expected = `Prevote{12345/02 by 56789:6AF1F4111082 for 384230313032333338364333 <000000000000> @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
if str2 != expected {
|
||||
t.Errorf("got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str2)
|
||||
}
|
||||
@@ -259,7 +259,11 @@ func TestVoteValidateBasic(t *testing.T) {
|
||||
vote.Signature = v.Signature
|
||||
require.NoError(t, err)
|
||||
tc.malleateVote(vote)
|
||||
assert.Equal(t, tc.expectErr, vote.ValidateBasic() != nil, "Validate Basic had an unexpected result")
|
||||
if tc.expectErr {
|
||||
require.Error(t, vote.ValidateBasic())
|
||||
} else {
|
||||
require.NoError(t, vote.ValidateBasic())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user