github.com/Finschia/ostracon@v1.1.5/blockchain/v2/io.go (about) 1 package v2 2 3 import ( 4 "fmt" 5 6 bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain" 7 8 "github.com/Finschia/ostracon/p2p" 9 ocbcproto "github.com/Finschia/ostracon/proto/ostracon/blockchain" 10 "github.com/Finschia/ostracon/state" 11 "github.com/Finschia/ostracon/types" 12 ) 13 14 type iIO interface { 15 sendBlockRequest(peerID p2p.ID, height int64) error 16 sendBlockToPeer(block *types.Block, peerID p2p.ID) error 17 sendBlockNotFound(height int64, peerID p2p.ID) error 18 sendStatusResponse(base, height int64, peerID p2p.ID) error 19 20 broadcastStatusRequest() 21 22 trySwitchToConsensus(state state.State, skipWAL bool) bool 23 } 24 25 type switchIO struct { 26 sw *p2p.Switch 27 } 28 29 func newSwitchIo(sw *p2p.Switch) *switchIO { 30 return &switchIO{ 31 sw: sw, 32 } 33 } 34 35 const ( 36 // BlockchainChannel is a channel for blocks and status updates (`BlockStore` height) 37 BlockchainChannel = byte(0x40) 38 ) 39 40 type consensusReactor interface { 41 // for when we switch from blockchain reactor and fast sync to 42 // the consensus machine 43 SwitchToConsensus(state state.State, skipWAL bool) 44 } 45 46 func (sio *switchIO) sendBlockRequest(peerID p2p.ID, height int64) error { 47 peer := sio.sw.Peers().Get(peerID) 48 if peer == nil { 49 return fmt.Errorf("peer not found") 50 } 51 if queued := p2p.TrySendEnvelopeShim(peer, p2p.Envelope{ //nolint: staticcheck 52 ChannelID: BlockchainChannel, 53 Message: &bcproto.BlockRequest{Height: height}, 54 }, sio.sw.Logger); !queued { 55 return fmt.Errorf("send queue full") 56 } 57 return nil 58 } 59 60 func (sio *switchIO) sendStatusResponse(base int64, height int64, peerID p2p.ID) error { 61 peer := sio.sw.Peers().Get(peerID) 62 if peer == nil { 63 return fmt.Errorf("peer not found") 64 } 65 66 if queued := p2p.TrySendEnvelopeShim(peer, p2p.Envelope{ //nolint: staticcheck 67 ChannelID: BlockchainChannel, 68 Message: &bcproto.StatusRequest{}, 69 }, sio.sw.Logger); !queued { 70 return fmt.Errorf("peer queue full") 71 } 72 73 return nil 74 } 75 76 func (sio *switchIO) sendBlockToPeer(block *types.Block, peerID p2p.ID) error { 77 peer := sio.sw.Peers().Get(peerID) 78 if peer == nil { 79 return fmt.Errorf("peer not found") 80 } 81 if block == nil { 82 panic("trying to send nil block") 83 } 84 85 bpb, err := block.ToProto() 86 if err != nil { 87 return err 88 } 89 90 if queued := p2p.TrySendEnvelopeShim(peer, p2p.Envelope{ //nolint: staticcheck 91 ChannelID: BlockchainChannel, 92 Message: &ocbcproto.BlockResponse{Block: bpb}, 93 }, sio.sw.Logger); !queued { 94 return fmt.Errorf("peer queue full") 95 } 96 97 return nil 98 } 99 100 func (sio *switchIO) sendBlockNotFound(height int64, peerID p2p.ID) error { 101 peer := sio.sw.Peers().Get(peerID) 102 if peer == nil { 103 return fmt.Errorf("peer not found") 104 } 105 if queued := p2p.TrySendEnvelopeShim(peer, p2p.Envelope{ //nolint: staticcheck 106 ChannelID: BlockchainChannel, 107 Message: &bcproto.NoBlockResponse{Height: height}, 108 }, sio.sw.Logger); !queued { 109 return fmt.Errorf("peer queue full") 110 } 111 112 return nil 113 } 114 115 func (sio *switchIO) trySwitchToConsensus(state state.State, skipWAL bool) bool { 116 conR, ok := sio.sw.Reactor("CONSENSUS").(consensusReactor) 117 if ok { 118 conR.SwitchToConsensus(state, skipWAL) 119 } 120 return ok 121 } 122 123 func (sio *switchIO) broadcastStatusRequest() { 124 // XXX: maybe we should use an io specific peer list here 125 sio.sw.BroadcastEnvelope(p2p.Envelope{ 126 ChannelID: BlockchainChannel, 127 Message: &bcproto.StatusRequest{}, 128 }) 129 }