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  }