mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-20 06:54:41 +00:00
Merge branch 'master' into abci++
This commit is contained in:
@@ -88,6 +88,7 @@ type validatorStub struct {
|
||||
Round int32
|
||||
types.PrivValidator
|
||||
VotingPower int64
|
||||
lastVote *types.Vote
|
||||
}
|
||||
|
||||
const testMinPower int64 = 10
|
||||
@@ -121,8 +122,18 @@ func (vs *validatorStub) signVote(
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: header},
|
||||
}
|
||||
v := vote.ToProto()
|
||||
err = vs.PrivValidator.SignVote(context.Background(), config.ChainID(), v)
|
||||
if err := vs.PrivValidator.SignVote(context.Background(), config.ChainID(), v); err != nil {
|
||||
return nil, fmt.Errorf("sign vote failed: %w", err)
|
||||
}
|
||||
|
||||
// ref: signVote in FilePV, the vote should use the privious vote info when the sign data is the same.
|
||||
if signDataIsEqual(vs.lastVote, v) {
|
||||
v.Signature = vs.lastVote.Signature
|
||||
v.Timestamp = vs.lastVote.Timestamp
|
||||
}
|
||||
|
||||
vote.Signature = v.Signature
|
||||
vote.Timestamp = v.Timestamp
|
||||
|
||||
return vote, err
|
||||
}
|
||||
@@ -139,6 +150,9 @@ func signVote(
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to sign vote: %v", err))
|
||||
}
|
||||
|
||||
vs.lastVote = v
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -876,3 +890,16 @@ func newKVStore() abci.Application {
|
||||
func newPersistentKVStoreWithPath(dbDir string) abci.Application {
|
||||
return kvstore.NewPersistentKVStoreApplication(dbDir)
|
||||
}
|
||||
|
||||
func signDataIsEqual(v1 *types.Vote, v2 *tmproto.Vote) bool {
|
||||
if v1 == nil || v2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return v1.Type == v2.Type &&
|
||||
bytes.Equal(v1.BlockID.Hash, v2.BlockID.GetHash()) &&
|
||||
v1.Height == v2.GetHeight() &&
|
||||
v1.Round == v2.Round &&
|
||||
bytes.Equal(v1.ValidatorAddress.Bytes(), v2.GetValidatorAddress()) &&
|
||||
v1.ValidatorIndex == v2.GetValidatorIndex()
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ type Metrics struct {
|
||||
TotalTxs metrics.Gauge
|
||||
// The latest block height.
|
||||
CommittedHeight metrics.Gauge
|
||||
// Whether or not a node is fast syncing. 1 if yes, 0 if no.
|
||||
FastSyncing metrics.Gauge
|
||||
// Whether or not a node is block syncing. 1 if yes, 0 if no.
|
||||
BlockSyncing metrics.Gauge
|
||||
// Whether or not a node is state syncing. 1 if yes, 0 if no.
|
||||
StateSyncing metrics.Gauge
|
||||
|
||||
@@ -169,11 +169,11 @@ func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
|
||||
Name: "latest_block_height",
|
||||
Help: "The latest block height.",
|
||||
}, labels).With(labelsAndValues...),
|
||||
FastSyncing: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||
BlockSyncing: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: MetricsSubsystem,
|
||||
Name: "fast_syncing",
|
||||
Help: "Whether or not a node is fast syncing. 1 if yes, 0 if no.",
|
||||
Name: "block_syncing",
|
||||
Help: "Whether or not a node is block syncing. 1 if yes, 0 if no.",
|
||||
}, labels).With(labelsAndValues...),
|
||||
StateSyncing: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
@@ -214,7 +214,7 @@ func NopMetrics() *Metrics {
|
||||
BlockSizeBytes: discard.NewHistogram(),
|
||||
TotalTxs: discard.NewGauge(),
|
||||
CommittedHeight: discard.NewGauge(),
|
||||
FastSyncing: discard.NewGauge(),
|
||||
BlockSyncing: discard.NewGauge(),
|
||||
StateSyncing: discard.NewGauge(),
|
||||
BlockParts: discard.NewCounter(),
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery 2.7.5. DO NOT EDIT.
|
||||
// Code generated by mockery. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
@@ -12,8 +12,8 @@ type ConsSyncReactor struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// SetFastSyncingMetrics provides a mock function with given fields: _a0
|
||||
func (_m *ConsSyncReactor) SetFastSyncingMetrics(_a0 float64) {
|
||||
// SetBlockSyncingMetrics provides a mock function with given fields: _a0
|
||||
func (_m *ConsSyncReactor) SetBlockSyncingMetrics(_a0 float64) {
|
||||
_m.Called(_a0)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
time "time"
|
||||
)
|
||||
|
||||
// FastSyncReactor is an autogenerated mock type for the FastSyncReactor type
|
||||
type FastSyncReactor struct {
|
||||
// BlockSyncReactor is an autogenerated mock type for the BlockSyncReactor type
|
||||
type BlockSyncReactor struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// GetMaxPeerBlockHeight provides a mock function with given fields:
|
||||
func (_m *FastSyncReactor) GetMaxPeerBlockHeight() int64 {
|
||||
func (_m *BlockSyncReactor) GetMaxPeerBlockHeight() int64 {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 int64
|
||||
@@ -29,7 +29,7 @@ func (_m *FastSyncReactor) GetMaxPeerBlockHeight() int64 {
|
||||
}
|
||||
|
||||
// GetRemainingSyncTime provides a mock function with given fields:
|
||||
func (_m *FastSyncReactor) GetRemainingSyncTime() time.Duration {
|
||||
func (_m *BlockSyncReactor) GetRemainingSyncTime() time.Duration {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 time.Duration
|
||||
@@ -43,7 +43,7 @@ func (_m *FastSyncReactor) GetRemainingSyncTime() time.Duration {
|
||||
}
|
||||
|
||||
// GetTotalSyncedTime provides a mock function with given fields:
|
||||
func (_m *FastSyncReactor) GetTotalSyncedTime() time.Duration {
|
||||
func (_m *BlockSyncReactor) GetTotalSyncedTime() time.Duration {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 time.Duration
|
||||
@@ -56,8 +56,8 @@ func (_m *FastSyncReactor) GetTotalSyncedTime() time.Duration {
|
||||
return r0
|
||||
}
|
||||
|
||||
// SwitchToFastSync provides a mock function with given fields: _a0
|
||||
func (_m *FastSyncReactor) SwitchToFastSync(_a0 state.State) error {
|
||||
// SwitchToBlockSync provides a mock function with given fields: _a0
|
||||
func (_m *BlockSyncReactor) SwitchToBlockSync(_a0 state.State) error {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 error
|
||||
|
||||
@@ -96,28 +96,28 @@ const (
|
||||
|
||||
type ReactorOption func(*Reactor)
|
||||
|
||||
// Temporary interface for switching to fast sync, we should get rid of v0.
|
||||
// NOTE: Temporary interface for switching to block sync, we should get rid of v0.
|
||||
// See: https://github.com/tendermint/tendermint/issues/4595
|
||||
type FastSyncReactor interface {
|
||||
SwitchToFastSync(sm.State) error
|
||||
type BlockSyncReactor interface {
|
||||
SwitchToBlockSync(sm.State) error
|
||||
|
||||
GetMaxPeerBlockHeight() int64
|
||||
|
||||
// GetTotalSyncedTime returns the time duration since the fastsync starting.
|
||||
// GetTotalSyncedTime returns the time duration since the blocksync starting.
|
||||
GetTotalSyncedTime() time.Duration
|
||||
|
||||
// GetRemainingSyncTime returns the estimating time the node will be fully synced,
|
||||
// if will return 0 if the fastsync does not perform or the number of block synced is
|
||||
// if will return 0 if the blocksync does not perform or the number of block synced is
|
||||
// too small (less than 100).
|
||||
GetRemainingSyncTime() time.Duration
|
||||
}
|
||||
|
||||
//go:generate mockery --case underscore --name ConsSyncReactor
|
||||
//go:generate ../../scripts/mockery_generate.sh ConsSyncReactor
|
||||
// ConsSyncReactor defines an interface used for testing abilities of node.startStateSync.
|
||||
type ConsSyncReactor interface {
|
||||
SwitchToConsensus(sm.State, bool)
|
||||
SetStateSyncingMetrics(float64)
|
||||
SetFastSyncingMetrics(float64)
|
||||
SetBlockSyncingMetrics(float64)
|
||||
}
|
||||
|
||||
// Reactor defines a reactor for the consensus service.
|
||||
@@ -265,7 +265,7 @@ func (r *Reactor) SetEventBus(b *types.EventBus) {
|
||||
r.state.SetEventBus(b)
|
||||
}
|
||||
|
||||
// WaitSync returns whether the consensus reactor is waiting for state/fast sync.
|
||||
// WaitSync returns whether the consensus reactor is waiting for state/block sync.
|
||||
func (r *Reactor) WaitSync() bool {
|
||||
r.mtx.RLock()
|
||||
defer r.mtx.RUnlock()
|
||||
@@ -278,8 +278,8 @@ func ReactorMetrics(metrics *Metrics) ReactorOption {
|
||||
return func(r *Reactor) { r.Metrics = metrics }
|
||||
}
|
||||
|
||||
// SwitchToConsensus switches from fast-sync mode to consensus mode. It resets
|
||||
// the state, turns off fast-sync, and starts the consensus state-machine.
|
||||
// SwitchToConsensus switches from block-sync mode to consensus mode. It resets
|
||||
// the state, turns off block-sync, and starts the consensus state-machine.
|
||||
func (r *Reactor) SwitchToConsensus(state sm.State, skipWAL bool) {
|
||||
r.Logger.Info("switching to consensus")
|
||||
|
||||
@@ -296,7 +296,7 @@ func (r *Reactor) SwitchToConsensus(state sm.State, skipWAL bool) {
|
||||
r.waitSync = false
|
||||
r.mtx.Unlock()
|
||||
|
||||
r.Metrics.FastSyncing.Set(0)
|
||||
r.Metrics.BlockSyncing.Set(0)
|
||||
r.Metrics.StateSyncing.Set(0)
|
||||
|
||||
if skipWAL {
|
||||
@@ -313,9 +313,9 @@ conR:
|
||||
%+v`, err, r.state, r))
|
||||
}
|
||||
|
||||
d := types.EventDataFastSyncStatus{Complete: true, Height: state.LastBlockHeight}
|
||||
if err := r.eventBus.PublishEventFastSyncStatus(d); err != nil {
|
||||
r.Logger.Error("failed to emit the fastsync complete event", "err", err)
|
||||
d := types.EventDataBlockSyncStatus{Complete: true, Height: state.LastBlockHeight}
|
||||
if err := r.eventBus.PublishEventBlockSyncStatus(d); err != nil {
|
||||
r.Logger.Error("failed to emit the blocksync complete event", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -969,7 +969,7 @@ func (r *Reactor) processPeerUpdate(peerUpdate p2p.PeerUpdate) {
|
||||
go r.gossipVotesRoutine(ps)
|
||||
go r.queryMaj23Routine(ps)
|
||||
|
||||
// Send our state to the peer. If we're fast-syncing, broadcast a
|
||||
// Send our state to the peer. If we're block-syncing, broadcast a
|
||||
// RoundStepMessage later upon SwitchToConsensus().
|
||||
if !r.waitSync {
|
||||
go r.sendNewRoundStepMessage(ps.peerID)
|
||||
@@ -1219,7 +1219,7 @@ func (r *Reactor) handleVoteSetBitsMessage(envelope p2p.Envelope, msgI Message)
|
||||
// It will handle errors and any possible panics gracefully. A caller can handle
|
||||
// any error returned by sending a PeerError on the respective channel.
|
||||
//
|
||||
// NOTE: We process these messages even when we're fast_syncing. Messages affect
|
||||
// NOTE: We process these messages even when we're block syncing. Messages affect
|
||||
// either a peer state or the consensus state. Peer state updates can happen in
|
||||
// parallel, but processing of proposals, block parts, and votes are ordered by
|
||||
// the p2p channel.
|
||||
@@ -1442,6 +1442,6 @@ func (r *Reactor) SetStateSyncingMetrics(v float64) {
|
||||
r.Metrics.StateSyncing.Set(v)
|
||||
}
|
||||
|
||||
func (r *Reactor) SetFastSyncingMetrics(v float64) {
|
||||
r.Metrics.FastSyncing.Set(v)
|
||||
func (r *Reactor) SetBlockSyncingMetrics(v float64) {
|
||||
r.Metrics.BlockSyncing.Set(v)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ type reactorTestSuite struct {
|
||||
states map[types.NodeID]*State
|
||||
reactors map[types.NodeID]*Reactor
|
||||
subs map[types.NodeID]types.Subscription
|
||||
fastsyncSubs map[types.NodeID]types.Subscription
|
||||
blocksyncSubs map[types.NodeID]types.Subscription
|
||||
stateChannels map[types.NodeID]*p2p.Channel
|
||||
dataChannels map[types.NodeID]*p2p.Channel
|
||||
voteChannels map[types.NodeID]*p2p.Channel
|
||||
@@ -60,11 +60,11 @@ func setup(t *testing.T, numNodes int, states []*State, size int) *reactorTestSu
|
||||
t.Helper()
|
||||
|
||||
rts := &reactorTestSuite{
|
||||
network: p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: numNodes}),
|
||||
states: make(map[types.NodeID]*State),
|
||||
reactors: make(map[types.NodeID]*Reactor, numNodes),
|
||||
subs: make(map[types.NodeID]types.Subscription, numNodes),
|
||||
fastsyncSubs: make(map[types.NodeID]types.Subscription, numNodes),
|
||||
network: p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: numNodes}),
|
||||
states: make(map[types.NodeID]*State),
|
||||
reactors: make(map[types.NodeID]*Reactor, numNodes),
|
||||
subs: make(map[types.NodeID]types.Subscription, numNodes),
|
||||
blocksyncSubs: make(map[types.NodeID]types.Subscription, numNodes),
|
||||
}
|
||||
|
||||
rts.stateChannels = rts.network.MakeChannelsNoCleanup(t, chDesc(StateChannel), new(tmcons.Message), size)
|
||||
@@ -94,13 +94,13 @@ func setup(t *testing.T, numNodes int, states []*State, size int) *reactorTestSu
|
||||
blocksSub, err := state.eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, size)
|
||||
require.NoError(t, err)
|
||||
|
||||
fsSub, err := state.eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryFastSyncStatus, size)
|
||||
fsSub, err := state.eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryBlockSyncStatus, size)
|
||||
require.NoError(t, err)
|
||||
|
||||
rts.states[nodeID] = state
|
||||
rts.subs[nodeID] = blocksSub
|
||||
rts.reactors[nodeID] = reactor
|
||||
rts.fastsyncSubs[nodeID] = fsSub
|
||||
rts.blocksyncSubs[nodeID] = fsSub
|
||||
|
||||
// simulate handle initChain in handshake
|
||||
if state.state.LastBlockHeight == 0 {
|
||||
@@ -263,9 +263,9 @@ func waitForBlockWithUpdatedValsAndValidateIt(
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func ensureFastSyncStatus(t *testing.T, msg tmpubsub.Message, complete bool, height int64) {
|
||||
func ensureBlockSyncStatus(t *testing.T, msg tmpubsub.Message, complete bool, height int64) {
|
||||
t.Helper()
|
||||
status, ok := msg.Data().(types.EventDataFastSyncStatus)
|
||||
status, ok := msg.Data().(types.EventDataBlockSyncStatus)
|
||||
|
||||
require.True(t, ok)
|
||||
require.Equal(t, complete, status.Complete)
|
||||
@@ -301,14 +301,14 @@ func TestReactorBasic(t *testing.T) {
|
||||
|
||||
wg.Wait()
|
||||
|
||||
for _, sub := range rts.fastsyncSubs {
|
||||
for _, sub := range rts.blocksyncSubs {
|
||||
wg.Add(1)
|
||||
|
||||
// wait till everyone makes the consensus switch
|
||||
go func(s types.Subscription) {
|
||||
defer wg.Done()
|
||||
msg := <-s.Out()
|
||||
ensureFastSyncStatus(t, msg, true, 0)
|
||||
ensureBlockSyncStatus(t, msg, true, 0)
|
||||
}(sub)
|
||||
}
|
||||
|
||||
|
||||
@@ -1203,8 +1203,8 @@ func (bs *mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSe
|
||||
func (bs *mockBlockStore) LoadBlockCommit(height int64) *types.Commit {
|
||||
return bs.commits[height-1]
|
||||
}
|
||||
func (bs *mockBlockStore) LoadSeenCommit(height int64) *types.Commit {
|
||||
return bs.commits[height-1]
|
||||
func (bs *mockBlockStore) LoadSeenCommit() *types.Commit {
|
||||
return bs.commits[len(bs.commits)-1]
|
||||
}
|
||||
|
||||
func (bs *mockBlockStore) PruneBlocks(height int64) (uint64, error) {
|
||||
|
||||
@@ -314,7 +314,14 @@ func (cs *State) LoadCommit(height int64) *types.Commit {
|
||||
defer cs.mtx.RUnlock()
|
||||
|
||||
if height == cs.blockStore.Height() {
|
||||
return cs.blockStore.LoadSeenCommit(height)
|
||||
commit := cs.blockStore.LoadSeenCommit()
|
||||
// NOTE: Retrieving the height of the most recent block and retrieving
|
||||
// the most recent commit does not currently occur as an atomic
|
||||
// operation. We check the height and commit here in case a more recent
|
||||
// commit has arrived since retrieving the latest height.
|
||||
if commit != nil && commit.Height == height {
|
||||
return commit
|
||||
}
|
||||
}
|
||||
|
||||
return cs.blockStore.LoadBlockCommit(height)
|
||||
@@ -594,15 +601,19 @@ func (cs *State) sendInternalMessage(mi msgInfo) {
|
||||
// Reconstruct LastCommit from SeenCommit, which we saved along with the block,
|
||||
// (which happens even before saving the state)
|
||||
func (cs *State) reconstructLastCommit(state sm.State) {
|
||||
seenCommit := cs.blockStore.LoadSeenCommit(state.LastBlockHeight)
|
||||
if seenCommit == nil {
|
||||
commit := cs.blockStore.LoadSeenCommit()
|
||||
if commit == nil || commit.Height != state.LastBlockHeight {
|
||||
commit = cs.blockStore.LoadBlockCommit(state.LastBlockHeight)
|
||||
}
|
||||
|
||||
if commit == nil {
|
||||
panic(fmt.Sprintf(
|
||||
"failed to reconstruct last commit; seen commit for height %v not found",
|
||||
"failed to reconstruct last commit; commit for height %v not found",
|
||||
state.LastBlockHeight,
|
||||
))
|
||||
}
|
||||
|
||||
lastPrecommits := types.CommitToVoteSet(state.ChainID, seenCommit, state.LastValidators)
|
||||
lastPrecommits := types.CommitToVoteSet(state.ChainID, commit, state.LastValidators)
|
||||
if !lastPrecommits.HasTwoThirdsMajority() {
|
||||
panic("failed to reconstruct last commit; does not have +2/3 maj")
|
||||
}
|
||||
@@ -2218,6 +2229,7 @@ func (cs *State) signVote(
|
||||
|
||||
err := cs.privValidator.SignVote(ctx, cs.state.ChainID, v)
|
||||
vote.Signature = v.Signature
|
||||
vote.Timestamp = v.Timestamp
|
||||
|
||||
return vote, err
|
||||
}
|
||||
@@ -2317,7 +2329,7 @@ func (cs *State) checkDoubleSigningRisk(height int64) error {
|
||||
}
|
||||
|
||||
for i := int64(1); i < doubleSignCheckHeight; i++ {
|
||||
lastCommit := cs.blockStore.LoadSeenCommit(height - i)
|
||||
lastCommit := cs.LoadCommit(height - i)
|
||||
if lastCommit != nil {
|
||||
for sigIdx, s := range lastCommit.Signatures {
|
||||
if s.BlockIDFlag == types.BlockIDFlagCommit && bytes.Equal(s.ValidatorAddress, valAddr) {
|
||||
|
||||
@@ -1939,6 +1939,30 @@ func TestStateOutputVoteStats(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestSignSameVoteTwice(t *testing.T) {
|
||||
config := configSetup(t)
|
||||
|
||||
_, vss := randState(config, 2)
|
||||
|
||||
randBytes := tmrand.Bytes(tmhash.Size)
|
||||
|
||||
vote := signVote(vss[1],
|
||||
config,
|
||||
tmproto.PrecommitType,
|
||||
randBytes,
|
||||
types.PartSetHeader{Total: 10, Hash: randBytes},
|
||||
)
|
||||
|
||||
vote2 := signVote(vss[1],
|
||||
config,
|
||||
tmproto.PrecommitType,
|
||||
randBytes,
|
||||
types.PartSetHeader{Total: 10, Hash: randBytes},
|
||||
)
|
||||
|
||||
require.Equal(t, vote, vote2)
|
||||
}
|
||||
|
||||
// subscribe subscribes test client to the given query and returns a channel with cap = 1.
|
||||
func subscribe(eventBus *types.EventBus, q tmpubsub.Query) <-chan tmpubsub.Message {
|
||||
sub, err := eventBus.Subscribe(context.Background(), testSubscriber, q)
|
||||
|
||||
Reference in New Issue
Block a user