network: implement getblocks command

Fixes #577, tested with C# nodes connecting to neo-go privnet.
This commit is contained in:
Roman Khimov 2019-12-25 19:40:18 +03:00
parent 9145855d2c
commit 234d94d27e
2 changed files with 37 additions and 0 deletions

View file

@ -5,6 +5,11 @@ import (
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
// Maximum inventory hashes number is limited to 500.
const (
MaxHashesCount = 500
)
// GetBlocks contains fields and methods to be shared with the // GetBlocks contains fields and methods to be shared with the
type GetBlocks struct { type GetBlocks struct {
// hash of latest block that node requests // hash of latest block that node requests

View file

@ -463,6 +463,35 @@ func (s *Server) handleGetDataCmd(p Peer, inv *payload.Inventory) error {
return nil return nil
} }
// handleGetBlocksCmd processes the getblocks request.
func (s *Server) handleGetBlocksCmd(p Peer, gb *payload.GetBlocks) error {
if len(gb.HashStart) < 1 {
return errInvalidHashStart
}
startHash := gb.HashStart[0]
if startHash.Equals(gb.HashStop) {
return nil
}
start, err := s.chain.GetHeader(startHash)
if err != nil {
return err
}
blockHashes := make([]util.Uint256, 0)
for i := start.Index + 1; i < start.Index+1+payload.MaxHashesCount; i++ {
hash := s.chain.GetHeaderHash(int(i))
if hash.Equals(util.Uint256{}) || hash.Equals(gb.HashStop) {
break
}
blockHashes = append(blockHashes, hash)
}
if len(blockHashes) == 0 {
return nil
}
payload := payload.NewInventory(payload.BlockType, blockHashes)
return p.WriteMsg(NewMessage(s.Net, CMDInv, payload))
}
// handleGetHeadersCmd processes the getheaders request. // handleGetHeadersCmd processes the getheaders request.
func (s *Server) handleGetHeadersCmd(p Peer, gh *payload.GetBlocks) error { func (s *Server) handleGetHeadersCmd(p Peer, gh *payload.GetBlocks) error {
if len(gh.HashStart) < 1 { if len(gh.HashStart) < 1 {
@ -585,6 +614,9 @@ func (s *Server) handleMessage(peer Peer, msg *Message) error {
case CMDGetAddr: case CMDGetAddr:
// it has no payload // it has no payload
return s.handleGetAddrCmd(peer) return s.handleGetAddrCmd(peer)
case CMDGetBlocks:
gb := msg.Payload.(*payload.GetBlocks)
return s.handleGetBlocksCmd(peer, gb)
case CMDGetData: case CMDGetData:
inv := msg.Payload.(*payload.Inventory) inv := msg.Payload.(*payload.Inventory)
return s.handleGetDataCmd(peer, inv) return s.handleGetDataCmd(peer, inv)