package v2
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"github.com/tendermint/tendermint/p2p"
|
|
bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain"
|
|
"github.com/tendermint/tendermint/state"
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
var (
|
|
errPeerQueueFull = errors.New("peer queue full")
|
|
)
|
|
|
|
type iIO interface {
|
|
sendBlockRequest(peer p2p.Peer, height int64) error
|
|
sendBlockToPeer(block *types.Block, peer p2p.Peer) error
|
|
sendBlockNotFound(height int64, peer p2p.Peer) error
|
|
sendStatusResponse(base, height int64, peer p2p.Peer) error
|
|
|
|
sendStatusRequest(peer p2p.Peer) error
|
|
broadcastStatusRequest() error
|
|
|
|
trySwitchToConsensus(state state.State, skipWAL bool) bool
|
|
}
|
|
|
|
type switchIO struct {
|
|
sw *p2p.Switch
|
|
}
|
|
|
|
func newSwitchIo(sw *p2p.Switch) *switchIO {
|
|
return &switchIO{
|
|
sw: sw,
|
|
}
|
|
}
|
|
|
|
const (
|
|
// BlockchainChannel is a channel for blocks and status updates (`BlockStore` height)
|
|
BlockchainChannel = byte(0x40)
|
|
)
|
|
|
|
type consensusReactor interface {
|
|
// for when we switch from blockchain reactor and fast sync to
|
|
// the consensus machine
|
|
SwitchToConsensus(state state.State, skipWAL bool)
|
|
}
|
|
|
|
func (sio *switchIO) sendBlockRequest(peer p2p.Peer, height int64) error {
|
|
msgProto := &bcproto.Message{
|
|
Sum: &bcproto.Message_BlockRequest{
|
|
BlockRequest: &bcproto.BlockRequest{
|
|
Height: height,
|
|
},
|
|
},
|
|
}
|
|
|
|
msgBytes, err := proto.Marshal(msgProto)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
queued := peer.TrySend(BlockchainChannel, msgBytes)
|
|
if !queued {
|
|
return errPeerQueueFull
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (sio *switchIO) sendStatusResponse(base int64, height int64, peer p2p.Peer) error {
|
|
msgProto := &bcproto.Message{
|
|
Sum: &bcproto.Message_StatusResponse{
|
|
StatusResponse: &bcproto.StatusResponse{
|
|
Height: height,
|
|
Base: base,
|
|
},
|
|
},
|
|
}
|
|
|
|
msgBytes, err := proto.Marshal(msgProto)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if queued := peer.TrySend(BlockchainChannel, msgBytes); !queued {
|
|
return errPeerQueueFull
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (sio *switchIO) sendBlockToPeer(block *types.Block, peer p2p.Peer) error {
|
|
if block == nil {
|
|
panic("trying to send nil block")
|
|
}
|
|
|
|
bpb, err := block.ToProto()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msgProto := &bcproto.Message{
|
|
Sum: &bcproto.Message_BlockResponse{
|
|
BlockResponse: &bcproto.BlockResponse{
|
|
Block: bpb,
|
|
},
|
|
},
|
|
}
|
|
|
|
msgBytes, err := proto.Marshal(msgProto)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if queued := peer.TrySend(BlockchainChannel, msgBytes); !queued {
|
|
return errPeerQueueFull
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (sio *switchIO) sendBlockNotFound(height int64, peer p2p.Peer) error {
|
|
msgProto := &bcproto.Message{
|
|
Sum: &bcproto.Message_NoBlockResponse{
|
|
NoBlockResponse: &bcproto.NoBlockResponse{
|
|
Height: height,
|
|
},
|
|
},
|
|
}
|
|
|
|
msgBytes, err := proto.Marshal(msgProto)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if queued := peer.TrySend(BlockchainChannel, msgBytes); !queued {
|
|
return errPeerQueueFull
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (sio *switchIO) trySwitchToConsensus(state state.State, skipWAL bool) bool {
|
|
conR, ok := sio.sw.Reactor("CONSENSUS").(consensusReactor)
|
|
if ok {
|
|
conR.SwitchToConsensus(state, skipWAL)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
func (sio *switchIO) sendStatusRequest(peer p2p.Peer) error {
|
|
msgProto := &bcproto.Message{
|
|
Sum: &bcproto.Message_StatusRequest{
|
|
StatusRequest: &bcproto.StatusRequest{},
|
|
},
|
|
}
|
|
|
|
msgBytes, err := proto.Marshal(msgProto)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if queued := peer.TrySend(BlockchainChannel, msgBytes); !queued {
|
|
return errPeerQueueFull
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (sio *switchIO) broadcastStatusRequest() error {
|
|
msgProto := &bcproto.Message{
|
|
Sum: &bcproto.Message_StatusRequest{
|
|
StatusRequest: &bcproto.StatusRequest{},
|
|
},
|
|
}
|
|
|
|
msgBytes, err := proto.Marshal(msgProto)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// XXX: maybe we should use an io specific peer list here
|
|
sio.sw.Broadcast(BlockchainChannel, msgBytes)
|
|
|
|
return nil
|
|
}
|