core, network: request blocks instead of headers

Closes #1192

1. We now have CMDGetBlockByIndex, so there's no need to request headers
   first when we can just ask for blocks.
2. We don't ask for headers (i.e. we don't send CMDGetHeaders),
   consequently, we shouldn't react on CMDHeaders.
3. But we still keep on reacting on CMDGetHeaders command as
   there could be a node which needs headers.
This commit is contained in:
Anna Shaleva 2020-07-31 17:12:13 +03:00
parent f6f3863e0e
commit 6c8accf18c
3 changed files with 7 additions and 61 deletions

View file

@ -446,23 +446,6 @@ func (s *Server) handleVersionCmd(p Peer, version *payload.Version) error {
return p.SendVersionAck(NewMessage(CMDVerack, nil)) return p.SendVersionAck(NewMessage(CMDVerack, nil))
} }
// handleHeadersCmd processes the headers received from its peer.
// If the headerHeight of the blockchain still smaller then the peer
// the server will request more headers.
// This method could best be called in a separate routine.
func (s *Server) handleHeadersCmd(p Peer, headers *payload.Headers) {
if err := s.chain.AddHeaders(headers.Hdrs...); err != nil {
s.log.Warn("failed processing headers", zap.Error(err))
return
}
// The peer will respond with a maximum of 2000 headers in one batch.
// We will ask one more batch here if needed. Eventually we will get synced
// due to the startProtocol routine that will ask headers every protoTick.
if s.chain.HeaderHeight() < p.LastBlockIndex() {
s.requestHeaders(p)
}
}
// handleBlockCmd processes the received block received from its peer. // handleBlockCmd processes the received block received from its peer.
func (s *Server) handleBlockCmd(p Peer, block *block.Block) error { func (s *Server) handleBlockCmd(p Peer, block *block.Block) error {
return s.bQueue.putBlock(block) return s.bQueue.putBlock(block)
@ -479,8 +462,8 @@ func (s *Server) handlePong(p Peer, pong *payload.Ping) error {
if err != nil { if err != nil {
return err return err
} }
if s.chain.HeaderHeight() < pong.LastBlockIndex { if s.chain.BlockHeight() < pong.LastBlockIndex {
return s.requestHeaders(p) return s.requestBlocks(p)
} }
return nil return nil
} }
@ -707,34 +690,12 @@ func (s *Server) handleGetAddrCmd(p Peer) error {
return p.EnqueueP2PMessage(NewMessage(CMDAddr, alist)) return p.EnqueueP2PMessage(NewMessage(CMDAddr, alist))
} }
// requestHeaders sends a getheaders message to the peer. // requestBlocks sends a CMDGetBlockByIndex message to the peer
// The peer will respond with headers op to a count of 2000.
func (s *Server) requestHeaders(p Peer) error {
payload := payload.NewGetBlockByIndex(s.chain.HeaderHeight(), -1)
return p.EnqueueP2PMessage(NewMessage(CMDGetHeaders, payload))
}
// requestBlocks sends a getdata message to the peer
// to sync up in blocks. A maximum of maxBlockBatch will // to sync up in blocks. A maximum of maxBlockBatch will
// send at once. // send at once.
func (s *Server) requestBlocks(p Peer) error { func (s *Server) requestBlocks(p Peer) error {
var ( payload := payload.NewGetBlockByIndex(s.chain.BlockHeight(), -1)
hashes []util.Uint256 return p.EnqueueP2PMessage(NewMessage(CMDGetBlockByIndex, payload))
hashStart = s.chain.BlockHeight() + 1
headerHeight = s.chain.HeaderHeight()
)
for hashStart <= headerHeight && len(hashes) < maxBlockBatch {
hash := s.chain.GetHeaderHash(int(hashStart))
hashes = append(hashes, hash)
hashStart++
}
if len(hashes) > 0 {
payload := payload.NewInventory(payload.BlockType, hashes)
return p.EnqueueP2PMessage(NewMessage(CMDGetData, payload))
} else if s.chain.HeaderHeight() < p.LastBlockIndex() {
return s.requestHeaders(p)
}
return nil
} }
// handleMessage processes the given message. // handleMessage processes the given message.
@ -768,9 +729,6 @@ func (s *Server) handleMessage(peer Peer, msg *Message) error {
case CMDGetHeaders: case CMDGetHeaders:
gh := msg.Payload.(*payload.GetBlockByIndex) gh := msg.Payload.(*payload.GetBlockByIndex)
return s.handleGetHeadersCmd(peer, gh) return s.handleGetHeadersCmd(peer, gh)
case CMDHeaders:
headers := msg.Payload.(*payload.Headers)
go s.handleHeadersCmd(peer, headers)
case CMDInv: case CMDInv:
inventory := msg.Payload.(*payload.Inventory) inventory := msg.Payload.(*payload.Inventory)
return s.handleInvCmd(peer, inventory) return s.handleInvCmd(peer, inventory)

View file

@ -142,15 +142,3 @@ func TestServerNotSendsVerack(t *testing.T) {
assert.NotNil(t, err) assert.NotNil(t, err)
require.Equal(t, errAlreadyConnected, err) require.Equal(t, errAlreadyConnected, err)
} }
func TestRequestHeaders(t *testing.T) {
var (
s = newTestServer(t, ServerConfig{})
p = newLocalPeer(t, s)
)
p.messageHandler = func(t *testing.T, msg *Message) {
assert.IsType(t, &payload.GetBlockByIndex{}, msg.Payload)
assert.Equal(t, CMDGetHeaders, msg.Command)
}
s.requestHeaders(p)
}

View file

@ -235,8 +235,8 @@ func (p *TCPPeer) StartProtocol() {
zap.Uint32("id", p.Version().Nonce)) zap.Uint32("id", p.Version().Nonce))
p.server.discovery.RegisterGoodAddr(p.PeerAddr().String(), p.version.Capabilities) p.server.discovery.RegisterGoodAddr(p.PeerAddr().String(), p.version.Capabilities)
if p.server.chain.HeaderHeight() < p.LastBlockIndex() { if p.server.chain.BlockHeight() < p.LastBlockIndex() {
err = p.server.requestHeaders(p) err = p.server.requestBlocks(p)
if err != nil { if err != nil {
p.Disconnect(err) p.Disconnect(err)
return return