Documentation ¶
Overview ¶
Package blocksync implements two versions of a reactor Service that are responsible for block propagation and gossip between peers. This mechanism was formerly known as fast-sync.
In order for a full node to successfully participate in consensus, it must have the latest view of state. The blocksync protocol is a mechanism in which peers may exchange and gossip entire blocks with one another, in a request/response type model, until they've successfully synced to the latest head block. Once succussfully synced, the full node can switch to an active role in consensus and will no longer blocksync and thus no longer run the blocksync process.
Note, the blocksync reactor Service gossips entire block and relevant data such that each receiving peer may construct the entire view of the blocksync state.
There is currently only one version of the blocksync reactor Service that is battle-tested, but whose test coverage is lacking and is not formally verified.
The v0 blocksync reactor Service has one p2p channel, BlockchainChannel. This channel is responsible for handling messages that both request blocks and respond to block requests from peers. For every block request from a peer, the reactor will execute respondToPeer which will fetch the block from the node's state store and respond to the peer. For every block response, the node will add the block to its pool via AddBlock.
Internally, v0 runs a poolRoutine that constantly checks for what blocks it needs and requests them. The poolRoutine is also responsible for taking blocks from the pool, saving and executing each block.
Index ¶
- Constants
- func GetChannelDescriptor() *p2p.ChannelDescriptor
- type BlockPool
- func (pool *BlockPool) AddBlock(peerID types.NodeID, block *types.Block, extCommit *types.ExtendedCommit, ...) error
- func (pool *BlockPool) GetStatus() (height int64, numPending int32, lenRequesters int)
- func (pool *BlockPool) IsCaughtUp() bool
- func (pool *BlockPool) LastAdvance() time.Time
- func (pool *BlockPool) MaxPeerHeight() int64
- func (pool *BlockPool) OnStart(ctx context.Context) error
- func (pool *BlockPool) OnStop()
- func (pool *BlockPool) PeekTwoBlocks() (first, second *types.Block, firstExtCommit *types.ExtendedCommit)
- func (pool *BlockPool) PopRequest()
- func (pool *BlockPool) RedoRequest(height int64) types.NodeID
- func (pool *BlockPool) RemovePeer(peerID types.NodeID)
- func (pool *BlockPool) SetPeerRange(peerID types.NodeID, base int64, height int64)
- type BlockRequest
- type Reactor
- func (r *Reactor) GetMaxPeerBlockHeight() int64
- func (r *Reactor) GetRemainingSyncTime() time.Duration
- func (r *Reactor) GetTotalSyncedTime() time.Duration
- func (r *Reactor) OnStart(ctx context.Context) error
- func (r *Reactor) OnStop()
- func (r *Reactor) PublishStatus(event types.EventDataBlockSyncStatus) error
- func (r *Reactor) SetChannel(ch *p2p.Channel)
- func (r *Reactor) SwitchToBlockSync(ctx context.Context, state state.State) error
- type RedoOp
- type RetryReason
Constants ¶
const ( // BlockSyncChannel is a channel for blocks and status updates BlockSyncChannel = p2p.ChannelID(0x40) )
const ( MaxMsgSize = types.MaxBlockSizeBytes + bcproto.BlockResponseMessagePrefixSize + bcproto.BlockResponseMessageFieldKeySize )
Variables ¶
This section is empty.
Functions ¶
func GetChannelDescriptor ¶
func GetChannelDescriptor() *p2p.ChannelDescriptor
Types ¶
type BlockPool ¶
type BlockPool struct { service.BaseService // contains filtered or unexported fields }
BlockPool keeps track of the block sync peers, block requests and block responses.
func NewBlockPool ¶
func NewBlockPool( logger log.Logger, start int64, requestsCh chan<- BlockRequest, errorsCh chan<- peerError, peerManager *p2p.PeerManager, ) *BlockPool
NewBlockPool returns a new BlockPool with the height equal to start. Block requests and errors will be sent to requestsCh and errorsCh accordingly.
func (*BlockPool) AddBlock ¶
func (pool *BlockPool) AddBlock(peerID types.NodeID, block *types.Block, extCommit *types.ExtendedCommit, blockSize int) error
AddBlock validates that the block comes from the peer it was expected from and calls the requester to store it.
This requires an extended commit at the same height as the supplied block - the block contains the last commit, but we need the latest commit in case we need to switch over from block sync to consensus at this height. If the height of the extended commit and the height of the block do not match, we do not add the block and return an error. TODO: ensure that blocks come in order for each peer.
func (*BlockPool) GetStatus ¶
GetStatus returns pool's height, numPending requests and the number of requesters.
func (*BlockPool) IsCaughtUp ¶
IsCaughtUp returns true if this node is caught up, false - otherwise.
func (*BlockPool) LastAdvance ¶
LastAdvance returns the time when the last block was processed (or start time if no blocks were processed).
func (*BlockPool) MaxPeerHeight ¶
MaxPeerHeight returns the highest reported height.
func (*BlockPool) OnStart ¶
OnStart implements service.Service by spawning requesters routine and recording pool's start time.
func (*BlockPool) PeekTwoBlocks ¶
func (pool *BlockPool) PeekTwoBlocks() (first, second *types.Block, firstExtCommit *types.ExtendedCommit)
PeekTwoBlocks returns blocks at pool.height and pool.height+1. We need to see the second block's Commit to validate the first block. So we peek two blocks at a time. We return an extended commit, containing vote extensions and their associated signatures, as this is critical to consensus in ABCI++ as we switch from block sync to consensus mode.
The caller will verify the commit.
func (*BlockPool) PopRequest ¶
func (pool *BlockPool) PopRequest()
PopRequest pops the first block at pool.height. It must have been validated by the second Commit from PeekTwoBlocks. TODO(thane): (?) and its corresponding ExtendedCommit.
func (*BlockPool) RedoRequest ¶
RedoRequest invalidates the block at pool.height, Remove the peer and redo request from others. Returns the ID of the removed peer.
func (*BlockPool) RemovePeer ¶
RemovePeer removes the peer with peerID from the pool. If there's no peer with peerID, function is a no-op.
type BlockRequest ¶
BlockRequest stores a block request identified by the block Height and the PeerID responsible for delivering the block.
type Reactor ¶
type Reactor struct { service.BaseService // contains filtered or unexported fields }
Reactor handles long-term catchup syncing.
func NewReactor ¶
func NewReactor( logger log.Logger, stateStore state.Store, blockExec *state.BlockExecutor, store *store.BlockStore, consReactor consensusReactor, peerEvents p2p.PeerEventSubscriber, peerManager *p2p.PeerManager, blockSync bool, metrics *consensus.Metrics, eventBus *eventbus.EventBus, restartCh chan struct{}, selfRemediationConfig *config.SelfRemediationConfig, ) *Reactor
NewReactor returns new reactor instance.
func (*Reactor) GetMaxPeerBlockHeight ¶
func (*Reactor) GetRemainingSyncTime ¶
func (*Reactor) GetTotalSyncedTime ¶
func (*Reactor) OnStart ¶
OnStart starts separate go routines for each p2p Channel and listens for envelopes on each. In addition, it also listens for peer updates and handles messages on that p2p channel accordingly. The caller must be sure to execute OnStop to ensure the outbound p2p Channels are closed.
If blockSync is enabled, we also start the pool and the pool processing goroutine. If the pool fails to start, an error is returned.
func (*Reactor) OnStop ¶
func (r *Reactor) OnStop()
OnStop stops the reactor by signaling to all spawned goroutines to exit and blocking until they all exit.
func (*Reactor) PublishStatus ¶
func (r *Reactor) PublishStatus(event types.EventDataBlockSyncStatus) error
func (*Reactor) SetChannel ¶
type RedoOp ¶
type RedoOp struct { PeerId types.NodeID Reason RetryReason }
type RetryReason ¶
type RetryReason string
const ( // Used to indicate the reason of the redo PeerRemoved RetryReason = "PeerRemoved" BadBlock RetryReason = "BadBlock" )