2
0
mirror of https://github.com/kaspanet/kaspad.git synced 2025-03-30 15:08:33 +00:00
Ori Newman 62d14bf2bd [NOD-16] implement initial sync first version ()
* [NOD-58] Replace lastBlock with selected tip in version message ()

* [NOD-58] Replace lastBlock with selected tip in version message

* [NOD-58] Fix typo in comment

* [NOD-58] Add mutex to SelectedTipHash

* [NOD-58] Remove redundant comment

* [NOD-58] Remove wantStartingHeight from peerStats

* [NOD-58] Remove lock from SelectedTipHash

* Nod 53 change getheaders message to handle new block locator ()

* [NOD-53] Change getheaders message to handle the new block locator mechanism

* [NOD-53] Use heap in locateHeaders

* [NOD-53] Create a constructor for each heap direction

* [NOD-57] Check if a node is synced only by timestamps ()

* [NOD-60] implement isSyncCandidate ()

* [NOD-60] Implement isSyncCandidate

* [NOD-60] Fix typo

* [NOD-65] Fix netsync related tests and remove fields optionality from… ()

* [NOD-65] Fix netsync related tests and remove fields optionality from msgversion

* [NOD-65] gofmt rpcserver.go

* [NOD-65] add missing test for verRelayTxFalse

* [NOD-62] Change getblocks message to handle the new block locator mechanism ()

* [NOD-62] Change getblocks message to handle the new block locator mechanism

* [NOD-62] Add locateBlockNodes function

* [NOD-68] Adjust orphan parents requesting for a DAG ()

* [NOD-68] Adjust orphan parents requesting for a DAG

* [NOD-68] add sendInvsFromRequestedQueue and trigger it when requested blocks slice is empty, or immediatly if we're not in sync mode

* [NOD-68] Prevent duplicates from entering to state.requestQueue and add wrapping locks to addBlocksToRequestQueue

* [NOD-68] Fix Lock -> Unlock in sendInvsFromRequestedQueue

* [NOD-74] Starts syncing again when the current sync peer is done ()

* [NOD-74] Starts syncing again when the current sync peer is done

* [NOD-74] Unlock mtx before netsync is restarted

* [NOD-74] Fix name isSyncPeerFree -> isWaitingForBlocks

* [NOD-75] fixing netsync bugs ()

* [NOD-74] Starts syncing again when the current sync peer is done

* [NOD-74] Unlock mtx before netsync is restarted

* [NOD-75] Fixing netsync bugs

* [NOD-80] Request block data from block propagation just after you are… ()

* [NOD-80] Request block data from block propagation just after you are current

* [NOD-80] Fix adding to both queues in addInvToRequestQueue

* [NOD-81] Start to mine on top of genesis iff all peers selected tip is genesis ()

* [NOD-81] Start to mine on top of genesis only if all of your peers' selected tip is genesis

* [NOD-81] Explain forAllPeers/forAllOutboundPeers shouldContinue behaviour in comments

* [NOD-81] Add forAllInboundPeers and add return values for forAllPeers/forAllOutboundPeers/forAllInboundPeers functions

* [NOD-16] Add pushSet to the BlockHeap type

* [NOD-16] Fixed syntax error
2019-03-31 16:47:28 +03:00

265 lines
7.2 KiB
Go

// 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"
"fmt"
"io"
"strings"
"time"
"github.com/daglabs/btcd/dagconfig/daghash"
"github.com/daglabs/btcd/util/subnetworkid"
)
// MaxUserAgentLen is the maximum allowed length for the user agent field in a
// version message (MsgVersion).
const MaxUserAgentLen = 256
// DefaultUserAgent for wire in the stack
const DefaultUserAgent = "/btcwire:0.5.0/"
// MsgVersion implements the Message interface and represents a bitcoin version
// message. It is used for a peer to advertise itself as soon as an outbound
// connection is made. The remote peer then uses this information along with
// its own to negotiate. The remote peer must then respond with a version
// message of its own containing the negotiated values followed by a verack
// message (MsgVerAck). This exchange must take place before any further
// communication is allowed to proceed.
type MsgVersion struct {
// Version of the protocol the node is using.
ProtocolVersion int32
// Bitfield which identifies the enabled services.
Services ServiceFlag
// Time the message was generated. This is encoded as an int64 on the wire.
Timestamp time.Time
// Address of the remote peer.
AddrYou NetAddress
// Address of the local peer.
AddrMe NetAddress
// Unique value associated with message that is used to detect self
// connections.
Nonce uint64
// The user agent that generated messsage. This is a encoded as a varString
// on the wire. This has a max length of MaxUserAgentLen.
UserAgent string
// The selected tip of the generator of the version message.
SelectedTip *daghash.Hash
// Don't announce transactions to peer.
DisableRelayTx bool
// The subnetwork of the generator of the version message.
SubnetworkID subnetworkid.SubnetworkID
}
// HasService returns whether the specified service is supported by the peer
// that generated the message.
func (msg *MsgVersion) HasService(service ServiceFlag) bool {
return msg.Services&service == service
}
// AddService adds service as a supported service by the peer generating the
// message.
func (msg *MsgVersion) AddService(service ServiceFlag) {
msg.Services |= service
}
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
// The version message is special in that the protocol version hasn't been
// negotiated yet. As a result, the pver field is ignored and any fields which
// are added in new versions are optional. This also mean that r must be a
// *bytes.Buffer so the number of remaining bytes can be ascertained.
//
// This is part of the Message interface implementation.
func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error {
buf, ok := r.(*bytes.Buffer)
if !ok {
return fmt.Errorf("MsgVersion.BtcDecode reader is not a " +
"*bytes.Buffer")
}
err := readElements(buf, &msg.ProtocolVersion, &msg.Services,
(*int64Time)(&msg.Timestamp))
if err != nil {
return err
}
err = readElement(buf, &msg.SubnetworkID)
if err != nil {
return err
}
err = readNetAddress(buf, pver, &msg.AddrYou, false)
if err != nil {
return err
}
err = readNetAddress(buf, pver, &msg.AddrMe, false)
if err != nil {
return err
}
err = readElement(buf, &msg.Nonce)
if err != nil {
return err
}
userAgent, err := ReadVarString(buf, pver)
if err != nil {
return err
}
err = validateUserAgent(userAgent)
if err != nil {
return err
}
msg.UserAgent = userAgent
msg.SelectedTip = &daghash.Hash{}
err = readElement(buf, msg.SelectedTip)
if err != nil {
return err
}
var relayTx bool
err = readElement(r, &relayTx)
if err != nil {
return err
}
msg.DisableRelayTx = !relayTx
return nil
}
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error {
err := validateUserAgent(msg.UserAgent)
if err != nil {
return err
}
err = writeElements(w, msg.ProtocolVersion, msg.Services,
msg.Timestamp.Unix())
if err != nil {
return err
}
err = writeElement(w, msg.SubnetworkID)
if err != nil {
return err
}
err = writeNetAddress(w, pver, &msg.AddrYou, false)
if err != nil {
return err
}
err = writeNetAddress(w, pver, &msg.AddrMe, false)
if err != nil {
return err
}
err = writeElement(w, msg.Nonce)
if err != nil {
return err
}
err = WriteVarString(w, pver, msg.UserAgent)
if err != nil {
return err
}
err = writeElement(w, msg.SelectedTip)
if err != nil {
return err
}
// The wire encoding for the field is true when transactions should be
// relayed, so reverse it from the DisableRelayTx field.
err = writeElement(w, !msg.DisableRelayTx)
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 *MsgVersion) Command() string {
return CmdVersion
}
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 {
// XXX: <= 106 different
// Protocol version 4 bytes + services 8 bytes + timestamp 16 bytes +
// remote and local net addresses + nonce 8 bytes + length of user
// agent (varInt) + max allowed useragent length + last block 4 bytes +
// relay transactions flag 1 byte.
return 33 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload +
MaxUserAgentLen
}
// NewMsgVersion returns a new bitcoin version message that conforms to the
// Message interface using the passed parameters and defaults for the remaining
// fields.
func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64,
selectedTip *daghash.Hash, subnetworkID *subnetworkid.SubnetworkID) *MsgVersion {
// Limit the timestamp to one second precision since the protocol
// doesn't support better.
return &MsgVersion{
ProtocolVersion: int32(ProtocolVersion),
Services: 0,
Timestamp: time.Unix(time.Now().Unix(), 0),
AddrYou: *you,
AddrMe: *me,
Nonce: nonce,
UserAgent: DefaultUserAgent,
SelectedTip: selectedTip,
DisableRelayTx: false,
SubnetworkID: *subnetworkID,
}
}
// validateUserAgent checks userAgent length against MaxUserAgentLen
func validateUserAgent(userAgent string) error {
if len(userAgent) > MaxUserAgentLen {
str := fmt.Sprintf("user agent too long [len %d, max %d]",
len(userAgent), MaxUserAgentLen)
return messageError("MsgVersion", str)
}
return nil
}
// AddUserAgent adds a user agent to the user agent string for the version
// message. The version string is not defined to any strict format, although
// it is recommended to use the form "major.minor.revision" e.g. "2.6.41".
func (msg *MsgVersion) AddUserAgent(name string, version string,
comments ...string) error {
newUserAgent := fmt.Sprintf("%s:%s", name, version)
if len(comments) != 0 {
newUserAgent = fmt.Sprintf("%s(%s)", newUserAgent,
strings.Join(comments, "; "))
}
newUserAgent = fmt.Sprintf("%s%s/", msg.UserAgent, newUserAgent)
err := validateUserAgent(newUserAgent)
if err != nil {
return err
}
msg.UserAgent = newUserAgent
return nil
}