Port getheaders
JSON-RPC command from dcrd
This commit is contained in:
parent
765ca28711
commit
7c44b6472f
9 changed files with 254 additions and 103 deletions
|
@ -90,6 +90,27 @@ func NewGetCurrentNetCmd() *GetCurrentNetCmd {
|
|||
return &GetCurrentNetCmd{}
|
||||
}
|
||||
|
||||
// GetHeadersCmd defines the getheaders JSON-RPC command.
|
||||
//
|
||||
// NOTE: This is a btcsuite extension ported from
|
||||
// github.com/decred/dcrd/dcrjson.
|
||||
type GetHeadersCmd struct {
|
||||
BlockLocators []string `json:"blocklocators"`
|
||||
HashStop string `json:"hashstop"`
|
||||
}
|
||||
|
||||
// NewGetHeadersCmd returns a new instance which can be used to issue a
|
||||
// getheaders JSON-RPC command.
|
||||
//
|
||||
// NOTE: This is a btcsuite extension ported from
|
||||
// github.com/decred/dcrd/dcrjson.
|
||||
func NewGetHeadersCmd(blockLocators []string, hashStop string) *GetHeadersCmd {
|
||||
return &GetHeadersCmd{
|
||||
BlockLocators: blockLocators,
|
||||
HashStop: hashStop,
|
||||
}
|
||||
}
|
||||
|
||||
// VersionCmd defines the version JSON-RPC command.
|
||||
//
|
||||
// NOTE: This is a btcsuite extension ported from
|
||||
|
@ -112,5 +133,6 @@ func init() {
|
|||
MustRegisterCmd("generate", (*GenerateCmd)(nil), flags)
|
||||
MustRegisterCmd("getbestblock", (*GetBestBlockCmd)(nil), flags)
|
||||
MustRegisterCmd("getcurrentnet", (*GetCurrentNetCmd)(nil), flags)
|
||||
MustRegisterCmd("getheaders", (*GetHeadersCmd)(nil), flags)
|
||||
MustRegisterCmd("version", (*VersionCmd)(nil), flags)
|
||||
}
|
||||
|
|
|
@ -136,6 +136,46 @@ func TestBtcdExtCmds(t *testing.T) {
|
|||
marshalled: `{"jsonrpc":"1.0","method":"getcurrentnet","params":[],"id":1}`,
|
||||
unmarshalled: &btcjson.GetCurrentNetCmd{},
|
||||
},
|
||||
{
|
||||
name: "getheaders",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("getheaders", []string{}, "")
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewGetHeadersCmd(
|
||||
[]string{},
|
||||
"",
|
||||
)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"getheaders","params":[[],""],"id":1}`,
|
||||
unmarshalled: &btcjson.GetHeadersCmd{
|
||||
BlockLocators: []string{},
|
||||
HashStop: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "getheaders - with arguments",
|
||||
newCmd: func() (interface{}, error) {
|
||||
return btcjson.NewCmd("getheaders", []string{"000000000000000001f1739002418e2f9a84c47a4fd2a0eb7a787a6b7dc12f16", "0000000000000000026f4b7f56eef057b32167eb5ad9ff62006f1807b7336d10"}, "000000000000000000ba33b33e1fad70b69e234fc24414dd47113bff38f523f7")
|
||||
},
|
||||
staticCmd: func() interface{} {
|
||||
return btcjson.NewGetHeadersCmd(
|
||||
[]string{
|
||||
"000000000000000001f1739002418e2f9a84c47a4fd2a0eb7a787a6b7dc12f16",
|
||||
"0000000000000000026f4b7f56eef057b32167eb5ad9ff62006f1807b7336d10",
|
||||
},
|
||||
"000000000000000000ba33b33e1fad70b69e234fc24414dd47113bff38f523f7",
|
||||
)
|
||||
},
|
||||
marshalled: `{"jsonrpc":"1.0","method":"getheaders","params":[["000000000000000001f1739002418e2f9a84c47a4fd2a0eb7a787a6b7dc12f16","0000000000000000026f4b7f56eef057b32167eb5ad9ff62006f1807b7336d10"],"000000000000000000ba33b33e1fad70b69e234fc24414dd47113bff38f523f7"],"id":1}`,
|
||||
unmarshalled: &btcjson.GetHeadersCmd{
|
||||
BlockLocators: []string{
|
||||
"000000000000000001f1739002418e2f9a84c47a4fd2a0eb7a787a6b7dc12f16",
|
||||
"0000000000000000026f4b7f56eef057b32167eb5ad9ff62006f1807b7336d10",
|
||||
},
|
||||
HashStop: "000000000000000000ba33b33e1fad70b69e234fc24414dd47113bff38f523f7",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
newCmd: func() (interface{}, error) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2016 The btcsuite developers
|
||||
// Copyright (c) 2015-2016 The Decred developers
|
||||
// Copyright (c) 2016-2017 The btcsuite developers
|
||||
// Copyright (c) 2015-2017 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2016 The btcsuite developers
|
||||
// Copyright (c) 2016-2017 The btcsuite developers
|
||||
// Copyright (c) 2015-2016 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
|
|
@ -84,35 +84,45 @@ func NewHash(newHash []byte) (*Hash, error) {
|
|||
// the hexadecimal string of a byte-reversed hash, but any missing characters
|
||||
// result in zero padding at the end of the Hash.
|
||||
func NewHashFromStr(hash string) (*Hash, error) {
|
||||
// Return error if hash string is too long.
|
||||
if len(hash) > MaxHashStringSize {
|
||||
return nil, ErrHashStrSize
|
||||
}
|
||||
|
||||
// Hex decoder expects the hash to be a multiple of two.
|
||||
if len(hash)%2 != 0 {
|
||||
hash = "0" + hash
|
||||
}
|
||||
|
||||
// Convert string hash to bytes.
|
||||
buf, err := hex.DecodeString(hash)
|
||||
ret := new(Hash)
|
||||
err := Decode(ret, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Un-reverse the decoded bytes, copying into in leading bytes of a
|
||||
// Hash. There is no need to explicitly pad the result as any
|
||||
// missing (when len(buf) < HashSize) bytes from the decoded hex string
|
||||
// will remain zeros at the end of the Hash.
|
||||
var ret Hash
|
||||
blen := len(buf)
|
||||
mid := blen / 2
|
||||
if blen%2 != 0 {
|
||||
mid++
|
||||
}
|
||||
blen--
|
||||
for i, b := range buf[:mid] {
|
||||
ret[i], ret[blen-i] = buf[blen-i], b
|
||||
}
|
||||
return &ret, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Decode decodes the byte-reversed hexadecimal string encoding of a Hash to a
|
||||
// destination.
|
||||
func Decode(dst *Hash, src string) error {
|
||||
// Return error if hash string is too long.
|
||||
if len(src) > MaxHashStringSize {
|
||||
return ErrHashStrSize
|
||||
}
|
||||
|
||||
// Hex decoder expects the hash to be a multiple of two. When not, pad
|
||||
// with a leading zero.
|
||||
var srcBytes []byte
|
||||
if len(src)%2 == 0 {
|
||||
srcBytes = []byte(src)
|
||||
} else {
|
||||
srcBytes = make([]byte, 1+len(src))
|
||||
srcBytes[0] = '0'
|
||||
copy(srcBytes[1:], src)
|
||||
}
|
||||
|
||||
// Hex decode the source bytes to a temporary destination.
|
||||
var reversedHash Hash
|
||||
_, err := hex.Decode(reversedHash[HashSize-hex.DecodedLen(len(srcBytes)):], srcBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reverse copy from the temporary hash to destination. Because the
|
||||
// temporary was zeroed, the written result will be correctly padded.
|
||||
for i, b := range reversedHash[:HashSize/2] {
|
||||
dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -584,6 +584,7 @@ The following is an overview of the RPC methods which are implemented by btcd, b
|
|||
|5|[node](#node)|N|Attempts to add or remove a peer. |None|
|
||||
|6|[generate](#generate)|N|When in simnet or regtest mode, generate a set number of blocks. |None|
|
||||
|7|[version](#version)|Y|Returns the JSON-RPC API version.|
|
||||
|8|[getheaders](#getheaders)|Y|Returns block headers starting with the first known block hash from the request.|
|
||||
|
||||
|
||||
<a name="ExtMethodDetails" />
|
||||
|
@ -678,6 +679,19 @@ The following is an overview of the RPC methods which are implemented by btcd, b
|
|||
|
||||
***
|
||||
|
||||
<a name="getheaders"/>
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
|Method|getheaders|
|
||||
|Parameters|1. Block Locators (JSON array, required)<br /> `[ (json array of strings)`<br /> `"blocklocator", (string) the known block hash`<br /> `...`<br /> `]`<br />2. hashstop (string) - last desired block's hash|
|
||||
|Description|Returns block headers starting with the first known block hash from the request.|
|
||||
|Returns|`[ (json array of strings)`<br /> `"blockheader",`<br /> `...`<br />`]`|
|
||||
|Example Return|`[`<br /> `"0000002099417930b2ae09feda10e38b58c0f6bb44b4d60fa33f0e000000000000000000d53...",`<br /> `"000000203ba25a173bfd24d09e0c76002a910b685ca297bd09a17b020000000000000000702..."`<br />`]`|
|
||||
[Return to Overview](#MethodOverview)<br />
|
||||
|
||||
***
|
||||
|
||||
<a name="WSExtMethods" />
|
||||
### 7. Websocket Extension Methods (Websocket-specific)
|
||||
|
||||
|
|
69
rpcserver.go
69
rpcserver.go
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2015-2016 The Decred developers
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Copyright (c) 2015-2017 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -45,9 +45,9 @@ import (
|
|||
|
||||
// API version constants
|
||||
const (
|
||||
jsonrpcSemverString = "1.0.0"
|
||||
jsonrpcSemverString = "1.1.0"
|
||||
jsonrpcSemverMajor = 1
|
||||
jsonrpcSemverMinor = 0
|
||||
jsonrpcSemverMinor = 1
|
||||
jsonrpcSemverPatch = 0
|
||||
)
|
||||
|
||||
|
@ -163,6 +163,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
|
|||
"getdifficulty": handleGetDifficulty,
|
||||
"getgenerate": handleGetGenerate,
|
||||
"gethashespersec": handleGetHashesPerSec,
|
||||
"getheaders": handleGetHeaders,
|
||||
"getinfo": handleGetInfo,
|
||||
"getmempoolinfo": handleGetMempoolInfo,
|
||||
"getmininginfo": handleGetMiningInfo,
|
||||
|
@ -270,6 +271,7 @@ var rpcLimited = map[string]struct{}{
|
|||
"getblockhash": {},
|
||||
"getcurrentnet": {},
|
||||
"getdifficulty": {},
|
||||
"getheaders": {},
|
||||
"getinfo": {},
|
||||
"getnettotals": {},
|
||||
"getnetworkhashps": {},
|
||||
|
@ -2148,6 +2150,65 @@ func handleGetHashesPerSec(s *rpcServer, cmd interface{}, closeChan <-chan struc
|
|||
return int64(s.server.cpuMiner.HashesPerSecond()), nil
|
||||
}
|
||||
|
||||
// handleGetHeaders implements the getheaders command.
|
||||
//
|
||||
// NOTE: This is a btcsuite extension ported from
|
||||
// github.com/decred/dcrd.
|
||||
func handleGetHeaders(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||
c := cmd.(*btcjson.GetHeadersCmd)
|
||||
blockLocators := make([]*chainhash.Hash, len(c.BlockLocators))
|
||||
for i := range c.BlockLocators {
|
||||
blockLocator, err := chainhash.NewHashFromStr(c.BlockLocators[i])
|
||||
if err != nil {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInvalidParameter,
|
||||
Message: "Failed to decode block locator: " +
|
||||
err.Error(),
|
||||
}
|
||||
}
|
||||
blockLocators[i] = blockLocator
|
||||
}
|
||||
var hashStop chainhash.Hash
|
||||
if c.HashStop != "" {
|
||||
err := chainhash.Decode(&hashStop, c.HashStop)
|
||||
if err != nil {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCInvalidParameter,
|
||||
Message: "Failed to decode hashstop: " + err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
blockHashes, err := s.server.locateBlocks(blockLocators, &hashStop)
|
||||
if err != nil {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCDatabase,
|
||||
Message: "Failed to fetch hashes of block " +
|
||||
"headers: " + err.Error(),
|
||||
}
|
||||
}
|
||||
blockHeaders, err := fetchHeaders(s.server.db, blockHashes)
|
||||
if err != nil {
|
||||
return nil, &btcjson.RPCError{
|
||||
Code: btcjson.ErrRPCDatabase,
|
||||
Message: "Failed to fetch headers of located blocks: " +
|
||||
err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
hexBlockHeaders := make([]string, len(blockHeaders))
|
||||
var buf bytes.Buffer
|
||||
for i, h := range blockHeaders {
|
||||
err := h.Serialize(&buf)
|
||||
if err != nil {
|
||||
return nil, internalRPCError(err.Error(),
|
||||
"Failed to serialize block header")
|
||||
}
|
||||
hexBlockHeaders[i] = hex.EncodeToString(buf.Bytes())
|
||||
buf.Reset()
|
||||
}
|
||||
return hexBlockHeaders, nil
|
||||
}
|
||||
|
||||
// handleGetInfo implements the getinfo command. We only return the fields
|
||||
// that are not related to wallet functionality.
|
||||
func handleGetInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2015-2016 The btcsuite developers
|
||||
// Copyright (c) 2015-2016 The Decred developers
|
||||
// Copyright (c) 2015-2017 The btcsuite developers
|
||||
// Copyright (c) 2015-2017 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -360,6 +360,12 @@ var helpDescsEnUS = map[string]string{
|
|||
"infowalletresult-relayfee": "The minimum relay fee for non-free transactions in BTC/KB",
|
||||
"infowalletresult-errors": "Any current errors",
|
||||
|
||||
// GetHeadersCmd help.
|
||||
"getheaders--synopsis": "Returns block headers starting with the first known block hash from the request",
|
||||
"getheaders-blocklocators": "JSON array of hex-encoded hashes of blocks. Headers are returned starting from the first known hash in this list",
|
||||
"getheaders-hashstop": "Block hash to stop including block headers for; if not found, all headers to the latest known block are returned.",
|
||||
"getheaders--result0": "Serialized block headers of all located blocks, limited to some arbitrary maximum number of hashes (currently 2000, which matches the wire protocol headers message, but this is not guaranteed)",
|
||||
|
||||
// GetInfoCmd help.
|
||||
"getinfo--synopsis": "Returns a JSON object containing various state info.",
|
||||
|
||||
|
@ -646,6 +652,7 @@ var rpcResultTypes = map[string][]interface{}{
|
|||
"getdifficulty": {(*float64)(nil)},
|
||||
"getgenerate": {(*bool)(nil)},
|
||||
"gethashespersec": {(*float64)(nil)},
|
||||
"getheaders": {(*[]string)(nil)},
|
||||
"getinfo": {(*btcjson.InfoChainResult)(nil)},
|
||||
"getmempoolinfo": {(*btcjson.GetMempoolInfoResult)(nil)},
|
||||
"getmininginfo": {(*btcjson.GetMiningInfoResult)(nil)},
|
||||
|
|
117
server.go
117
server.go
|
@ -1,4 +1,5 @@
|
|||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Copyright (c) 2015-2017 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -640,58 +641,30 @@ func (sp *serverPeer) OnGetBlocks(_ *peer.Peer, msg *wire.MsgGetBlocks) {
|
|||
}
|
||||
}
|
||||
|
||||
// OnGetHeaders is invoked when a peer receives a getheaders bitcoin
|
||||
// message.
|
||||
func (sp *serverPeer) OnGetHeaders(_ *peer.Peer, msg *wire.MsgGetHeaders) {
|
||||
// Ignore getheaders requests if not in sync.
|
||||
if !sp.server.blockManager.IsCurrent() {
|
||||
return
|
||||
}
|
||||
|
||||
// locateBlocks returns the hashes of the blocks after the first known block in
|
||||
// locators, until hashStop is reached, or up to a max of
|
||||
// wire.MaxBlockHeadersPerMsg block hashes. This implements the search
|
||||
// algorithm used by getheaders.
|
||||
func (s *server) locateBlocks(locators []*chainhash.Hash, hashStop *chainhash.Hash) ([]chainhash.Hash, error) {
|
||||
// Attempt to look up the height of the provided stop hash.
|
||||
chain := sp.server.blockManager.chain
|
||||
chain := s.blockManager.chain
|
||||
endIdx := int32(math.MaxInt32)
|
||||
height, err := chain.BlockHeightByHash(&msg.HashStop)
|
||||
height, err := chain.BlockHeightByHash(hashStop)
|
||||
if err == nil {
|
||||
endIdx = height + 1
|
||||
}
|
||||
|
||||
// There are no block locators so a specific header is being requested
|
||||
// as identified by the stop hash.
|
||||
if len(msg.BlockLocatorHashes) == 0 {
|
||||
if len(locators) == 0 {
|
||||
// No blocks with the stop hash were found so there is nothing
|
||||
// to do. Just return. This behavior mirrors the reference
|
||||
// implementation.
|
||||
if endIdx == math.MaxInt32 {
|
||||
return
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Fetch the raw block header bytes from the database.
|
||||
var headerBytes []byte
|
||||
err := sp.server.db.View(func(dbTx database.Tx) error {
|
||||
var err error
|
||||
headerBytes, err = dbTx.FetchBlockHeader(&msg.HashStop)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
peerLog.Warnf("Lookup of known block hash failed: %v",
|
||||
err)
|
||||
return
|
||||
}
|
||||
|
||||
// Deserialize the block header.
|
||||
var header wire.BlockHeader
|
||||
err = header.Deserialize(bytes.NewReader(headerBytes))
|
||||
if err != nil {
|
||||
peerLog.Warnf("Block header deserialize failed: %v",
|
||||
err)
|
||||
return
|
||||
}
|
||||
|
||||
headersMsg := wire.NewMsgHeaders()
|
||||
headersMsg.AddBlockHeader(&header)
|
||||
sp.QueueMessage(headersMsg, nil)
|
||||
return
|
||||
return []chainhash.Hash{*hashStop}, nil
|
||||
}
|
||||
|
||||
// Find the most recent known block based on the block locator.
|
||||
|
@ -700,8 +673,8 @@ func (sp *serverPeer) OnGetHeaders(_ *peer.Peer, msg *wire.MsgGetHeaders) {
|
|||
// over with the genesis block if unknown block locators are provided.
|
||||
// This mirrors the behavior in the reference implementation.
|
||||
startIdx := int32(1)
|
||||
for _, hash := range msg.BlockLocatorHashes {
|
||||
height, err := chain.BlockHeightByHash(hash)
|
||||
for _, loc := range locators {
|
||||
height, err := chain.BlockHeightByHash(loc)
|
||||
if err == nil {
|
||||
// Start with the next hash since we know this one.
|
||||
startIdx = height + 1
|
||||
|
@ -709,43 +682,67 @@ func (sp *serverPeer) OnGetHeaders(_ *peer.Peer, msg *wire.MsgGetHeaders) {
|
|||
}
|
||||
}
|
||||
|
||||
// Don't attempt to fetch more than we can put into a single message.
|
||||
// Don't attempt to fetch more than we can put into a single wire
|
||||
// message.
|
||||
if endIdx-startIdx > wire.MaxBlockHeadersPerMsg {
|
||||
endIdx = startIdx + wire.MaxBlockHeadersPerMsg
|
||||
}
|
||||
|
||||
// Fetch the inventory from the block database.
|
||||
hashList, err := chain.HeightRange(startIdx, endIdx)
|
||||
if err != nil {
|
||||
peerLog.Warnf("Header lookup failed: %v", err)
|
||||
return
|
||||
}
|
||||
return chain.HeightRange(startIdx, endIdx)
|
||||
}
|
||||
|
||||
// Generate headers message and send it.
|
||||
headersMsg := wire.NewMsgHeaders()
|
||||
err = sp.server.db.View(func(dbTx database.Tx) error {
|
||||
for i := range hashList {
|
||||
headerBytes, err := dbTx.FetchBlockHeader(&hashList[i])
|
||||
// fetchHeaders fetches and decodes headers from the db for each hash in
|
||||
// blockHashes.
|
||||
func fetchHeaders(db database.DB, blockHashes []chainhash.Hash) ([]*wire.BlockHeader, error) {
|
||||
headers := make([]*wire.BlockHeader, 0, len(blockHashes))
|
||||
err := db.View(func(dbTx database.Tx) error {
|
||||
rawHeaders, err := dbTx.FetchBlockHeaders(blockHashes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var header wire.BlockHeader
|
||||
err = header.Deserialize(bytes.NewReader(headerBytes))
|
||||
for _, headerBytes := range rawHeaders {
|
||||
h := new(wire.BlockHeader)
|
||||
err = h.Deserialize(bytes.NewReader(headerBytes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headersMsg.AddBlockHeader(&header)
|
||||
headers = append(headers, h)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
peerLog.Warnf("Failed to build headers: %v", err)
|
||||
return headers, err
|
||||
}
|
||||
|
||||
// OnGetHeaders is invoked when a peer receives a getheaders bitcoin
|
||||
// message.
|
||||
func (sp *serverPeer) OnGetHeaders(_ *peer.Peer, msg *wire.MsgGetHeaders) {
|
||||
// Ignore getheaders requests if not in sync.
|
||||
if !sp.server.blockManager.IsCurrent() {
|
||||
return
|
||||
}
|
||||
|
||||
sp.QueueMessage(headersMsg, nil)
|
||||
blockHashes, err := sp.server.locateBlocks(msg.BlockLocatorHashes,
|
||||
&msg.HashStop)
|
||||
if err != nil {
|
||||
peerLog.Errorf("OnGetHeaders: failed to fetch hashes: %v", err)
|
||||
return
|
||||
}
|
||||
blockHeaders, err := fetchHeaders(sp.server.db, blockHashes)
|
||||
if err != nil {
|
||||
peerLog.Errorf("OnGetHeaders: failed to fetch block headers: "+
|
||||
"%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(blockHeaders) > wire.MaxBlockHeadersPerMsg {
|
||||
peerLog.Warnf("OnGetHeaders: fetched more block headers than " +
|
||||
"allowed per message")
|
||||
// Can still recover from this error, just slice off the extra
|
||||
// headers and continue queing the message.
|
||||
blockHeaders = blockHeaders[:wire.MaxBlockHeaderPayload]
|
||||
}
|
||||
sp.QueueMessage(&wire.MsgHeaders{Headers: blockHeaders}, nil)
|
||||
}
|
||||
|
||||
// enforceNodeBloomFlag disconnects the peer if the server is not configured to
|
||||
|
|
Loading…
Reference in a new issue