package v2 import ( "errors" "github.com/gogo/protobuf/proto" "github.com/tendermint/tendermint/internal/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 }