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 }