[NOD-545] Remove headers first related logic (#621)

* [NOD-545] Remove headers first related logic

* [NOD-545] Fix tests

* [NOD-545] Change getTopHeadersMaxHeaders to be equal to getHeadersMaxHeaders
This commit is contained in:
Ori Newman 2020-02-04 14:54:42 +02:00 committed by GitHub
parent 4ffb5daa37
commit 45dc1a3e7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 22 additions and 1136 deletions

View File

@ -1741,7 +1741,7 @@ func (dag *BlockDAG) antiPastHeadersBetween(lowHash, highHash *daghash.Hash, max
}
// GetTopHeaders returns the top wire.MaxBlockHeadersPerMsg block headers ordered by blue score.
func (dag *BlockDAG) GetTopHeaders(highHash *daghash.Hash) ([]*wire.BlockHeader, error) {
func (dag *BlockDAG) GetTopHeaders(highHash *daghash.Hash, maxHeaders uint64) ([]*wire.BlockHeader, error) {
highNode := &dag.virtual.blockNode
if highHash != nil {
highNode = dag.index.LookupNode(highHash)
@ -1754,7 +1754,7 @@ func (dag *BlockDAG) GetTopHeaders(highHash *daghash.Hash) ([]*wire.BlockHeader,
queue.pushSet(highNode.parents)
visited := newSet()
for i := uint32(0); queue.Len() > 0 && len(headers) < wire.MaxBlockHeadersPerMsg; i++ {
for i := uint32(0); queue.Len() > 0 && uint64(len(headers)) < maxHeaders; i++ {
var current *blockNode
current = queue.pop()
if !visited.contains(current) {
@ -1791,9 +1791,9 @@ func (dag *BlockDAG) RUnlock() {
// wire.MaxBlockHeadersPerMsg block headers.
//
// This function is safe for concurrent access.
func (dag *BlockDAG) AntiPastHeadersBetween(lowHash, highHash *daghash.Hash) ([]*wire.BlockHeader, error) {
func (dag *BlockDAG) AntiPastHeadersBetween(lowHash, highHash *daghash.Hash, maxHeaders uint64) ([]*wire.BlockHeader, error) {
dag.dagLock.RLock()
headers, err := dag.antiPastHeadersBetween(lowHash, highHash, wire.MaxBlockHeadersPerMsg)
headers, err := dag.antiPastHeadersBetween(lowHash, highHash, maxHeaders)
if err != nil {
return nil, err
}

View File

@ -143,10 +143,6 @@ func messageSummary(msg wire.Message) string {
return fmt.Sprintf("low hash %s, high hash %s", msg.LowHash,
msg.HighHash)
case *wire.MsgGetHeaders:
return fmt.Sprintf("low hash %s, high hash %s", msg.LowHash,
msg.HighHash)
case *wire.MsgGetBlockLocator:
return fmt.Sprintf("high hash %s, low hash %s", msg.HighHash,
msg.LowHash)
@ -157,9 +153,6 @@ func messageSummary(msg wire.Message) string {
}
return fmt.Sprintf("no locator")
case *wire.MsgHeaders:
return fmt.Sprintf("num %d", len(msg.Headers))
case *wire.MsgReject:
// Ensure the variable length strings don't contain any
// characters which are even remotely dangerous such as HTML

View File

@ -164,10 +164,6 @@ type MessageListeners struct {
// OnReject is invoked when a peer receives a reject kaspa message.
OnReject func(p *Peer, msg *wire.MsgReject)
// OnSendHeaders is invoked when a peer receives a sendheaders kaspa
// message.
OnSendHeaders func(p *Peer, msg *wire.MsgSendHeaders)
// OnGetSelectedTip is invoked when a peer receives a getSelectedTip kaspa
// message.
OnGetSelectedTip func()
@ -410,16 +406,15 @@ type Peer struct {
cfg Config
inbound bool
flagsMtx sync.Mutex // protects the peer flags below
na *wire.NetAddress
id int32
userAgent string
services wire.ServiceFlag
versionKnown bool
advertisedProtoVer uint32 // protocol version advertised by remote
protocolVersion uint32 // negotiated protocol version
sendHeadersPreferred bool // peer sent a sendheaders message
verAckReceived bool
flagsMtx sync.Mutex // protects the peer flags below
na *wire.NetAddress
id int32
userAgent string
services wire.ServiceFlag
versionKnown bool
advertisedProtoVer uint32 // protocol version advertised by remote
protocolVersion uint32 // negotiated protocol version
verAckReceived bool
knownInventory *mruInventoryMap
prevGetBlockInvsMtx sync.Mutex
@ -717,18 +712,6 @@ func (p *Peer) TimeOffset() int64 {
return timeOffset
}
// WantsHeaders returns if the peer wants header messages instead of
// inventory vectors for blocks.
//
// This function is safe for concurrent access.
func (p *Peer) WantsHeaders() bool {
p.flagsMtx.Lock()
sendHeadersPreferred := p.sendHeadersPreferred
p.flagsMtx.Unlock()
return sendHeadersPreferred
}
// localVersionMsg creates a version message that can be used to send to the
// remote peer.
func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) {
@ -878,37 +861,6 @@ func (p *Peer) PushBlockLocatorMsg(locator blockdag.BlockLocator) error {
return nil
}
// PushGetHeadersMsg sends a getblockinvs message for the provided block locator
// and low hash. It will ignore back-to-back duplicate requests.
//
// This function is safe for concurrent access.
func (p *Peer) PushGetHeadersMsg(lowHash, highHash *daghash.Hash) error {
// Filter duplicate getheaders requests.
p.prevGetHdrsMtx.Lock()
isDuplicate := p.prevGetHdrsHigh != nil && p.prevGetHdrsLow != nil &&
lowHash != nil && highHash.IsEqual(p.prevGetHdrsHigh) &&
lowHash.IsEqual(p.prevGetHdrsLow)
p.prevGetHdrsMtx.Unlock()
if isDuplicate {
log.Tracef("Filtering duplicate [getheaders] with low hash %s",
lowHash)
return nil
}
// Construct the getheaders request and queue it to be sent.
msg := wire.NewMsgGetHeaders(lowHash, highHash)
p.QueueMessage(msg, nil)
// Update the previous getheaders request information for filtering
// duplicates.
p.prevGetHdrsMtx.Lock()
p.prevGetHdrsLow = lowHash
p.prevGetHdrsHigh = highHash
p.prevGetHdrsMtx.Unlock()
return nil
}
// PushRejectMsg sends a reject message for the provided command, reject code,
// reject reason, and hash. The hash will only be used when the command is a tx
// or block and should be nil in other cases. The wait parameter will cause the
@ -1181,13 +1133,6 @@ func (p *Peer) maybeAddDeadline(pendingResponses map[string]time.Time, msgCmd st
pendingResponses[wire.CmdTx] = deadline
pendingResponses[wire.CmdNotFound] = deadline
case wire.CmdGetHeaders:
// Expects a headers message. Use a longer deadline since it
// can take a while for the remote peer to load all of the
// headers.
deadline = time.Now().Add(stallResponseTimeout * 3)
pendingResponses[wire.CmdHeaders] = deadline
case wire.CmdGetSelectedTip:
// Expects a selected tip message.
pendingResponses[wire.CmdSelectedTip] = deadline
@ -1510,15 +1455,6 @@ out:
p.cfg.Listeners.OnReject(p, msg)
}
case *wire.MsgSendHeaders:
p.flagsMtx.Lock()
p.sendHeadersPreferred = true
p.flagsMtx.Unlock()
if p.cfg.Listeners.OnSendHeaders != nil {
p.cfg.Listeners.OnSendHeaders(p, msg)
}
case *wire.MsgGetSelectedTip:
if p.cfg.Listeners.OnGetSelectedTip != nil {
p.cfg.Listeners.OnGetSelectedTip()

View File

@ -394,9 +394,6 @@ func TestPeerListeners(t *testing.T) {
OnReject: func(p *peer.Peer, msg *wire.MsgReject) {
ok <- msg
},
OnSendHeaders: func(p *peer.Peer, msg *wire.MsgSendHeaders) {
ok <- msg
},
},
UserAgentName: "peer",
UserAgentVersion: "1.0",
@ -505,10 +502,6 @@ func TestPeerListeners(t *testing.T) {
"OnReject",
wire.NewMsgReject("block", wire.RejectDuplicate, "dupe block"),
},
{
"OnSendHeaders",
wire.NewMsgSendHeaders(),
},
}
t.Logf("Running %d tests", len(tests))
for _, test := range tests {
@ -618,10 +611,6 @@ func TestOutboundPeer(t *testing.T) {
t.Errorf("PushGetBlockInvsMsg: unexpected err %v\n", err)
return
}
if err := p2.PushGetHeadersMsg(nil, &daghash.Hash{}); err != nil {
t.Errorf("PushGetHeadersMsg: unexpected err %v\n", err)
return
}
p2.PushRejectMsg("block", wire.RejectMalformed, "malformed", nil, false)
p2.PushRejectMsg("block", wire.RejectInvalid, "invalid", nil, false)
@ -630,7 +619,6 @@ func TestOutboundPeer(t *testing.T) {
p2.QueueMessage(wire.NewMsgGetAddr(false, nil), nil)
p2.QueueMessage(wire.NewMsgPing(1), nil)
p2.QueueMessage(wire.NewMsgGetData(), nil)
p2.QueueMessage(wire.NewMsgGetHeaders(&daghash.ZeroHash, &daghash.ZeroHash), nil)
p2.QueueMessage(wire.NewMsgFeeFilter(20000), nil)
p2.Disconnect()

View File

@ -750,26 +750,6 @@ func (s *Server) handleRelayInvMsg(state *peerState, msg relayMsg) {
return true
}
// If the inventory is a block and the peer prefers headers,
// generate and send a headers message instead of an inventory
// message.
if msg.invVect.Type == wire.InvTypeBlock && sp.WantsHeaders() {
blockHeader, ok := msg.data.(wire.BlockHeader)
if !ok {
peerLog.Warnf("Underlying data for headers" +
" is not a block header")
return true
}
msgHeaders := wire.NewMsgHeaders()
if err := msgHeaders.AddBlockHeader(&blockHeader); err != nil {
peerLog.Errorf("Failed to add block"+
" header: %s", err)
return true
}
sp.QueueMessage(msgHeaders, nil)
return true
}
if msg.invVect.Type == wire.InvTypeTx {
// Don't relay the transaction to the peer when it has
// transaction relaying disabled.

View File

@ -7,6 +7,8 @@ import (
"github.com/kaspanet/kaspad/util/daghash"
)
const getHeadersMaxHeaders = 2000
// handleGetHeaders implements the getHeaders command.
func handleGetHeaders(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
c := cmd.(*rpcmodel.GetHeadersCmd)
@ -25,7 +27,7 @@ func handleGetHeaders(s *Server, cmd interface{}, closeChan <-chan struct{}) (in
return nil, rpcDecodeHexError(c.HighHash)
}
}
headers, err := s.cfg.SyncMgr.AntiPastHeadersBetween(lowHash, highHash)
headers, err := s.cfg.SyncMgr.AntiPastHeadersBetween(lowHash, highHash, getHeadersMaxHeaders)
if err != nil {
return nil, &rpcmodel.RPCError{
Code: rpcmodel.ErrRPCMisc,

View File

@ -7,6 +7,8 @@ import (
"github.com/kaspanet/kaspad/util/daghash"
)
const getTopHeadersMaxHeaders = getHeadersMaxHeaders
// handleGetTopHeaders implements the getTopHeaders command.
func handleGetTopHeaders(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
c := cmd.(*rpcmodel.GetTopHeadersCmd)
@ -19,7 +21,7 @@ func handleGetTopHeaders(s *Server, cmd interface{}, closeChan <-chan struct{})
return nil, rpcDecodeHexError(*c.HighHash)
}
}
headers, err := s.cfg.DAG.GetTopHeaders(highHash)
headers, err := s.cfg.DAG.GetTopHeaders(highHash, getTopHeadersMaxHeaders)
if err != nil {
return nil, internalRPCError(err.Error(),
"Failed to get top headers")

View File

@ -275,6 +275,6 @@ func (b *rpcSyncMgr) SyncPeerID() int32 {
//
// This function is safe for concurrent access and is part of the
// rpcserverSyncManager interface implementation.
func (b *rpcSyncMgr) AntiPastHeadersBetween(lowHash, highHash *daghash.Hash) ([]*wire.BlockHeader, error) {
return b.server.DAG.AntiPastHeadersBetween(lowHash, highHash)
func (b *rpcSyncMgr) AntiPastHeadersBetween(lowHash, highHash *daghash.Hash, maxHeaders uint64) ([]*wire.BlockHeader, error) {
return b.server.DAG.AntiPastHeadersBetween(lowHash, highHash, maxHeaders)
}

View File

@ -739,7 +739,7 @@ type rpcserverSyncManager interface {
// AntiPastHeadersBetween returns the headers of the blocks between the
// lowHash's antiPast and highHash's antiPast, or up to
// wire.MaxBlockHeadersPerMsg block headers.
AntiPastHeadersBetween(lowHash, highHash *daghash.Hash) ([]*wire.BlockHeader, error)
AntiPastHeadersBetween(lowHash, highHash *daghash.Hash, maxHeaders uint64) ([]*wire.BlockHeader, error)
}
// rpcserverConfig is a descriptor containing the RPC server configuration.

View File

@ -374,69 +374,6 @@ func BenchmarkWriteBlockHeader(b *testing.B) {
}
}
// BenchmarkDecodeGetHeaders performs a benchmark on how long it takes to
// decode a getheaders message.
func BenchmarkDecodeGetHeaders(b *testing.B) {
pver := ProtocolVersion
var m MsgGetHeaders
m.LowHash = &daghash.Hash{1}
m.HighHash = &daghash.Hash{1}
// Serialize it so the bytes are available to test the decode below.
var bb bytes.Buffer
if err := m.KaspaEncode(&bb, pver); err != nil {
b.Fatalf("MsgGetHeaders.KaspaEncode: unexpected error: %v", err)
}
buf := bb.Bytes()
r := bytes.NewReader(buf)
var msg MsgGetHeaders
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Seek(0, 0)
msg.KaspaDecode(r, pver)
}
}
// BenchmarkDecodeHeaders performs a benchmark on how long it takes to
// decode a headers message with the maximum number of headers and maximum number of
// parent hashes per header.
func BenchmarkDecodeHeaders(b *testing.B) {
// Create a message with the maximum number of headers.
pver := ProtocolVersion
var m MsgHeaders
for i := 0; i < MaxBlockHeadersPerMsg; i++ {
hash, err := daghash.NewHashFromStr(fmt.Sprintf("%x", i))
if err != nil {
b.Fatalf("NewHashFromStr: unexpected error: %v", err)
}
parentHashes := make([]*daghash.Hash, MaxNumParentBlocks)
for j := byte(0); j < MaxNumParentBlocks; j++ {
hash, err := daghash.NewHashFromStr(fmt.Sprintf("%x%x", i, j))
if err != nil {
b.Fatalf("NewHashFromStr: unexpected error: %v", err)
}
parentHashes[i] = hash
}
m.AddBlockHeader(NewBlockHeader(1, parentHashes, hash, hash, hash, 0, uint64(i)))
}
// Serialize it so the bytes are available to test the decode below.
var bb bytes.Buffer
if err := m.KaspaEncode(&bb, pver); err != nil {
b.Fatalf("MsgHeaders.KaspaEncode: unexpected error: %v", err)
}
buf := bb.Bytes()
r := bytes.NewReader(buf)
var msg MsgHeaders
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Seek(0, 0)
msg.KaspaDecode(r, pver)
}
}
// BenchmarkDecodeGetBlockInvs performs a benchmark on how long it takes to
// decode a getblockinvs message.
func BenchmarkDecodeGetBlockInvs(b *testing.B) {

View File

@ -39,8 +39,6 @@ const (
CmdNotFound = "notfound"
CmdBlock = "block"
CmdTx = "tx"
CmdGetHeaders = "getheaders"
CmdHeaders = "headers"
CmdPing = "ping"
CmdPong = "pong"
CmdFilterAdd = "filteradd"
@ -48,7 +46,6 @@ const (
CmdFilterLoad = "filterload"
CmdMerkleBlock = "merkleblock"
CmdReject = "reject"
CmdSendHeaders = "sendheaders"
CmdFeeFilter = "feefilter"
CmdGetBlockLocator = "getlocator"
CmdBlockLocator = "locator"
@ -114,12 +111,6 @@ func makeEmptyMessage(command string) (Message, error) {
case CmdPong:
msg = &MsgPong{}
case CmdGetHeaders:
msg = &MsgGetHeaders{}
case CmdHeaders:
msg = &MsgHeaders{}
case CmdFilterAdd:
msg = &MsgFilterAdd{}
@ -135,9 +126,6 @@ func makeEmptyMessage(command string) (Message, error) {
case CmdReject:
msg = &MsgReject{}
case CmdSendHeaders:
msg = &MsgSendHeaders{}
case CmdFeeFilter:
msg = &MsgFeeFilter{}

View File

@ -60,12 +60,9 @@ func TestMessage(t *testing.T) {
msgTx := NewNativeMsgTx(1, nil, nil)
msgPing := NewMsgPing(123123)
msgPong := NewMsgPong(123123)
msgGetHeaders := NewMsgGetHeaders(&daghash.Hash{}, &daghash.Hash{})
msgGetBlockLocator := NewMsgGetBlockLocator(&daghash.ZeroHash, &daghash.ZeroHash)
msgBlockLocator := NewMsgBlockLocator()
msgSendHeaders := NewMsgSendHeaders()
msgFeeFilter := NewMsgFeeFilter(123456)
msgHeaders := NewMsgHeaders()
msgFilterAdd := NewMsgFilterAdd([]byte{0x01})
msgFilterClear := NewMsgFilterClear()
msgFilterLoad := NewMsgFilterLoad([]byte{0x01}, 10, 0, BloomUpdateNone)
@ -92,12 +89,9 @@ func TestMessage(t *testing.T) {
{msgTx, msgTx, pver, Mainnet, 58},
{msgPing, msgPing, pver, Mainnet, 32},
{msgPong, msgPong, pver, Mainnet, 32},
{msgGetHeaders, msgGetHeaders, pver, Mainnet, 88},
{msgGetBlockLocator, msgGetBlockLocator, pver, Mainnet, 88},
{msgBlockLocator, msgBlockLocator, pver, Mainnet, 25},
{msgSendHeaders, msgSendHeaders, pver, Mainnet, 24},
{msgFeeFilter, msgFeeFilter, pver, Mainnet, 32},
{msgHeaders, msgHeaders, pver, Mainnet, 25},
{msgFilterAdd, msgFilterAdd, pver, Mainnet, 26},
{msgFilterClear, msgFilterClear, pver, Mainnet, 24},
{msgFilterLoad, msgFilterLoad, pver, Mainnet, 35},

View File

@ -1,78 +0,0 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"io"
"github.com/kaspanet/kaspad/util/daghash"
)
// MsgGetHeaders implements the Message interface and represents a kaspa
// getheaders message. It is used to request a list of block headers for
// blocks starting after the last known hash in the slice of block locator
// hashes. The list is returned via a headers message (MsgHeaders) and is
// limited by a specific hash to stop at or the maximum number of block headers
// per message, which is currently 2000.
//
// Set the HighHash field to the hash at which to stop and use
// AddBlockLocatorHash to build up the list of block locator hashes.
//
// The algorithm for building the block locator hashes should be to add the
// hashes in reverse order until you reach the genesis block. In order to keep
// the list of locator hashes to a resonable number of entries, first add the
// most recent 10 block hashes, then double the step each loop iteration to
// exponentially decrease the number of hashes the further away from head and
// closer to the genesis block you get.
type MsgGetHeaders struct {
LowHash *daghash.Hash
HighHash *daghash.Hash
}
// KaspaDecode decodes r using the kaspa protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgGetHeaders) KaspaDecode(r io.Reader, pver uint32) error {
msg.LowHash = &daghash.Hash{}
err := ReadElement(r, msg.LowHash)
if err != nil {
return err
}
msg.HighHash = &daghash.Hash{}
return ReadElement(r, msg.HighHash)
}
// KaspaEncode encodes the receiver to w using the kaspa protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgGetHeaders) KaspaEncode(w io.Writer, pver uint32) error {
err := WriteElement(w, msg.LowHash)
if err != nil {
return err
}
return WriteElement(w, msg.HighHash)
}
// Command returns the protocol command string for the message. This is part
// of the Message interface implementation.
func (msg *MsgGetHeaders) Command() string {
return CmdGetHeaders
}
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgGetHeaders) MaxPayloadLength(pver uint32) uint32 {
// low hash + high hash.
return 2 * daghash.HashSize
}
// NewMsgGetHeaders returns a new kaspa getheaders message that conforms to
// the Message interface. See MsgGetHeaders for details.
func NewMsgGetHeaders(lowHash, highHash *daghash.Hash) *MsgGetHeaders {
return &MsgGetHeaders{
LowHash: lowHash,
HighHash: highHash,
}
}

View File

@ -1,227 +0,0 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"bytes"
"github.com/pkg/errors"
"io"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/kaspanet/kaspad/util/daghash"
)
// TestGetHeaders tests the MsgGetHeader API.
func TestGetHeaders(t *testing.T) {
pver := ProtocolVersion
// Block 99500 hash.
hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0"
lowHash, err := daghash.NewHashFromStr(hashStr)
if err != nil {
t.Errorf("NewHashFromStr: %v", err)
}
// Ensure the command is expected value.
wantCmd := "getheaders"
msg := NewMsgGetHeaders(lowHash, &daghash.ZeroHash)
if cmd := msg.Command(); cmd != wantCmd {
t.Errorf("NewMsgGetHeaders: wrong command - got %v want %v",
cmd, wantCmd)
}
// Ensure max payload is low hash (32 bytes) + high hash (32 bytes)..
wantPayload := uint32(64)
maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload {
t.Errorf("MaxPayloadLength: wrong max payload length for "+
"protocol version %d - got %v, want %v", pver,
maxPayload, wantPayload)
}
}
// TestGetHeadersWire tests the MsgGetHeaders wire encode and decode.
func TestGetHeadersWire(t *testing.T) {
hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535"
lowHash, err := daghash.NewHashFromStr(hashStr)
if err != nil {
t.Errorf("NewHashFromStr: %v", err)
}
hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
highHash, err := daghash.NewHashFromStr(hashStr)
if err != nil {
t.Errorf("NewHashFromStr: %v", err)
}
// MsgGetHeaders message with no block locators or high hash.
noLowAndHighHash := NewMsgGetHeaders(&daghash.ZeroHash, &daghash.ZeroHash)
noLowAndHighHashEncoded := []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Low hash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // High hash
}
// MsgGetHeaders message with multiple block locators and a high hash.
withLowAndHighHash := NewMsgGetHeaders(lowHash, highHash)
withLowAndHighHashEncoded := []byte{
0x35, 0x75, 0x95, 0xb7, 0xf6, 0x8c, 0xb1, 0x60,
0xcc, 0xba, 0x2c, 0x9a, 0xc5, 0x42, 0x5f, 0xd9,
0x6f, 0x0a, 0x01, 0x3d, 0xc9, 0x7e, 0xc8, 0x40,
0x0f, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Low hash
0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39,
0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2,
0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa,
0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // High hash
}
tests := []struct {
in *MsgGetHeaders // Message to encode
out *MsgGetHeaders // Expected decoded message
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
}{
// Message with no low hash and high hash.
{
noLowAndHighHash,
noLowAndHighHash,
noLowAndHighHashEncoded,
ProtocolVersion,
},
// Message with low hash and high hash.
{
withLowAndHighHash,
withLowAndHighHash,
withLowAndHighHashEncoded,
ProtocolVersion,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode the message to wire format.
var buf bytes.Buffer
err := test.in.KaspaEncode(&buf, test.pver)
if err != nil {
t.Errorf("KaspaEncode #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("KaspaEncode #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Decode the message from wire format.
var msg MsgGetHeaders
rbuf := bytes.NewReader(test.buf)
err = msg.KaspaDecode(rbuf, test.pver)
if err != nil {
t.Errorf("KaspaDecode #%d error %v", i, err)
continue
}
if !reflect.DeepEqual(&msg, test.out) {
t.Errorf("KaspaDecode #%d\n got: %s want: %s", i,
spew.Sdump(&msg), spew.Sdump(test.out))
continue
}
}
}
// TestGetHeadersWireErrors performs negative tests against wire encode and
// decode of MsgGetHeaders to confirm error paths work correctly.
func TestGetHeadersWireErrors(t *testing.T) {
// Set protocol inside getheaders message.
pver := ProtocolVersion
hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535"
lowHash, err := daghash.NewHashFromStr(hashStr)
if err != nil {
t.Errorf("NewHashFromStr: %v", err)
}
hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
highHash, err := daghash.NewHashFromStr(hashStr)
if err != nil {
t.Errorf("NewHashFromStr: %v", err)
}
// MsgGetHeaders message with multiple block locators and a high hash.
baseGetHeaders := NewMsgGetHeaders(lowHash, highHash)
baseGetHeadersEncoded := []byte{
0x35, 0x75, 0x95, 0xb7, 0xf6, 0x8c, 0xb1, 0x60,
0xcc, 0xba, 0x2c, 0x9a, 0xc5, 0x42, 0x5f, 0xd9,
0x6f, 0x0a, 0x01, 0x3d, 0xc9, 0x7e, 0xc8, 0x40,
0x0f, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Low hash
0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39,
0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2,
0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa,
0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // High hash
}
tests := []struct {
in *MsgGetHeaders // Value to encode
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
max int // Max size of fixed buffer to induce errors
writeErr error // Expected write error
readErr error // Expected read error
}{
// Force error in low hash.
{baseGetHeaders, baseGetHeadersEncoded, pver, 0, io.ErrShortWrite, io.EOF},
// Force error in high hash.
{baseGetHeaders, baseGetHeadersEncoded, pver, 32, io.ErrShortWrite, io.EOF},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
w := newFixedWriter(test.max)
err := test.in.KaspaEncode(w, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
t.Errorf("KaspaEncode #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// For errors which are not of type MessageError, check them for
// equality.
if msgErr := &(MessageError{}); !errors.As(err, &msgErr) {
if err != test.writeErr {
t.Errorf("KaspaEncode #%d wrong error got: %v, "+
"want: %v", i, err, test.writeErr)
continue
}
}
// Decode from wire format.
var msg MsgGetHeaders
r := newFixedReader(test.max, test.buf)
err = msg.KaspaDecode(r, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
t.Errorf("KaspaDecode #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
// For errors which are not of type MessageError, check them for
// equality.
if msgErr := &(MessageError{}); !errors.As(err, &msgErr) {
if err != test.readErr {
t.Errorf("KaspaDecode #%d wrong error got: %v, "+
"want: %v", i, err, test.readErr)
continue
}
}
}
}

View File

@ -1,136 +0,0 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"fmt"
"io"
)
// MaxBlockHeadersPerMsg is the maximum number of block headers that can be in
// a single kaspa headers message.
const MaxBlockHeadersPerMsg = 2000
// MsgHeaders implements the Message interface and represents a kaspa headers
// message. It is used to deliver block header information in response
// to a getheaders message (MsgGetHeaders). The maximum number of block headers
// per message is currently 2000. See MsgGetHeaders for details on requesting
// the headers.
type MsgHeaders struct {
Headers []*BlockHeader
}
// AddBlockHeader adds a new block header to the message.
func (msg *MsgHeaders) AddBlockHeader(bh *BlockHeader) error {
if len(msg.Headers)+1 > MaxBlockHeadersPerMsg {
str := fmt.Sprintf("too many block headers in message [max %d]",
MaxBlockHeadersPerMsg)
return messageError("MsgHeaders.AddBlockHeader", str)
}
msg.Headers = append(msg.Headers, bh)
return nil
}
// KaspaDecode decodes r using the kaspa protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgHeaders) KaspaDecode(r io.Reader, pver uint32) error {
count, err := ReadVarInt(r)
if err != nil {
return err
}
// Limit to max block headers per message.
if count > MaxBlockHeadersPerMsg {
str := fmt.Sprintf("too many block headers for message "+
"[count %d, max %d]", count, MaxBlockHeadersPerMsg)
return messageError("MsgHeaders.KaspaDecode", str)
}
// Create a contiguous slice of headers to deserialize into in order to
// reduce the number of allocations.
headers := make([]BlockHeader, count)
msg.Headers = make([]*BlockHeader, 0, count)
for i := uint64(0); i < count; i++ {
bh := &headers[i]
err := readBlockHeader(r, pver, bh)
if err != nil {
return err
}
txCount, err := ReadVarInt(r)
if err != nil {
return err
}
// Ensure the transaction count is zero for headers.
if txCount > 0 {
str := fmt.Sprintf("block headers may not contain "+
"transactions [count %d]", txCount)
return messageError("MsgHeaders.KaspaDecode", str)
}
msg.AddBlockHeader(bh)
}
return nil
}
// KaspaEncode encodes the receiver to w using the kaspa protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgHeaders) KaspaEncode(w io.Writer, pver uint32) error {
// Limit to max block headers per message.
count := len(msg.Headers)
if count > MaxBlockHeadersPerMsg {
str := fmt.Sprintf("too many block headers for message "+
"[count %d, max %d]", count, MaxBlockHeadersPerMsg)
return messageError("MsgHeaders.KaspaEncode", str)
}
err := WriteVarInt(w, uint64(count))
if err != nil {
return err
}
for _, bh := range msg.Headers {
err := writeBlockHeader(w, pver, bh)
if err != nil {
return err
}
// The wire protocol encoding always includes a 0 for the number
// of transactions on header messages. This is really just an
// artifact of the way the original implementation serializes
// block headers, but it is required.
err = WriteVarInt(w, 0)
if err != nil {
return err
}
}
return nil
}
// Command returns the protocol command string for the message. This is part
// of the Message interface implementation.
func (msg *MsgHeaders) Command() string {
return CmdHeaders
}
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 {
// Num headers (varInt) + max allowed headers (header length + 1 byte
// for the number of transactions which is always 0).
return MaxVarIntPayload + ((MaxBlockHeaderPayload + 1) *
MaxBlockHeadersPerMsg)
}
// NewMsgHeaders returns a new kaspa headers message that conforms to the
// Message interface. See MsgHeaders for details.
func NewMsgHeaders() *MsgHeaders {
return &MsgHeaders{
Headers: make([]*BlockHeader, 0, MaxBlockHeadersPerMsg),
}
}

View File

@ -1,329 +0,0 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"bytes"
"github.com/pkg/errors"
"io"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/kaspanet/kaspad/util/daghash"
)
// TestHeaders tests the MsgHeaders API.
func TestHeaders(t *testing.T) {
pver := ProtocolVersion
// Ensure the command is expected value.
wantCmd := "headers"
msg := NewMsgHeaders()
if cmd := msg.Command(); cmd != wantCmd {
t.Errorf("NewMsgHeaders: wrong command - got %v want %v",
cmd, wantCmd)
}
// Ensure max payload is expected value for latest protocol version.
// Num headers (varInt) + max allowed headers (header length + 1 byte
// for the number of transactions which is always 0).
wantPayload := uint32(16564009)
maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload {
t.Errorf("MaxPayloadLength: wrong max payload length for "+
"protocol version %d - got %v, want %v", pver,
maxPayload, wantPayload)
}
// Ensure headers are added properly.
bh := &blockOne.Header
msg.AddBlockHeader(bh)
if !reflect.DeepEqual(msg.Headers[0], bh) {
t.Errorf("AddHeader: wrong header - got %v, want %v",
spew.Sdump(msg.Headers),
spew.Sdump(bh))
}
// Ensure adding more than the max allowed headers per message returns
// error.
var err error
for i := 0; i < MaxBlockHeadersPerMsg+1; i++ {
err = msg.AddBlockHeader(bh)
}
if reflect.TypeOf(err) != reflect.TypeOf(&MessageError{}) {
t.Errorf("AddBlockHeader: expected error on too many headers " +
"not received")
}
}
// TestHeadersWire tests the MsgHeaders wire encode and decode for various
// numbers of headers and protocol versions.
func TestHeadersWire(t *testing.T) {
hashes := []*daghash.Hash{mainnetGenesisHash, simnetGenesisHash}
hashMerkleRoot := blockOne.Header.HashMerkleRoot
acceptedIDMerkleRoot := blockOne.Header.AcceptedIDMerkleRoot
utxoCommitment := blockOne.Header.UTXOCommitment
bits := uint32(0x1d00ffff)
nonce := uint64(0x9962e301)
bh := NewBlockHeader(1, hashes, hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, bits, nonce)
bh.Version = blockOne.Header.Version
bh.Timestamp = blockOne.Header.Timestamp
// Empty headers message.
noHeaders := NewMsgHeaders()
noHeadersEncoded := []byte{
0x00, // Varint for number of headers
}
// Headers message with one header.
oneHeader := NewMsgHeaders()
oneHeader.AddBlockHeader(bh)
oneHeaderEncoded := []byte{
0x01, // VarInt for number of headers.
0x01, 0x00, 0x00, 0x00, // Version 1
0x02, // NumParentBlocks
0xdc, 0x5f, 0x5b, 0x5b, 0x1d, 0xc2, 0xa7, 0x25, // mainnetGenesisHash
0x49, 0xd5, 0x1d, 0x4d, 0xee, 0xd7, 0xa4, 0x8b,
0xaf, 0xd3, 0x14, 0x4b, 0x56, 0x78, 0x98, 0xb1,
0x8c, 0xfd, 0x9f, 0x69, 0xdd, 0xcf, 0xbb, 0x63,
0xf6, 0x7a, 0xd7, 0x69, 0x5d, 0x9b, 0x66, 0x2a, // simnetGenesisHash
0x72, 0xff, 0x3d, 0x8e, 0xdb, 0xbb, 0x2d, 0xe0,
0xbf, 0xa6, 0x7b, 0x13, 0x97, 0x4b, 0xb9, 0x91,
0x0d, 0x11, 0x6d, 0x5c, 0xbd, 0x86, 0x3e, 0x68,
0x4a, 0x5e, 0x1e, 0x4b, 0xaa, 0xb8, 0x9f, 0x3a, // MerkleRoot
0x32, 0x51, 0x8a, 0x88, 0xc3, 0x1b, 0xc8, 0x7f,
0x61, 0x8f, 0x76, 0x67, 0x3e, 0x2c, 0xc7, 0x7a,
0xb2, 0x12, 0x7b, 0x7a, 0xfd, 0xed, 0xa3, 0x3b,
0x09, 0x3B, 0xC7, 0xE3, 0x67, 0x11, 0x7B, 0x3C, // AcceptedIDMerkleRoot
0x30, 0xC1, 0xF8, 0xFD, 0xD0, 0xD9, 0x72, 0x87,
0x7F, 0x16, 0xC5, 0x96, 0x2E, 0x8B, 0xD9, 0x63,
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
0x10, 0x3B, 0xC7, 0xE3, 0x67, 0x11, 0x7B, 0x3C, // UTXOCommitment
0x30, 0xC1, 0xF8, 0xFD, 0xD0, 0xD9, 0x72, 0x87,
0x7F, 0x16, 0xC5, 0x96, 0x2E, 0x8B, 0xD9, 0x63,
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
0x61, 0xbc, 0x66, 0x49, 0x00, 0x00, 0x00, 0x00, // Timestamp
0xff, 0xff, 0x00, 0x1d, // Bits
0x01, 0xe3, 0x62, 0x99, 0x00, 0x00, 0x00, 0x00, // Fake Nonce. TODO: (Ori) Replace to a real nonce
0x00, // TxnCount (0 for headers message)
}
tests := []struct {
in *MsgHeaders // Message to encode
out *MsgHeaders // Expected decoded message
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
}{
// Latest protocol version with no headers.
{
noHeaders,
noHeaders,
noHeadersEncoded,
ProtocolVersion,
},
// Latest protocol version with one header.
{
oneHeader,
oneHeader,
oneHeaderEncoded,
ProtocolVersion,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode the message to wire format.
var buf bytes.Buffer
err := test.in.KaspaEncode(&buf, test.pver)
if err != nil {
t.Errorf("KaspaEncode #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("KaspaEncode #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Decode the message from wire format.
var msg MsgHeaders
rbuf := bytes.NewReader(test.buf)
err = msg.KaspaDecode(rbuf, test.pver)
if err != nil {
t.Errorf("KaspaDecode #%d error %v", i, err)
continue
}
if !reflect.DeepEqual(&msg, test.out) {
t.Errorf("KaspaDecode #%d\n got: %s want: %s", i,
spew.Sdump(&msg), spew.Sdump(test.out))
continue
}
}
}
// TestHeadersWireErrors performs negative tests against wire encode and decode
// of MsgHeaders to confirm error paths work correctly.
func TestHeadersWireErrors(t *testing.T) {
pver := ProtocolVersion
wireErr := &MessageError{}
hashes := []*daghash.Hash{mainnetGenesisHash, simnetGenesisHash}
hashMerkleRoot := blockOne.Header.HashMerkleRoot
acceptedIDMerkleRoot := blockOne.Header.AcceptedIDMerkleRoot
utxoCommitment := blockOne.Header.UTXOCommitment
bits := uint32(0x1d00ffff)
nonce := uint64(0x9962e301)
bh := NewBlockHeader(1, hashes, hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, bits, nonce)
bh.Version = blockOne.Header.Version
bh.Timestamp = blockOne.Header.Timestamp
// Headers message with one header.
oneHeader := NewMsgHeaders()
oneHeader.AddBlockHeader(bh)
oneHeaderEncoded := []byte{
0x01, // VarInt for number of headers.
0x01, 0x00, 0x00, 0x00, // Version 1
0x02, // NumParentBlocks
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, // mainnetGenesisHash
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f,
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c,
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf6, 0x7a, 0xd7, 0x69, 0x5d, 0x9b, 0x66, 0x2a, // simnetGenesisHash
0x72, 0xff, 0x3d, 0x8e, 0xdb, 0xbb, 0x2d, 0xe0,
0xbf, 0xa6, 0x7b, 0x13, 0x97, 0x4b, 0xb9, 0x91,
0x0d, 0x11, 0x6d, 0x5c, 0xbd, 0x86, 0x3e, 0x68,
0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, // MerkleRoot
0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61,
0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32,
0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a,
0x09, 0x3B, 0xC7, 0xE3, 0x67, 0x11, 0x7B, 0x3C, // AcceptedIDMerkleRoot
0x30, 0xC1, 0xF8, 0xFD, 0xD0, 0xD9, 0x72, 0x87,
0x7F, 0x16, 0xC5, 0x96, 0x2E, 0x8B, 0xD9, 0x63,
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
0x10, 0x3B, 0xC7, 0xE3, 0x67, 0x11, 0x7B, 0x3C, // UTXOCommitment
0x30, 0xC1, 0xF8, 0xFD, 0xD0, 0xD9, 0x72, 0x87,
0x7F, 0x16, 0xC5, 0x96, 0x2E, 0x8B, 0xD9, 0x63,
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
0x61, 0xbc, 0x66, 0x49, 0x00, 0x00, 0x00, 0x00, // Timestamp
0xff, 0xff, 0x00, 0x1d, // Bits
0x01, 0xe3, 0x62, 0x99, 0x00, 0x00, 0x00, 0x00, // Fake Nonce. TODO: (Ori) Replace to a real nonce
0x00, // TxnCount (0 for headers message)
}
// Message that forces an error by having more than the max allowed
// headers.
maxHeaders := NewMsgHeaders()
for i := 0; i < MaxBlockHeadersPerMsg; i++ {
maxHeaders.AddBlockHeader(bh)
}
maxHeaders.Headers = append(maxHeaders.Headers, bh)
maxHeadersEncoded := []byte{
0xfd, 0xd1, 0x07, // Varint for number of addresses (2001)7D1
}
// Intentionally invalid block header that has a transaction count used
// to force errors.
bhTrans := NewBlockHeader(1, hashes, hashMerkleRoot, acceptedIDMerkleRoot, utxoCommitment, bits, nonce)
bhTrans.Version = blockOne.Header.Version
bhTrans.Timestamp = blockOne.Header.Timestamp
transHeader := NewMsgHeaders()
transHeader.AddBlockHeader(bhTrans)
transHeaderEncoded := []byte{
0x01, // VarInt for number of headers.
0x01, 0x00, 0x00, 0x00, // Version 1
0x02, // NumParentBlocks
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, // mainnetGenesisHash
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f,
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c,
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf6, 0x7a, 0xd7, 0x69, 0x5d, 0x9b, 0x66, 0x2a, // simnetGenesisHash
0x72, 0xff, 0x3d, 0x8e, 0xdb, 0xbb, 0x2d, 0xe0,
0xbf, 0xa6, 0x7b, 0x13, 0x97, 0x4b, 0xb9, 0x91,
0x0d, 0x11, 0x6d, 0x5c, 0xbd, 0x86, 0x3e, 0x68,
0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, // HashMerkleRoot
0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61,
0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32,
0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a,
0x09, 0x3B, 0xC7, 0xE3, 0x67, 0x11, 0x7B, 0x3C, // AcceptedIDMerkleRoot
0x30, 0xC1, 0xF8, 0xFD, 0xD0, 0xD9, 0x72, 0x87,
0x7F, 0x16, 0xC5, 0x96, 0x2E, 0x8B, 0xD9, 0x63,
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
0x10, 0x3B, 0xC7, 0xE3, 0x67, 0x11, 0x7B, 0x3C, // UTXOCommitment
0x30, 0xC1, 0xF8, 0xFD, 0xD0, 0xD9, 0x72, 0x87,
0x7F, 0x16, 0xC5, 0x96, 0x2E, 0x8B, 0xD9, 0x63,
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
0x61, 0xbc, 0x66, 0x49, 0x00, 0x00, 0x00, 0x00, // Timestamp
0xff, 0xff, 0x00, 0x1d, // Bits
0x01, 0xe3, 0x62, 0x99, 0x00, 0x00, 0x00, 0x00, // Fake Nonce. TODO: (Ori) Replace to a real nonce
0x01, // TxnCount (should be 0 for headers message, but 1 to force error)
}
tests := []struct {
in *MsgHeaders // Value to encode
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
max int // Max size of fixed buffer to induce errors
writeErr error // Expected write error
readErr error // Expected read error
}{
// Latest protocol version with intentional read/write errors.
// Force error in header count.
{oneHeader, oneHeaderEncoded, pver, 0, io.ErrShortWrite, io.EOF},
// Force error in block header.
{oneHeader, oneHeaderEncoded, pver, 5, io.ErrShortWrite, io.EOF},
// Force error with greater than max headers.
{maxHeaders, maxHeadersEncoded, pver, 3, wireErr, wireErr},
// Force error with number of transactions.
{transHeader, transHeaderEncoded, pver, 178, io.ErrShortWrite, io.EOF},
// Force error with included transactions.
{transHeader, transHeaderEncoded, pver, len(transHeaderEncoded), nil, wireErr},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
w := newFixedWriter(test.max)
err := test.in.KaspaEncode(w, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
t.Errorf("KaspaEncode #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// For errors which are not of type MessageError, check them for
// equality.
if msgErr := &(MessageError{}); !errors.As(err, &msgErr) {
if err != test.writeErr {
t.Errorf("KaspaEncode #%d wrong error got: %v, "+
"want: %v", i, err, test.writeErr)
continue
}
}
// Decode from wire format.
var msg MsgHeaders
r := newFixedReader(test.max, test.buf)
err = msg.KaspaDecode(r, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
t.Errorf("KaspaDecode #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
// For errors which are not of type MessageError, check them for
// equality.
if msgErr := &(MessageError{}); !errors.As(err, &msgErr) {
if err != test.readErr {
t.Errorf("KaspaDecode #%d wrong error got: %v, "+
"want: %v", i, err, test.readErr)
continue
}
}
}
}

View File

@ -1,46 +0,0 @@
// Copyright (c) 2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"io"
)
// MsgSendHeaders implements the Message interface and represents a kaspa
// sendheaders message. It is used to request the peer send block headers
// rather than inventory vectors.
//
// This message has no payload.
type MsgSendHeaders struct{}
// KaspaDecode decodes r using the kaspa protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgSendHeaders) KaspaDecode(r io.Reader, pver uint32) error {
return nil
}
// KaspaEncode encodes the receiver to w using the kaspa protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgSendHeaders) KaspaEncode(w io.Writer, pver uint32) error {
return nil
}
// Command returns the protocol command string for the message. This is part
// of the Message interface implementation.
func (msg *MsgSendHeaders) Command() string {
return CmdSendHeaders
}
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgSendHeaders) MaxPayloadLength(pver uint32) uint32 {
return 0
}
// NewMsgSendHeaders returns a new kaspa sendheaders message that conforms to
// the Message interface. See MsgSendHeaders for details.
func NewMsgSendHeaders() *MsgSendHeaders {
return &MsgSendHeaders{}
}

View File

@ -1,118 +0,0 @@
// Copyright (c) 2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"bytes"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
)
// TestSendHeaders tests the MsgSendHeaders API against the latest protocol
// version.
func TestSendHeaders(t *testing.T) {
pver := ProtocolVersion
// Ensure the command is expected value.
wantCmd := "sendheaders"
msg := NewMsgSendHeaders()
if cmd := msg.Command(); cmd != wantCmd {
t.Errorf("NewMsgSendHeaders: wrong command - got %v want %v",
cmd, wantCmd)
}
// Ensure max payload is expected value.
wantPayload := uint32(0)
maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload {
t.Errorf("MaxPayloadLength: wrong max payload length for "+
"protocol version %d - got %v, want %v", pver,
maxPayload, wantPayload)
}
// Test encode with latest protocol version.
var buf bytes.Buffer
err := msg.KaspaEncode(&buf, pver)
if err != nil {
t.Errorf("encode of MsgSendHeaders failed %v err <%v>", msg,
err)
}
// Test decode with latest protocol version.
readmsg := NewMsgSendHeaders()
err = readmsg.KaspaDecode(&buf, pver)
if err != nil {
t.Errorf("decode of MsgSendHeaders failed [%v] err <%v>", buf,
err)
}
}
// TestSendHeadersCrossProtocol tests the MsgSendHeaders API when encoding with
// the latest protocol version and decoding with SendHeadersVersion.
func TestSendHeadersCrossProtocol(t *testing.T) {
msg := NewMsgSendHeaders()
// Encode with latest protocol version.
var buf bytes.Buffer
err := msg.KaspaEncode(&buf, ProtocolVersion)
if err != nil {
t.Errorf("encode of MsgSendHeaders failed %v err <%v>", msg,
err)
}
}
// TestSendHeadersWire tests the MsgSendHeaders wire encode and decode for
// various protocol versions.
func TestSendHeadersWire(t *testing.T) {
msgSendHeaders := NewMsgSendHeaders()
msgSendHeadersEncoded := []byte{}
tests := []struct {
in *MsgSendHeaders // Message to encode
out *MsgSendHeaders // Expected decoded message
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
}{
// Latest protocol version.
{
msgSendHeaders,
msgSendHeaders,
msgSendHeadersEncoded,
ProtocolVersion,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode the message to wire format.
var buf bytes.Buffer
err := test.in.KaspaEncode(&buf, test.pver)
if err != nil {
t.Errorf("KaspaEncode #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("KaspaEncode #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Decode the message from wire format.
var msg MsgSendHeaders
rbuf := bytes.NewReader(test.buf)
err = msg.KaspaDecode(rbuf, test.pver)
if err != nil {
t.Errorf("KaspaDecode #%d error %v", i, err)
continue
}
if !reflect.DeepEqual(&msg, test.out) {
t.Errorf("KaspaDecode #%d\n got: %s want: %s", i,
spew.Sdump(msg), spew.Sdump(test.out))
continue
}
}
}