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  }