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