github.com/aergoio/aergo@v1.3.1/p2p/subproto/block.go (about)

     1  /*
     2   * @file
     3   * @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package subproto
     7  
     8  import (
     9  	"github.com/aergoio/aergo-lib/log"
    10  	"github.com/aergoio/aergo/internal/enc"
    11  	"github.com/aergoio/aergo/message"
    12  	"github.com/aergoio/aergo/p2p/p2pcommon"
    13  	"github.com/aergoio/aergo/p2p/p2putil"
    14  	"github.com/aergoio/aergo/types"
    15  )
    16  
    17  type getBlockHeadersRequestHandler struct {
    18  	BaseMsgHandler
    19  	asyncHelper
    20  }
    21  
    22  var _ p2pcommon.MessageHandler = (*getBlockHeadersRequestHandler)(nil)
    23  
    24  type getBlockHeadersResponseHandler struct {
    25  	BaseMsgHandler
    26  }
    27  
    28  var _ p2pcommon.MessageHandler = (*getBlockHeadersResponseHandler)(nil)
    29  
    30  type newBlockNoticeHandler struct {
    31  	BaseMsgHandler
    32  }
    33  
    34  var _ p2pcommon.MessageHandler = (*newBlockNoticeHandler)(nil)
    35  
    36  type getAncestorRequestHandler struct {
    37  	BaseMsgHandler
    38  	asyncHelper
    39  }
    40  
    41  var _ p2pcommon.MessageHandler = (*getAncestorRequestHandler)(nil)
    42  
    43  type getAncestorResponseHandler struct {
    44  	BaseMsgHandler
    45  }
    46  
    47  var _ p2pcommon.MessageHandler = (*getAncestorResponseHandler)(nil)
    48  
    49  // newListBlockHeadersReqHandler creates handler for GetBlockHeadersRequest
    50  func NewGetBlockHeadersReqHandler(pm p2pcommon.PeerManager, peer p2pcommon.RemotePeer, logger *log.Logger, actor p2pcommon.ActorService) *getBlockHeadersRequestHandler {
    51  	bh := &getBlockHeadersRequestHandler{BaseMsgHandler{protocol: p2pcommon.GetBlockHeadersRequest, pm: pm, peer: peer, actor: actor, logger: logger}, newAsyncHelper()}
    52  	return bh
    53  }
    54  
    55  func (bh *getBlockHeadersRequestHandler) ParsePayload(rawbytes []byte) (p2pcommon.MessageBody, error) {
    56  	return p2putil.UnmarshalAndReturn(rawbytes, &types.GetBlockHeadersRequest{})
    57  }
    58  
    59  func (bh *getBlockHeadersRequestHandler) Handle(msg p2pcommon.Message, msgBody p2pcommon.MessageBody) {
    60  	remotePeer := bh.peer
    61  	data := msgBody.(*types.GetBlockHeadersRequest)
    62  	p2putil.DebugLogReceive(bh.logger, bh.protocol, msg.ID().String(), remotePeer, data)
    63  	if bh.issue() {
    64  		go bh.handleGetBlockHeaders(msg, data)
    65  	} else {
    66  		resp := &types.GetBlockHeadersResponse{
    67  			Hashes: nil, Headers: nil,
    68  			Status: types.ResultStatus_RESOURCE_EXHAUSTED,
    69  		}
    70  		remotePeer.SendMessage(remotePeer.MF().NewMsgResponseOrder(msg.ID(), p2pcommon.GetBlockHeadersResponse, resp))
    71  	}
    72  }
    73  
    74  func (bh *getBlockHeadersRequestHandler) handleGetBlockHeaders(msg p2pcommon.Message, data *types.GetBlockHeadersRequest) {
    75  	defer bh.release()
    76  	remotePeer := bh.peer
    77  
    78  	// find block info from chainservice
    79  	maxFetchSize := min(p2pcommon.MaxBlockHeaderResponseCount, data.Size)
    80  	idx := uint32(0)
    81  	hashes := make([][]byte, 0, data.Size)
    82  	headers := make([]*types.BlockHeader, 0, data.Size)
    83  	if len(data.Hash) > 0 {
    84  		hash := data.Hash
    85  		for idx < maxFetchSize {
    86  			foundBlock, err := bh.actor.GetChainAccessor().GetBlock(hash)
    87  			if err != nil || foundBlock == nil {
    88  				break
    89  			}
    90  			hashes = append(hashes, foundBlock.BlockHash())
    91  			headers = append(headers, getBlockHeader(foundBlock))
    92  			idx++
    93  			hash = foundBlock.Header.PrevBlockHash
    94  			if len(hash) == 0 {
    95  				break
    96  			}
    97  		}
    98  	} else {
    99  		end := types.BlockNo(0)
   100  		if types.BlockNo(data.Height) >= types.BlockNo(maxFetchSize) {
   101  			end = types.BlockNo(data.Height - uint64(maxFetchSize-1))
   102  		}
   103  		for i := types.BlockNo(data.Height); i >= end; i-- {
   104  			foundBlock, err := p2putil.ExtractBlockFromRequest(bh.actor.CallRequestDefaultTimeout(message.ChainSvc,
   105  				&message.GetBlockByNo{BlockNo: i}))
   106  			if err != nil || foundBlock == nil {
   107  				break
   108  			}
   109  			hashes = append(hashes, foundBlock.BlockHash())
   110  			headers = append(headers, getBlockHeader(foundBlock))
   111  			idx++
   112  		}
   113  	}
   114  	// generate response message
   115  	resp := &types.GetBlockHeadersResponse{
   116  		Hashes: hashes, Headers: headers,
   117  		Status: types.ResultStatus_OK,
   118  	}
   119  	remotePeer.SendMessage(remotePeer.MF().NewMsgResponseOrder(msg.ID(), p2pcommon.GetBlockHeadersResponse, resp))
   120  }
   121  
   122  func getBlockHeader(blk *types.Block) *types.BlockHeader {
   123  	return blk.Header
   124  }
   125  
   126  // newListBlockRespHandler creates handler for GetBlockHeadersResponse
   127  func NewGetBlockHeaderRespHandler(pm p2pcommon.PeerManager, peer p2pcommon.RemotePeer, logger *log.Logger, actor p2pcommon.ActorService) *getBlockHeadersResponseHandler {
   128  	bh := &getBlockHeadersResponseHandler{BaseMsgHandler{protocol: p2pcommon.GetBlockHeadersResponse, pm: pm, peer: peer, actor: actor, logger: logger}}
   129  	return bh
   130  }
   131  
   132  func (bh *getBlockHeadersResponseHandler) ParsePayload(rawbytes []byte) (p2pcommon.MessageBody, error) {
   133  	return p2putil.UnmarshalAndReturn(rawbytes, &types.GetBlockHeadersResponse{})
   134  }
   135  
   136  func (bh *getBlockHeadersResponseHandler) Handle(msg p2pcommon.Message, msgBody p2pcommon.MessageBody) {
   137  	remotePeer := bh.peer
   138  	data := msgBody.(*types.GetBlockHeadersResponse)
   139  	p2putil.DebugLogReceiveResponse(bh.logger, bh.protocol, msg.ID().String(), msg.OriginalID().String(), bh.peer, data)
   140  
   141  	// send block headers to blockchain service
   142  	remotePeer.ConsumeRequest(msg.OriginalID())
   143  
   144  	// TODO: it's not used yet, but used in RPC and can be used in future performance tuning
   145  }
   146  
   147  // newNewBlockNoticeHandler creates handler for NewBlockNotice
   148  func NewNewBlockNoticeHandler(pm p2pcommon.PeerManager, peer p2pcommon.RemotePeer, logger *log.Logger, actor p2pcommon.ActorService, sm p2pcommon.SyncManager) *newBlockNoticeHandler {
   149  	bh := &newBlockNoticeHandler{BaseMsgHandler: BaseMsgHandler{protocol: p2pcommon.NewBlockNotice, pm: pm, sm: sm, peer: peer, actor: actor, logger: logger}}
   150  	return bh
   151  }
   152  
   153  func (bh *newBlockNoticeHandler) ParsePayload(rawbytes []byte) (p2pcommon.MessageBody, error) {
   154  	return p2putil.UnmarshalAndReturn(rawbytes, &types.NewBlockNotice{})
   155  }
   156  
   157  func (bh *newBlockNoticeHandler) Handle(msg p2pcommon.Message, msgBody p2pcommon.MessageBody) {
   158  	remotePeer := bh.peer
   159  	data := msgBody.(*types.NewBlockNotice)
   160  	// remove to verbose log
   161  	// debugLogReceiveMsg(bh.logger, bh.protocol, msg.ID().String(), peerID, log.DoLazyEval(func() string { return enc.ToString(data.BlkHash) }))
   162  
   163  	if _, err := types.ParseToBlockID(data.BlockHash); err != nil {
   164  		// TODO Add penalty score and break
   165  		bh.logger.Info().Str(p2putil.LogPeerName, remotePeer.Name()).Str("hash", enc.ToString(data.BlockHash)).Msg("malformed blockHash")
   166  		return
   167  	}
   168  	// lru cache can't accept byte slice key
   169  	if !remotePeer.UpdateBlkCache(data.BlockHash, data.BlockNo) {
   170  		bh.sm. HandleNewBlockNotice(remotePeer, data)
   171  	}
   172  }
   173  
   174  func max(a, b uint32) uint32 {
   175  	if a > b {
   176  		return a
   177  	}
   178  	return b
   179  }
   180  func min(a, b uint32) uint32 {
   181  	if a < b {
   182  		return a
   183  	}
   184  	return b
   185  }
   186  
   187  // newGetAncestorReqHandler creates handler for GetAncestorRequest
   188  func NewGetAncestorReqHandler(pm p2pcommon.PeerManager, peer p2pcommon.RemotePeer, logger *log.Logger, actor p2pcommon.ActorService) *getAncestorRequestHandler {
   189  	bh := &getAncestorRequestHandler{BaseMsgHandler{protocol: p2pcommon.GetAncestorRequest, pm: pm, peer: peer, actor: actor, logger: logger}, newAsyncHelper()}
   190  	return bh
   191  }
   192  
   193  func (bh *getAncestorRequestHandler) ParsePayload(rawbytes []byte) (p2pcommon.MessageBody, error) {
   194  	return p2putil.UnmarshalAndReturn(rawbytes, &types.GetAncestorRequest{})
   195  }
   196  
   197  func (bh *getAncestorRequestHandler) Handle(msg p2pcommon.Message, msgBody p2pcommon.MessageBody) {
   198  	data := msgBody.(*types.GetAncestorRequest)
   199  
   200  	if bh.issue() {
   201  		go bh.handleGetAncestorReq(msg, data)
   202  	} else {
   203  		resp := &types.GetAncestorResponse{
   204  			Status: types.ResultStatus_RESOURCE_EXHAUSTED,
   205  		}
   206  		bh.peer.SendMessage(bh.peer.MF().NewMsgResponseOrder(msg.ID(), p2pcommon.GetAncestorResponse, resp))
   207  	}
   208  }
   209  
   210  func (bh *getAncestorRequestHandler) handleGetAncestorReq(msg p2pcommon.Message, data *types.GetAncestorRequest) {
   211  	defer bh.release()
   212  	remotePeer := bh.peer
   213  	status := types.ResultStatus_OK
   214  	if bh.logger.IsDebugEnabled() {
   215  		p2putil.DebugLogReceive(bh.logger, bh.protocol, msg.ID().String(), remotePeer, data)
   216  	}
   217  
   218  	// send to ChainSvc
   219  	// find ancestor from chainservice
   220  	ancestor := &types.BlockInfo{}
   221  
   222  	//TODO split rsp handler
   223  	rawResponse, err := bh.actor.CallRequestDefaultTimeout(
   224  		message.ChainSvc, &message.GetAncestor{Hashes: data.Hashes})
   225  	if err != nil {
   226  		//TODO error handling
   227  		status = types.ResultStatus_ABORTED
   228  	} else {
   229  		v := rawResponse.(message.GetAncestorRsp)
   230  		result := (*message.GetAncestorRsp)(&v)
   231  		if result.Err != nil {
   232  			status = types.ResultStatus_NOT_FOUND
   233  		} else {
   234  			ancestor = result.Ancestor
   235  		}
   236  	}
   237  
   238  	resp := &types.GetAncestorResponse{
   239  		Status:       status,
   240  		AncestorHash: ancestor.Hash,
   241  		AncestorNo:   ancestor.No,
   242  	}
   243  
   244  	bh.logger.Debug().Uint64("ancestorno", ancestor.No).Str("ancestorhash", enc.ToString(ancestor.Hash)).Msg("Sending get ancestor response")
   245  	remotePeer.SendMessage(remotePeer.MF().NewMsgResponseOrder(msg.ID(), p2pcommon.GetAncestorResponse, resp))
   246  }
   247  
   248  // newBlockRespHandler creates handler for GetAncestorResponse
   249  func NewGetAncestorRespHandler(pm p2pcommon.PeerManager, peer p2pcommon.RemotePeer, logger *log.Logger, actor p2pcommon.ActorService) *getAncestorResponseHandler {
   250  	bh := &getAncestorResponseHandler{BaseMsgHandler: BaseMsgHandler{protocol: p2pcommon.GetAncestorResponse, pm: pm, peer: peer, actor: actor, logger: logger}}
   251  	return bh
   252  }
   253  
   254  func (bh *getAncestorResponseHandler) ParsePayload(rawbytes []byte) (p2pcommon.MessageBody, error) {
   255  	return p2putil.UnmarshalAndReturn(rawbytes, &types.GetAncestorResponse{})
   256  }
   257  
   258  func (bh *getAncestorResponseHandler) Handle(msg p2pcommon.Message, msgBody p2pcommon.MessageBody) {
   259  	data := msgBody.(*types.GetAncestorResponse)
   260  	p2putil.DebugLogReceiveResponse(bh.logger, bh.protocol, msg.ID().String(), msg.OriginalID().String(), bh.peer,data)
   261  
   262  	// locate request data and remove it if found
   263  	bh.peer.GetReceiver(msg.OriginalID())(msg, data)
   264  }