mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-09-15 22:10:12 +00:00
Compare commits
2 Commits
master
...
v0.7.2-rc1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b88e34fd84 | ||
![]() |
689098082f |
@ -101,6 +101,8 @@ const (
|
|||||||
CmdGetMempoolEntriesResponseMessage
|
CmdGetMempoolEntriesResponseMessage
|
||||||
CmdShutDownRequestMessage
|
CmdShutDownRequestMessage
|
||||||
CmdShutDownResponseMessage
|
CmdShutDownResponseMessage
|
||||||
|
CmdGetHeadersRequestMessage
|
||||||
|
CmdGetHeadersResponseMessage
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
// ProtocolMessageCommandToString maps all MessageCommands to their string representation
|
||||||
@ -176,6 +178,8 @@ var RPCMessageCommandToString = map[MessageCommand]string{
|
|||||||
CmdFinalityConflictResolvedNotificationMessage: "FinalityConflictResolvedNotification",
|
CmdFinalityConflictResolvedNotificationMessage: "FinalityConflictResolvedNotification",
|
||||||
CmdGetMempoolEntriesRequestMessage: "GetMempoolEntriesRequestMessage",
|
CmdGetMempoolEntriesRequestMessage: "GetMempoolEntriesRequestMessage",
|
||||||
CmdGetMempoolEntriesResponseMessage: "GetMempoolEntriesResponseMessage",
|
CmdGetMempoolEntriesResponseMessage: "GetMempoolEntriesResponseMessage",
|
||||||
|
CmdGetHeadersRequestMessage: "GetHeadersRequest",
|
||||||
|
CmdGetHeadersResponseMessage: "GetHeadersResponse",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is an interface that describes a kaspa message. A type that
|
// Message is an interface that describes a kaspa message. A type that
|
||||||
|
@ -18,7 +18,7 @@ func TestRequstIBDBlocks(t *testing.T) {
|
|||||||
t.Errorf("NewHashFromStr: %v", err)
|
t.Errorf("NewHashFromStr: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
|
hashStr = "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
|
||||||
highHash, err := daghash.NewHashFromStr(hashStr)
|
highHash, err := daghash.NewHashFromStr(hashStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("NewHashFromStr: %v", err)
|
t.Errorf("NewHashFromStr: %v", err)
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
func TestTx(t *testing.T) {
|
func TestTx(t *testing.T) {
|
||||||
pver := ProtocolVersion
|
pver := ProtocolVersion
|
||||||
|
|
||||||
txIDStr := "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
|
txIDStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
|
||||||
txID, err := daghash.NewTxIDFromStr(txIDStr)
|
txID, err := daghash.NewTxIDFromStr(txIDStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("NewTxIDFromStr: %v", err)
|
t.Errorf("NewTxIDFromStr: %v", err)
|
||||||
|
45
app/appmessage/rpc_get_headers.go
Normal file
45
app/appmessage/rpc_get_headers.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package appmessage
|
||||||
|
|
||||||
|
// GetHeadersRequestMessage is an appmessage corresponding to
|
||||||
|
// its respective RPC message
|
||||||
|
type GetHeadersRequestMessage struct {
|
||||||
|
baseMessage
|
||||||
|
StartHash string
|
||||||
|
Limit uint64
|
||||||
|
IsAscending bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command returns the protocol command string for the message
|
||||||
|
func (msg *GetHeadersRequestMessage) Command() MessageCommand {
|
||||||
|
return CmdGetHeadersRequestMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetHeadersRequestMessage returns a instance of the message
|
||||||
|
func NewGetHeadersRequestMessage(startHash string, limit uint64, isAscending bool) *GetHeadersRequestMessage {
|
||||||
|
return &GetHeadersRequestMessage{
|
||||||
|
StartHash: startHash,
|
||||||
|
Limit: limit,
|
||||||
|
IsAscending: isAscending,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeadersResponseMessage is an appmessage corresponding to
|
||||||
|
// its respective RPC message
|
||||||
|
type GetHeadersResponseMessage struct {
|
||||||
|
baseMessage
|
||||||
|
Headers []string
|
||||||
|
|
||||||
|
Error *RPCError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command returns the protocol command string for the message
|
||||||
|
func (msg *GetHeadersResponseMessage) Command() MessageCommand {
|
||||||
|
return CmdGetHeadersResponseMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetHeadersResponseMessage returns a instance of the message
|
||||||
|
func NewGetHeadersResponseMessage(headers []string) *GetHeadersResponseMessage {
|
||||||
|
return &GetHeadersResponseMessage{
|
||||||
|
Headers: headers,
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,8 @@ func NewGetPeerAddressesRequestMessage() *GetPeerAddressesRequestMessage {
|
|||||||
// its respective RPC message
|
// its respective RPC message
|
||||||
type GetPeerAddressesResponseMessage struct {
|
type GetPeerAddressesResponseMessage struct {
|
||||||
baseMessage
|
baseMessage
|
||||||
Addresses []*GetPeerAddressesKnownAddressMessage
|
Addresses []*GetPeerAddressesKnownAddressMessage
|
||||||
|
BannedAddresses []*GetPeerAddressesKnownAddressMessage
|
||||||
|
|
||||||
Error *RPCError
|
Error *RPCError
|
||||||
}
|
}
|
||||||
@ -31,9 +32,10 @@ func (msg *GetPeerAddressesResponseMessage) Command() MessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGetPeerAddressesResponseMessage returns a instance of the message
|
// NewGetPeerAddressesResponseMessage returns a instance of the message
|
||||||
func NewGetPeerAddressesResponseMessage(addresses []*GetPeerAddressesKnownAddressMessage) *GetPeerAddressesResponseMessage {
|
func NewGetPeerAddressesResponseMessage(addresses []*GetPeerAddressesKnownAddressMessage, bannedAddresses []*GetPeerAddressesKnownAddressMessage) *GetPeerAddressesResponseMessage {
|
||||||
return &GetPeerAddressesResponseMessage{
|
return &GetPeerAddressesResponseMessage{
|
||||||
Addresses: addresses,
|
Addresses: addresses,
|
||||||
|
BannedAddresses: bannedAddresses,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,11 +72,6 @@ func (a *ComponentManager) Stop() {
|
|||||||
log.Errorf("Error stopping the net adapter: %+v", err)
|
log.Errorf("Error stopping the net adapter: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.addressManager.Stop()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error stopping address manager: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,18 +94,22 @@ func NewComponentManager(cfg *config.Config, databaseContext *dbaccess.DatabaseC
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
addressManager, err := addressmanager.New(cfg, databaseContext)
|
|
||||||
|
addressManager, err := addressmanager.New(addressmanager.NewConfig(cfg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionManager, err := connmanager.New(cfg, netAdapter, addressManager)
|
connectionManager, err := connmanager.New(cfg, netAdapter, addressManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
protocolManager, err := protocol.NewManager(cfg, dag, netAdapter, addressManager, txMempool, connectionManager)
|
protocolManager, err := protocol.NewManager(cfg, dag, netAdapter, addressManager, txMempool, connectionManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcManager := setupRPC(cfg, txMempool, dag, sigCache, netAdapter, protocolManager, connectionManager, addressManager, acceptanceIndex, interrupt)
|
rpcManager := setupRPC(cfg, txMempool, dag, sigCache, netAdapter, protocolManager, connectionManager, addressManager, acceptanceIndex, interrupt)
|
||||||
|
|
||||||
return &ComponentManager{
|
return &ComponentManager{
|
||||||
@ -187,14 +186,14 @@ func (a *ComponentManager) maybeSeedFromDNS() {
|
|||||||
// Kaspad uses a lookup of the dns seeder here. Since seeder returns
|
// Kaspad uses a lookup of the dns seeder here. Since seeder returns
|
||||||
// IPs of nodes and not its own IP, we can not know real IP of
|
// IPs of nodes and not its own IP, we can not know real IP of
|
||||||
// source. So we'll take first returned address as source.
|
// source. So we'll take first returned address as source.
|
||||||
a.addressManager.AddAddresses(addresses, addresses[0], nil)
|
a.addressManager.AddAddresses(addresses...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.cfg.GRPCSeed != "" {
|
if a.cfg.GRPCSeed != "" {
|
||||||
dnsseed.SeedFromGRPC(a.cfg.NetParams(), a.cfg.GRPCSeed, appmessage.SFNodeNetwork, false, nil,
|
dnsseed.SeedFromGRPC(a.cfg.NetParams(), a.cfg.GRPCSeed, appmessage.SFNodeNetwork, false, nil,
|
||||||
func(addresses []*appmessage.NetAddress) {
|
func(addresses []*appmessage.NetAddress) {
|
||||||
a.addressManager.AddAddresses(addresses, addresses[0], nil)
|
a.addressManager.AddAddresses(addresses...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,6 @@ type ReceiveAddressesContext interface {
|
|||||||
func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Route, outgoingRoute *router.Route,
|
func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Route, outgoingRoute *router.Route,
|
||||||
peer *peerpkg.Peer) error {
|
peer *peerpkg.Peer) error {
|
||||||
|
|
||||||
if !context.AddressManager().NeedMoreAddresses() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
subnetworkID := peer.SubnetworkID()
|
subnetworkID := peer.SubnetworkID()
|
||||||
msgGetAddresses := appmessage.NewMsgRequestAddresses(false, subnetworkID)
|
msgGetAddresses := appmessage.NewMsgRequestAddresses(false, subnetworkID)
|
||||||
err := outgoingRoute.Enqueue(msgGetAddresses)
|
err := outgoingRoute.Enqueue(msgGetAddresses)
|
||||||
@ -51,7 +47,6 @@ func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Rou
|
|||||||
context.Config().SubnetworkID, msgAddresses.Command(), msgAddresses.SubnetworkID)
|
context.Config().SubnetworkID, msgAddresses.Command(), msgAddresses.SubnetworkID)
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceAddress := peer.Connection().NetAddress()
|
context.AddressManager().AddAddresses(msgAddresses.AddrList...)
|
||||||
context.AddressManager().AddAddresses(msgAddresses.AddrList, sourceAddress, msgAddresses.SubnetworkID)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package addressexchange
|
package addressexchange
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
"math/rand"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SendAddressesContext is the interface for the context needed for the SendAddresses flow.
|
// SendAddressesContext is the interface for the context needed for the SendAddresses flow.
|
||||||
@ -20,8 +21,7 @@ func SendAddresses(context SendAddressesContext, incomingRoute *router.Route, ou
|
|||||||
}
|
}
|
||||||
|
|
||||||
msgGetAddresses := message.(*appmessage.MsgRequestAddresses)
|
msgGetAddresses := message.(*appmessage.MsgRequestAddresses)
|
||||||
addresses := context.AddressManager().AddressCache(msgGetAddresses.IncludeAllSubnetworks,
|
addresses := context.AddressManager().Addresses()
|
||||||
msgGetAddresses.SubnetworkID)
|
|
||||||
msgAddresses := appmessage.NewMsgAddresses(msgGetAddresses.IncludeAllSubnetworks, msgGetAddresses.SubnetworkID)
|
msgAddresses := appmessage.NewMsgAddresses(msgGetAddresses.IncludeAllSubnetworks, msgGetAddresses.SubnetworkID)
|
||||||
err = msgAddresses.AddAddresses(shuffleAddresses(addresses)...)
|
err = msgAddresses.AddAddresses(shuffleAddresses(addresses)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -85,9 +85,7 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
|
|||||||
}
|
}
|
||||||
|
|
||||||
if peerAddress != nil {
|
if peerAddress != nil {
|
||||||
subnetworkID := peer.SubnetworkID()
|
context.AddressManager().AddAddresses(peerAddress)
|
||||||
context.AddressManager().AddAddress(peerAddress, peerAddress, subnetworkID)
|
|
||||||
context.AddressManager().Good(peerAddress, subnetworkID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.StartIBDIfRequired()
|
context.StartIBDIfRequired()
|
||||||
|
@ -50,7 +50,7 @@ func (flow *sendVersionFlow) start() error {
|
|||||||
subnetworkID := flow.Config().SubnetworkID
|
subnetworkID := flow.Config().SubnetworkID
|
||||||
|
|
||||||
// Version message.
|
// Version message.
|
||||||
localAddress := flow.AddressManager().GetBestLocalAddress(flow.peer.Connection().NetAddress())
|
localAddress := flow.AddressManager().BestLocalAddress(flow.peer.Connection().NetAddress())
|
||||||
msg := appmessage.NewMsgVersion(localAddress, flow.NetAdapter().ID(),
|
msg := appmessage.NewMsgVersion(localAddress, flow.NetAdapter().ID(),
|
||||||
flow.Config().ActiveNetParams.Name, selectedTipHash, subnetworkID)
|
flow.Config().ActiveNetParams.Name, selectedTipHash, subnetworkID)
|
||||||
msg.AddUserAgent(userAgentName, userAgentVersion, flow.Config().UserAgentComments...)
|
msg.AddUserAgent(userAgentName, userAgentVersion, flow.Config().UserAgentComments...)
|
||||||
|
@ -32,7 +32,8 @@ var handlers = map[appmessage.MessageCommand]handler{
|
|||||||
appmessage.CmdResolveFinalityConflictRequestMessage: rpchandlers.HandleResolveFinalityConflict,
|
appmessage.CmdResolveFinalityConflictRequestMessage: rpchandlers.HandleResolveFinalityConflict,
|
||||||
appmessage.CmdNotifyFinalityConflictsRequestMessage: rpchandlers.HandleNotifyFinalityConflicts,
|
appmessage.CmdNotifyFinalityConflictsRequestMessage: rpchandlers.HandleNotifyFinalityConflicts,
|
||||||
appmessage.CmdGetMempoolEntriesRequestMessage: rpchandlers.HandleGetMempoolEntries,
|
appmessage.CmdGetMempoolEntriesRequestMessage: rpchandlers.HandleGetMempoolEntries,
|
||||||
appmessage.CmdShutDownRequestMessage: rpchandlers.HandleShutDown,
|
appmessage.CmdShutDownRequestMessage: rpchandlers.HandleGetMempoolEntries,
|
||||||
|
appmessage.CmdGetHeadersRequestMessage: rpchandlers.HandleGetHeaders,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) {
|
func (m *Manager) routerInitializer(router *router.Router, netConnection *netadapter.NetConnection) {
|
||||||
|
52
app/rpc/rpchandlers/get_headers.go
Normal file
52
app/rpc/rpchandlers/get_headers.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package rpchandlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
|
"github.com/kaspanet/kaspad/util/daghash"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleGetHeaders handles the respectively named RPC command
|
||||||
|
func HandleGetHeaders(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
||||||
|
getHeadersRequest := request.(*appmessage.GetHeadersRequestMessage)
|
||||||
|
dag := context.DAG
|
||||||
|
|
||||||
|
var startHash *daghash.Hash
|
||||||
|
if getHeadersRequest.StartHash != "" {
|
||||||
|
var err error
|
||||||
|
startHash, err = daghash.NewHashFromStr(getHeadersRequest.StartHash)
|
||||||
|
if err != nil {
|
||||||
|
errorMessage := &appmessage.GetHeadersResponseMessage{}
|
||||||
|
errorMessage.Error = appmessage.RPCErrorf("Start hash could not be parsed: %s", err)
|
||||||
|
return errorMessage, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getHeadersDefaultLimit uint64 = 2000
|
||||||
|
limit := getHeadersDefaultLimit
|
||||||
|
if getHeadersRequest.Limit != 0 {
|
||||||
|
limit = getHeadersRequest.Limit
|
||||||
|
}
|
||||||
|
|
||||||
|
headers, err := dag.GetHeaders(startHash, limit, getHeadersRequest.IsAscending)
|
||||||
|
if err != nil {
|
||||||
|
errorMessage := &appmessage.GetHeadersResponseMessage{}
|
||||||
|
errorMessage.Error = appmessage.RPCErrorf("Error getting the headers: %s", err)
|
||||||
|
return errorMessage, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
headersHex := make([]string, len(headers))
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i, header := range headers {
|
||||||
|
err := header.Serialize(&buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
headersHex[i] = hex.EncodeToString(buf.Bytes())
|
||||||
|
buf.Reset()
|
||||||
|
}
|
||||||
|
return appmessage.NewGetHeadersResponseMessage(headersHex), nil
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
package rpchandlers
|
package rpchandlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||||
@ -8,14 +11,20 @@ import (
|
|||||||
|
|
||||||
// HandleGetPeerAddresses handles the respectively named RPC command
|
// HandleGetPeerAddresses handles the respectively named RPC command
|
||||||
func HandleGetPeerAddresses(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
func HandleGetPeerAddresses(context *rpccontext.Context, _ *router.Router, _ appmessage.Message) (appmessage.Message, error) {
|
||||||
peersState, err := context.AddressManager.PeersStateForSerialization()
|
netAddresses := context.AddressManager.Addresses()
|
||||||
if err != nil {
|
addressMessages := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(netAddresses))
|
||||||
return nil, err
|
for i, netAddress := range netAddresses {
|
||||||
|
addressWithPort := net.JoinHostPort(netAddress.IP.String(), strconv.FormatUint(uint64(netAddress.Port), 10))
|
||||||
|
addressMessages[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: addressWithPort}
|
||||||
}
|
}
|
||||||
addresses := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(peersState.Addresses))
|
|
||||||
for i, address := range peersState.Addresses {
|
bannedAddresses := context.AddressManager.BannedAddresses()
|
||||||
addresses[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: string(address.Address)}
|
bannedAddressMessages := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(bannedAddresses))
|
||||||
|
for i, netAddress := range bannedAddresses {
|
||||||
|
addressWithPort := net.JoinHostPort(netAddress.IP.String(), strconv.FormatUint(uint64(netAddress.Port), 10))
|
||||||
|
bannedAddressMessages[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: addressWithPort}
|
||||||
}
|
}
|
||||||
response := appmessage.NewGetPeerAddressesResponseMessage(addresses)
|
|
||||||
|
response := appmessage.NewGetPeerAddressesResponseMessage(addressMessages, bannedAddressMessages)
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
@ -412,17 +412,30 @@ func (dag *BlockDAG) isAnyInPastOf(nodes blockSet, other *blockNode) (bool, erro
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTopHeaders returns the top appmessage.MaxBlockHeadersPerMsg block headers ordered by blue score.
|
// GetHeaders returns DAG headers ordered by blue score, starts from the given hash with the given direction.
|
||||||
func (dag *BlockDAG) GetTopHeaders(highHash *daghash.Hash, maxHeaders uint64) ([]*appmessage.BlockHeader, error) {
|
func (dag *BlockDAG) GetHeaders(startHash *daghash.Hash, maxHeaders uint64,
|
||||||
|
isAscending bool) ([]*appmessage.BlockHeader, error) {
|
||||||
|
|
||||||
|
dag.RLock()
|
||||||
|
defer dag.RUnlock()
|
||||||
|
|
||||||
|
if isAscending {
|
||||||
|
return dag.getHeadersAscending(startHash, maxHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dag.getHeadersDescending(startHash, maxHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dag *BlockDAG) getHeadersDescending(highHash *daghash.Hash, maxHeaders uint64) ([]*appmessage.BlockHeader, error) {
|
||||||
highNode := dag.virtual.blockNode
|
highNode := dag.virtual.blockNode
|
||||||
if highHash != nil {
|
if highHash != nil {
|
||||||
var ok bool
|
var ok bool
|
||||||
highNode, ok = dag.index.LookupNode(highHash)
|
highNode, ok = dag.index.LookupNode(highHash)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Errorf("Couldn't find the high hash %s in the dag", highHash)
|
return nil, errors.Errorf("Couldn't find the start hash %s in the dag", highHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
headers := make([]*appmessage.BlockHeader, 0, highNode.blueScore)
|
headers := make([]*appmessage.BlockHeader, 0, maxHeaders)
|
||||||
queue := newDownHeap()
|
queue := newDownHeap()
|
||||||
queue.pushSet(highNode.parents)
|
queue.pushSet(highNode.parents)
|
||||||
|
|
||||||
@ -438,6 +451,31 @@ func (dag *BlockDAG) GetTopHeaders(highHash *daghash.Hash, maxHeaders uint64) ([
|
|||||||
return headers, nil
|
return headers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dag *BlockDAG) getHeadersAscending(lowHash *daghash.Hash, maxHeaders uint64) ([]*appmessage.BlockHeader, error) {
|
||||||
|
lowNode := dag.genesis
|
||||||
|
if lowHash != nil {
|
||||||
|
var ok bool
|
||||||
|
lowNode, ok = dag.index.LookupNode(lowHash)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.Errorf("Couldn't find the start hash %s in the dag", lowHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
headers := make([]*appmessage.BlockHeader, 0, maxHeaders)
|
||||||
|
queue := newUpHeap()
|
||||||
|
queue.pushSet(lowNode.children)
|
||||||
|
|
||||||
|
visited := newBlockSet()
|
||||||
|
for i := uint32(0); queue.Len() > 0 && uint64(len(headers)) < maxHeaders; i++ {
|
||||||
|
current := queue.pop()
|
||||||
|
if !visited.contains(current) {
|
||||||
|
visited.add(current)
|
||||||
|
headers = append(headers, current.Header())
|
||||||
|
queue.pushSet(current.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headers, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ForEachHash runs the given fn on every hash that's currently known to
|
// ForEachHash runs the given fn on every hash that's currently known to
|
||||||
// the DAG.
|
// the DAG.
|
||||||
//
|
//
|
||||||
|
@ -214,7 +214,7 @@ func TestIsKnownBlock(t *testing.T) {
|
|||||||
{hash: "732c891529619d43b5aeb3df42ba25dea483a8c0aded1cf585751ebabea28f29", want: true},
|
{hash: "732c891529619d43b5aeb3df42ba25dea483a8c0aded1cf585751ebabea28f29", want: true},
|
||||||
|
|
||||||
// Random hashes should not be available.
|
// Random hashes should not be available.
|
||||||
{hash: "123", want: false},
|
{hash: "1234567812345678123456781234567812345678123456781234567812345678", want: false},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
|
@ -627,10 +627,7 @@ func TestProcessTransaction(t *testing.T) {
|
|||||||
t.Fatalf("Script: error creating wrappedP2shNonSigScript: %v", err)
|
t.Fatalf("Script: error creating wrappedP2shNonSigScript: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dummyPrevOutTxID, err := daghash.NewTxIDFromStr("01")
|
dummyPrevOutTxID := &daghash.TxID{}
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("NewShaHashFromStr: unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
dummyPrevOut := appmessage.Outpoint{TxID: *dummyPrevOutTxID, Index: 1}
|
dummyPrevOut := appmessage.Outpoint{TxID: *dummyPrevOutTxID, Index: 1}
|
||||||
dummySigScript := bytes.Repeat([]byte{0x00}, 65)
|
dummySigScript := bytes.Repeat([]byte{0x00}, 65)
|
||||||
|
|
||||||
|
@ -168,10 +168,7 @@ func TestDust(t *testing.T) {
|
|||||||
// TestCheckTransactionStandard tests the checkTransactionStandard API.
|
// TestCheckTransactionStandard tests the checkTransactionStandard API.
|
||||||
func TestCheckTransactionStandard(t *testing.T) {
|
func TestCheckTransactionStandard(t *testing.T) {
|
||||||
// Create some dummy, but otherwise standard, data for transactions.
|
// Create some dummy, but otherwise standard, data for transactions.
|
||||||
prevOutTxID, err := daghash.NewTxIDFromStr("01")
|
prevOutTxID := &daghash.TxID{}
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("NewShaHashFromStr: unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
dummyPrevOut := appmessage.Outpoint{TxID: *prevOutTxID, Index: 1}
|
dummyPrevOut := appmessage.Outpoint{TxID: *prevOutTxID, Index: 1}
|
||||||
dummySigScript := bytes.Repeat([]byte{0x00}, 65)
|
dummySigScript := bytes.Repeat([]byte{0x00}, 65)
|
||||||
dummyTxIn := appmessage.TxIn{
|
dummyTxIn := appmessage.TxIn{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,518 +5,27 @@
|
|||||||
package addressmanager
|
package addressmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
|
||||||
"github.com/kaspanet/kaspad/util/mstime"
|
|
||||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// naTest is used to describe a test to be performed against the NetAddressKey
|
func newAddrManagerForTest(t *testing.T, testName string) (addressManager *AddressManager, teardown func()) {
|
||||||
// method.
|
|
||||||
type naTest struct {
|
|
||||||
in appmessage.NetAddress
|
|
||||||
want AddressKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// naTests houses all of the tests to be performed against the NetAddressKey
|
|
||||||
// method.
|
|
||||||
var naTests = make([]naTest, 0)
|
|
||||||
|
|
||||||
// Put some IP in here for convenience. Points to google.
|
|
||||||
var someIP = "173.194.115.66"
|
|
||||||
|
|
||||||
// addNaTests
|
|
||||||
func addNaTests() {
|
|
||||||
// IPv4
|
|
||||||
// Localhost
|
|
||||||
addNaTest("127.0.0.1", 16111, "127.0.0.1:16111")
|
|
||||||
addNaTest("127.0.0.1", 16110, "127.0.0.1:16110")
|
|
||||||
|
|
||||||
// Class A
|
|
||||||
addNaTest("1.0.0.1", 16111, "1.0.0.1:16111")
|
|
||||||
addNaTest("2.2.2.2", 16110, "2.2.2.2:16110")
|
|
||||||
addNaTest("27.253.252.251", 8335, "27.253.252.251:8335")
|
|
||||||
addNaTest("123.3.2.1", 8336, "123.3.2.1:8336")
|
|
||||||
|
|
||||||
// Private Class A
|
|
||||||
addNaTest("10.0.0.1", 16111, "10.0.0.1:16111")
|
|
||||||
addNaTest("10.1.1.1", 16110, "10.1.1.1:16110")
|
|
||||||
addNaTest("10.2.2.2", 8335, "10.2.2.2:8335")
|
|
||||||
addNaTest("10.10.10.10", 8336, "10.10.10.10:8336")
|
|
||||||
|
|
||||||
// Class B
|
|
||||||
addNaTest("128.0.0.1", 16111, "128.0.0.1:16111")
|
|
||||||
addNaTest("129.1.1.1", 16110, "129.1.1.1:16110")
|
|
||||||
addNaTest("180.2.2.2", 8335, "180.2.2.2:8335")
|
|
||||||
addNaTest("191.10.10.10", 8336, "191.10.10.10:8336")
|
|
||||||
|
|
||||||
// Private Class B
|
|
||||||
addNaTest("172.16.0.1", 16111, "172.16.0.1:16111")
|
|
||||||
addNaTest("172.16.1.1", 16110, "172.16.1.1:16110")
|
|
||||||
addNaTest("172.16.2.2", 8335, "172.16.2.2:8335")
|
|
||||||
addNaTest("172.16.172.172", 8336, "172.16.172.172:8336")
|
|
||||||
|
|
||||||
// Class C
|
|
||||||
addNaTest("193.0.0.1", 16111, "193.0.0.1:16111")
|
|
||||||
addNaTest("200.1.1.1", 16110, "200.1.1.1:16110")
|
|
||||||
addNaTest("205.2.2.2", 8335, "205.2.2.2:8335")
|
|
||||||
addNaTest("223.10.10.10", 8336, "223.10.10.10:8336")
|
|
||||||
|
|
||||||
// Private Class C
|
|
||||||
addNaTest("192.168.0.1", 16111, "192.168.0.1:16111")
|
|
||||||
addNaTest("192.168.1.1", 16110, "192.168.1.1:16110")
|
|
||||||
addNaTest("192.168.2.2", 8335, "192.168.2.2:8335")
|
|
||||||
addNaTest("192.168.192.192", 8336, "192.168.192.192:8336")
|
|
||||||
|
|
||||||
// IPv6
|
|
||||||
// Localhost
|
|
||||||
addNaTest("::1", 16111, "[::1]:16111")
|
|
||||||
addNaTest("fe80::1", 16110, "[fe80::1]:16110")
|
|
||||||
|
|
||||||
// Link-local
|
|
||||||
addNaTest("fe80::1:1", 16111, "[fe80::1:1]:16111")
|
|
||||||
addNaTest("fe91::2:2", 16110, "[fe91::2:2]:16110")
|
|
||||||
addNaTest("fea2::3:3", 8335, "[fea2::3:3]:8335")
|
|
||||||
addNaTest("feb3::4:4", 8336, "[feb3::4:4]:8336")
|
|
||||||
|
|
||||||
// Site-local
|
|
||||||
addNaTest("fec0::1:1", 16111, "[fec0::1:1]:16111")
|
|
||||||
addNaTest("fed1::2:2", 16110, "[fed1::2:2]:16110")
|
|
||||||
addNaTest("fee2::3:3", 8335, "[fee2::3:3]:8335")
|
|
||||||
addNaTest("fef3::4:4", 8336, "[fef3::4:4]:8336")
|
|
||||||
}
|
|
||||||
|
|
||||||
func addNaTest(ip string, port uint16, want AddressKey) {
|
|
||||||
nip := net.ParseIP(ip)
|
|
||||||
na := *appmessage.NewNetAddressIPPort(nip, port, appmessage.SFNodeNetwork)
|
|
||||||
test := naTest{na, want}
|
|
||||||
naTests = append(naTests, test)
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupFuncForTest(host string) ([]net.IP, error) {
|
|
||||||
return nil, errors.New("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func newAddrManagerForTest(t *testing.T, testName string,
|
|
||||||
localSubnetworkID *subnetworkid.SubnetworkID) (addressManager *AddressManager, teardown func()) {
|
|
||||||
|
|
||||||
cfg := config.DefaultConfig()
|
cfg := config.DefaultConfig()
|
||||||
cfg.SubnetworkID = localSubnetworkID
|
|
||||||
|
|
||||||
dbPath, err := ioutil.TempDir("", testName)
|
addressManager, err := New(NewConfig(cfg))
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error creating temporary directory: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
databaseContext, err := dbaccess.New(dbPath)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error creating db: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
addressManager, err = New(cfg, databaseContext)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error creating address manager: %s", err)
|
t.Fatalf("error creating address manager: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return addressManager, func() {
|
return addressManager, func() {
|
||||||
err := databaseContext.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error closing the database: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStartStop(t *testing.T) {
|
func TestBestLocalAddress(t *testing.T) {
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestStartStop", nil)
|
|
||||||
defer teardown()
|
|
||||||
err := amgr.Start()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Address Manager failed to start: %v", err)
|
|
||||||
}
|
|
||||||
err = amgr.Stop()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Address Manager failed to stop: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddAddressByIP(t *testing.T) {
|
|
||||||
fmtErr := errors.Errorf("")
|
|
||||||
addrErr := &net.AddrError{}
|
|
||||||
var tests = []struct {
|
|
||||||
addrIP string
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
someIP + ":16111",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
someIP,
|
|
||||||
addrErr,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
someIP[:12] + ":8333",
|
|
||||||
fmtErr,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
someIP + ":abcd",
|
|
||||||
fmtErr,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP", nil)
|
|
||||||
defer teardown()
|
|
||||||
for i, test := range tests {
|
|
||||||
err := AddAddressByIP(amgr, test.addrIP, nil)
|
|
||||||
if test.err != nil && err == nil {
|
|
||||||
t.Errorf("TestAddAddressByIP test %d failed expected an error and got none", i)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if test.err == nil && err != nil {
|
|
||||||
t.Errorf("TestAddAddressByIP test %d failed expected no error and got one", i)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
|
||||||
t.Errorf("TestAddAddressByIP test %d failed got %v, want %v", i,
|
|
||||||
reflect.TypeOf(err), reflect.TypeOf(test.err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddLocalAddress(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
address appmessage.NetAddress
|
|
||||||
priority AddressPriority
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
appmessage.NetAddress{IP: net.ParseIP("192.168.0.100")},
|
|
||||||
InterfacePrio,
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
appmessage.NetAddress{IP: net.ParseIP("204.124.1.1")},
|
|
||||||
InterfacePrio,
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
appmessage.NetAddress{IP: net.ParseIP("204.124.1.1")},
|
|
||||||
BoundPrio,
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
appmessage.NetAddress{IP: net.ParseIP("::1")},
|
|
||||||
InterfacePrio,
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
appmessage.NetAddress{IP: net.ParseIP("fe80::1")},
|
|
||||||
InterfacePrio,
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
appmessage.NetAddress{IP: net.ParseIP("2620:100::1")},
|
|
||||||
InterfacePrio,
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestAddLocalAddress", nil)
|
|
||||||
defer teardown()
|
|
||||||
for x, test := range tests {
|
|
||||||
result := amgr.AddLocalAddress(&test.address, test.priority)
|
|
||||||
if result == nil && !test.valid {
|
|
||||||
t.Errorf("TestAddLocalAddress test #%d failed: %s should have "+
|
|
||||||
"been accepted", x, test.address.IP)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if result != nil && test.valid {
|
|
||||||
t.Errorf("TestAddLocalAddress test #%d failed: %s should not have "+
|
|
||||||
"been accepted", x, test.address.IP)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAttempt(t *testing.T) {
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestAttempt", nil)
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
// Add a new address and get it
|
|
||||||
err := AddAddressByIP(amgr, someIP+":8333", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Adding address failed: %v", err)
|
|
||||||
}
|
|
||||||
ka := amgr.GetAddress()
|
|
||||||
|
|
||||||
if !ka.LastAttempt().IsZero() {
|
|
||||||
t.Errorf("Address should not have attempts, but does")
|
|
||||||
}
|
|
||||||
|
|
||||||
na := ka.NetAddress()
|
|
||||||
amgr.Attempt(na)
|
|
||||||
|
|
||||||
if ka.LastAttempt().IsZero() {
|
|
||||||
t.Errorf("Address should have an attempt, but does not")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConnected(t *testing.T) {
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestConnected", nil)
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
// Add a new address and get it
|
|
||||||
err := AddAddressByIP(amgr, someIP+":8333", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Adding address failed: %v", err)
|
|
||||||
}
|
|
||||||
ka := amgr.GetAddress()
|
|
||||||
na := ka.NetAddress()
|
|
||||||
// make it an hour ago
|
|
||||||
na.Timestamp = mstime.Now().Add(time.Hour * -1)
|
|
||||||
|
|
||||||
amgr.Connected(na)
|
|
||||||
|
|
||||||
if !ka.NetAddress().Timestamp.After(na.Timestamp) {
|
|
||||||
t.Errorf("Address should have a new timestamp, but does not")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNeedMoreAddresses(t *testing.T) {
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestNeedMoreAddresses", nil)
|
|
||||||
defer teardown()
|
|
||||||
addrsToAdd := 1500
|
|
||||||
b := amgr.NeedMoreAddresses()
|
|
||||||
if !b {
|
|
||||||
t.Errorf("Expected that we need more addresses")
|
|
||||||
}
|
|
||||||
addrs := make([]*appmessage.NetAddress, addrsToAdd)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
for i := 0; i < addrsToAdd; i++ {
|
|
||||||
s := AddressKey(fmt.Sprintf("%d.%d.173.147:8333", i/128+60, i%128+60))
|
|
||||||
addrs[i], err = amgr.DeserializeNetAddress(s)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
|
||||||
|
|
||||||
amgr.AddAddresses(addrs, srcAddr, nil)
|
|
||||||
numAddrs := amgr.TotalNumAddresses()
|
|
||||||
if numAddrs > addrsToAdd {
|
|
||||||
t.Errorf("Number of addresses is too many %d vs %d", numAddrs, addrsToAdd)
|
|
||||||
}
|
|
||||||
|
|
||||||
b = amgr.NeedMoreAddresses()
|
|
||||||
if b {
|
|
||||||
t.Errorf("Expected that we don't need more addresses")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGood(t *testing.T) {
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestGood", nil)
|
|
||||||
defer teardown()
|
|
||||||
addrsToAdd := 64 * 64
|
|
||||||
addrs := make([]*appmessage.NetAddress, addrsToAdd)
|
|
||||||
subnetworkCount := 32
|
|
||||||
subnetworkIDs := make([]*subnetworkid.SubnetworkID, subnetworkCount)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
for i := 0; i < addrsToAdd; i++ {
|
|
||||||
s := AddressKey(fmt.Sprintf("%d.173.147.%d:8333", i/64+60, i%64+60))
|
|
||||||
addrs[i], err = amgr.DeserializeNetAddress(s)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < subnetworkCount; i++ {
|
|
||||||
subnetworkIDs[i] = &subnetworkid.SubnetworkID{0xff - byte(i)}
|
|
||||||
}
|
|
||||||
|
|
||||||
srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
|
||||||
|
|
||||||
amgr.AddAddresses(addrs, srcAddr, nil)
|
|
||||||
for i, addr := range addrs {
|
|
||||||
amgr.Good(addr, subnetworkIDs[i%subnetworkCount])
|
|
||||||
}
|
|
||||||
|
|
||||||
numAddrs := amgr.TotalNumAddresses()
|
|
||||||
if numAddrs >= addrsToAdd {
|
|
||||||
t.Errorf("Number of addresses is too many: %d vs %d", numAddrs, addrsToAdd)
|
|
||||||
}
|
|
||||||
|
|
||||||
numCache := len(amgr.AddressCache(true, nil))
|
|
||||||
if numCache == 0 || numCache >= numAddrs/4 {
|
|
||||||
t.Errorf("Number of addresses in cache: got %d, want positive and less than %d",
|
|
||||||
numCache, numAddrs/4)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < subnetworkCount; i++ {
|
|
||||||
numCache = len(amgr.AddressCache(false, subnetworkIDs[i]))
|
|
||||||
if numCache == 0 || numCache >= numAddrs/subnetworkCount {
|
|
||||||
t.Errorf("Number of addresses in subnetwork cache: got %d, want positive and less than %d",
|
|
||||||
numCache, numAddrs/4/subnetworkCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGoodChangeSubnetworkID(t *testing.T) {
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestGoodChangeSubnetworkID", nil)
|
|
||||||
defer teardown()
|
|
||||||
addr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
|
||||||
addrKey := NetAddressKey(addr)
|
|
||||||
srcAddr := appmessage.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
|
||||||
|
|
||||||
oldSubnetwork := subnetworkid.SubnetworkIDNative
|
|
||||||
amgr.AddAddress(addr, srcAddr, oldSubnetwork)
|
|
||||||
amgr.Good(addr, oldSubnetwork)
|
|
||||||
|
|
||||||
// make sure address was saved to addressIndex under oldSubnetwork
|
|
||||||
ka := amgr.knownAddress(addr)
|
|
||||||
if ka == nil {
|
|
||||||
t.Fatalf("Address was not found after first time .Good called")
|
|
||||||
}
|
|
||||||
if !ka.SubnetworkID().IsEqual(oldSubnetwork) {
|
|
||||||
t.Fatalf("Address index did not point to oldSubnetwork")
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure address was added to correct bucket under oldSubnetwork
|
|
||||||
bucket := amgr.subnetworkTriedAddresBucketArrays[*oldSubnetwork][amgr.triedAddressBucketIndex(addr)]
|
|
||||||
wasFound := false
|
|
||||||
for _, ka := range bucket {
|
|
||||||
if NetAddressKey(ka.NetAddress()) == addrKey {
|
|
||||||
wasFound = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !wasFound {
|
|
||||||
t.Fatalf("Address was not found in the correct bucket in oldSubnetwork")
|
|
||||||
}
|
|
||||||
|
|
||||||
// now call .Good again with a different subnetwork
|
|
||||||
newSubnetwork := subnetworkid.SubnetworkIDRegistry
|
|
||||||
amgr.Good(addr, newSubnetwork)
|
|
||||||
|
|
||||||
// make sure address was updated in addressIndex under newSubnetwork
|
|
||||||
ka = amgr.knownAddress(addr)
|
|
||||||
if ka == nil {
|
|
||||||
t.Fatalf("Address was not found after second time .Good called")
|
|
||||||
}
|
|
||||||
if !ka.SubnetworkID().IsEqual(newSubnetwork) {
|
|
||||||
t.Fatalf("Address index did not point to newSubnetwork")
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure address was removed from bucket under oldSubnetwork
|
|
||||||
bucket = amgr.subnetworkTriedAddresBucketArrays[*oldSubnetwork][amgr.triedAddressBucketIndex(addr)]
|
|
||||||
wasFound = false
|
|
||||||
for _, ka := range bucket {
|
|
||||||
if NetAddressKey(ka.NetAddress()) == addrKey {
|
|
||||||
wasFound = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if wasFound {
|
|
||||||
t.Fatalf("Address was not removed from bucket in oldSubnetwork")
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure address was added to correct bucket under newSubnetwork
|
|
||||||
bucket = amgr.subnetworkTriedAddresBucketArrays[*newSubnetwork][amgr.triedAddressBucketIndex(addr)]
|
|
||||||
wasFound = false
|
|
||||||
for _, ka := range bucket {
|
|
||||||
if NetAddressKey(ka.NetAddress()) == addrKey {
|
|
||||||
wasFound = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !wasFound {
|
|
||||||
t.Fatalf("Address was not found in the correct bucket in newSubnetwork")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAddress(t *testing.T) {
|
|
||||||
localSubnetworkID := &subnetworkid.SubnetworkID{0xff}
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestGetAddress", localSubnetworkID)
|
|
||||||
defer teardown()
|
|
||||||
|
|
||||||
// Get an address from an empty set (should error)
|
|
||||||
if rv := amgr.GetAddress(); rv != nil {
|
|
||||||
t.Errorf("GetAddress failed: got: %v want: %v\n", rv, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new address and get it
|
|
||||||
err := AddAddressByIP(amgr, someIP+":8332", localSubnetworkID)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Adding address failed: %v", err)
|
|
||||||
}
|
|
||||||
ka := amgr.GetAddress()
|
|
||||||
if ka == nil {
|
|
||||||
t.Fatalf("Did not get an address where there is one in the pool")
|
|
||||||
}
|
|
||||||
amgr.Attempt(ka.NetAddress())
|
|
||||||
|
|
||||||
// Checks that we don't get it if we find that it has other subnetwork ID than expected.
|
|
||||||
actualSubnetworkID := &subnetworkid.SubnetworkID{0xfe}
|
|
||||||
amgr.Good(ka.NetAddress(), actualSubnetworkID)
|
|
||||||
ka = amgr.GetAddress()
|
|
||||||
if ka != nil {
|
|
||||||
t.Errorf("Didn't expect to get an address because there shouldn't be any address from subnetwork ID %s or nil", localSubnetworkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks that the total number of addresses incremented although the new address is not full node or a partial node of the same subnetwork as the local node.
|
|
||||||
numAddrs := amgr.TotalNumAddresses()
|
|
||||||
if numAddrs != 1 {
|
|
||||||
t.Errorf("Wrong number of addresses: got %d, want %d", numAddrs, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we repeat the same process, but now the address has the expected subnetwork ID.
|
|
||||||
|
|
||||||
// Add a new address and get it
|
|
||||||
err = AddAddressByIP(amgr, someIP+":8333", localSubnetworkID)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Adding address failed: %v", err)
|
|
||||||
}
|
|
||||||
ka = amgr.GetAddress()
|
|
||||||
if ka == nil {
|
|
||||||
t.Fatalf("Did not get an address where there is one in the pool")
|
|
||||||
}
|
|
||||||
if ka.NetAddress().IP.String() != someIP {
|
|
||||||
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().IP.String(), someIP)
|
|
||||||
}
|
|
||||||
if !ka.SubnetworkID().IsEqual(localSubnetworkID) {
|
|
||||||
t.Errorf("Wrong Subnetwork ID: got %v, want %v", *ka.SubnetworkID(), localSubnetworkID)
|
|
||||||
}
|
|
||||||
amgr.Attempt(ka.NetAddress())
|
|
||||||
|
|
||||||
// Mark this as a good address and get it
|
|
||||||
amgr.Good(ka.NetAddress(), localSubnetworkID)
|
|
||||||
ka = amgr.GetAddress()
|
|
||||||
if ka == nil {
|
|
||||||
t.Fatalf("Did not get an address where there is one in the pool")
|
|
||||||
}
|
|
||||||
if ka.NetAddress().IP.String() != someIP {
|
|
||||||
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().IP.String(), someIP)
|
|
||||||
}
|
|
||||||
if *ka.SubnetworkID() != *localSubnetworkID {
|
|
||||||
t.Errorf("Wrong Subnetwork ID: got %v, want %v", ka.SubnetworkID(), localSubnetworkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
numAddrs = amgr.TotalNumAddresses()
|
|
||||||
if numAddrs != 2 {
|
|
||||||
t.Errorf("Wrong number of addresses: got %d, want %d", numAddrs, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetBestLocalAddress(t *testing.T) {
|
|
||||||
localAddrs := []appmessage.NetAddress{
|
localAddrs := []appmessage.NetAddress{
|
||||||
{IP: net.ParseIP("192.168.0.100")},
|
{IP: net.ParseIP("192.168.0.100")},
|
||||||
{IP: net.ParseIP("::1")},
|
{IP: net.ParseIP("::1")},
|
||||||
@ -557,12 +66,12 @@ func TestGetBestLocalAddress(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestGetBestLocalAddress", nil)
|
amgr, teardown := newAddrManagerForTest(t, "TestGetBestLocalAddress")
|
||||||
defer teardown()
|
defer teardown()
|
||||||
|
|
||||||
// Test against default when there's no address
|
// Test against default when there's no address
|
||||||
for x, test := range tests {
|
for x, test := range tests {
|
||||||
got := amgr.GetBestLocalAddress(&test.remoteAddr)
|
got := amgr.BestLocalAddress(&test.remoteAddr)
|
||||||
if !test.want0.IP.Equal(got.IP) {
|
if !test.want0.IP.Equal(got.IP) {
|
||||||
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
|
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
|
||||||
x, test.remoteAddr.IP, test.want1.IP, got.IP)
|
x, test.remoteAddr.IP, test.want1.IP, got.IP)
|
||||||
@ -571,12 +80,12 @@ func TestGetBestLocalAddress(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, localAddr := range localAddrs {
|
for _, localAddr := range localAddrs {
|
||||||
amgr.AddLocalAddress(&localAddr, InterfacePrio)
|
amgr.localAddresses.addLocalNetAddress(&localAddr, InterfacePrio)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test against want1
|
// Test against want1
|
||||||
for x, test := range tests {
|
for x, test := range tests {
|
||||||
got := amgr.GetBestLocalAddress(&test.remoteAddr)
|
got := amgr.BestLocalAddress(&test.remoteAddr)
|
||||||
if !test.want1.IP.Equal(got.IP) {
|
if !test.want1.IP.Equal(got.IP) {
|
||||||
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
|
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
|
||||||
x, test.remoteAddr.IP, test.want1.IP, got.IP)
|
x, test.remoteAddr.IP, test.want1.IP, got.IP)
|
||||||
@ -586,42 +95,15 @@ func TestGetBestLocalAddress(t *testing.T) {
|
|||||||
|
|
||||||
// Add a public IP to the list of local addresses.
|
// Add a public IP to the list of local addresses.
|
||||||
localAddr := appmessage.NetAddress{IP: net.ParseIP("204.124.8.100")}
|
localAddr := appmessage.NetAddress{IP: net.ParseIP("204.124.8.100")}
|
||||||
amgr.AddLocalAddress(&localAddr, InterfacePrio)
|
amgr.localAddresses.addLocalNetAddress(&localAddr, InterfacePrio)
|
||||||
|
|
||||||
// Test against want2
|
// Test against want2
|
||||||
for x, test := range tests {
|
for x, test := range tests {
|
||||||
got := amgr.GetBestLocalAddress(&test.remoteAddr)
|
got := amgr.BestLocalAddress(&test.remoteAddr)
|
||||||
if !test.want2.IP.Equal(got.IP) {
|
if !test.want2.IP.Equal(got.IP) {
|
||||||
t.Errorf("TestGetBestLocalAddress test2 #%d failed for remote address %s: want %s got %s",
|
t.Errorf("TestGetBestLocalAddress test2 #%d failed for remote address %s: want %s got %s",
|
||||||
x, test.remoteAddr.IP, test.want2.IP, got.IP)
|
x, test.remoteAddr.IP, test.want2.IP, got.IP)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
// Add a Tor generated IP address
|
|
||||||
localAddr = appmessage.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")}
|
|
||||||
amgr.AddLocalAddress(&localAddr, ManualPrio)
|
|
||||||
// Test against want3
|
|
||||||
for x, test := range tests {
|
|
||||||
got := amgr.GetBestLocalAddress(&test.remoteAddr)
|
|
||||||
if !test.want3.IP.Equal(got.IP) {
|
|
||||||
t.Errorf("TestGetBestLocalAddress test3 #%d failed for remote address %s: want %s got %s",
|
|
||||||
x, test.remoteAddr.IP, test.want3.IP, got.IP)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNetAddressKey(t *testing.T) {
|
|
||||||
addNaTests()
|
|
||||||
|
|
||||||
t.Logf("Running %d tests", len(naTests))
|
|
||||||
for i, test := range naTests {
|
|
||||||
key := NetAddressKey(&test.in)
|
|
||||||
if key != test.want {
|
|
||||||
t.Errorf("NetAddressKey #%d\n got: %s want: %s", i, key, test.want)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
43
infrastructure/network/addressmanager/addressrandomize.go
Normal file
43
infrastructure/network/addressmanager/addressrandomize.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package addressmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddressRandomize implement AddressRandomizer interface
|
||||||
|
type AddressRandomize struct {
|
||||||
|
random *rand.Rand
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAddressRandomize returns a new RandomizeAddress.
|
||||||
|
func NewAddressRandomize() *AddressRandomize {
|
||||||
|
return &AddressRandomize{
|
||||||
|
random: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomAddress returns a random address from input list
|
||||||
|
func (amc *AddressRandomize) RandomAddress(addresses []*appmessage.NetAddress) *appmessage.NetAddress {
|
||||||
|
if len(addresses) > 0 {
|
||||||
|
randomIndex := rand.Intn(len(addresses))
|
||||||
|
return addresses[randomIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomAddresses returns count addresses at random from input list
|
||||||
|
func (amc *AddressRandomize) RandomAddresses(addresses []*appmessage.NetAddress, count int) []*appmessage.NetAddress {
|
||||||
|
result := make([]*appmessage.NetAddress, 0, count)
|
||||||
|
if len(addresses) > 0 {
|
||||||
|
randomIndexes := rand.Perm(len(addresses))
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
result = append(result, addresses[randomIndexes[i]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
27
infrastructure/network/addressmanager/config.go
Normal file
27
infrastructure/network/addressmanager/config.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package addressmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config is a descriptor which specifies the AddressManager instance configuration.
|
||||||
|
type Config struct {
|
||||||
|
AcceptUnroutable bool
|
||||||
|
DefaultPort string
|
||||||
|
ExternalIPs []string
|
||||||
|
Listeners []string
|
||||||
|
Lookup func(string) ([]net.IP, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfig returns a new address manager Config.
|
||||||
|
func NewConfig(cfg *config.Config) *Config {
|
||||||
|
return &Config{
|
||||||
|
AcceptUnroutable: cfg.NetParams().AcceptUnroutable,
|
||||||
|
DefaultPort: cfg.NetParams().DefaultPort,
|
||||||
|
ExternalIPs: cfg.ExternalIPs,
|
||||||
|
Listeners: cfg.Listeners,
|
||||||
|
Lookup: cfg.Lookup,
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
// Copyright (c) 2013-2015 The btcsuite developers
|
|
||||||
// Use of this source code is governed by an ISC
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package addressmanager
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
|
||||||
"github.com/kaspanet/kaspad/util/mstime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TstKnownAddressIsBad(ka *KnownAddress) bool {
|
|
||||||
return ka.isBad()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TstKnownAddressChance(ka *KnownAddress) float64 {
|
|
||||||
return ka.chance()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TstNewKnownAddress(na *appmessage.NetAddress, attempts int,
|
|
||||||
lastattempt, lastsuccess mstime.Time, tried bool, refs int) *KnownAddress {
|
|
||||||
return &KnownAddress{netAddress: na, attempts: attempts, lastAttempt: lastattempt,
|
|
||||||
lastSuccess: lastsuccess, tried: tried, referenceCount: refs}
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
// Copyright (c) 2013-2014 The btcsuite developers
|
|
||||||
// Use of this source code is governed by an ISC
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package addressmanager
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
|
||||||
"github.com/kaspanet/kaspad/util/mstime"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// KnownAddress tracks information about a known network address that is used
|
|
||||||
// to determine how viable an address is.
|
|
||||||
type KnownAddress struct {
|
|
||||||
netAddress *appmessage.NetAddress
|
|
||||||
sourceAddress *appmessage.NetAddress
|
|
||||||
attempts int
|
|
||||||
lastAttempt mstime.Time
|
|
||||||
lastSuccess mstime.Time
|
|
||||||
tried bool
|
|
||||||
referenceCount int // reference count of new buckets
|
|
||||||
subnetworkID *subnetworkid.SubnetworkID
|
|
||||||
isBanned bool
|
|
||||||
bannedTime mstime.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetAddress returns the underlying appmessage.NetAddress associated with the
|
|
||||||
// known address.
|
|
||||||
func (ka *KnownAddress) NetAddress() *appmessage.NetAddress {
|
|
||||||
return ka.netAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubnetworkID returns the subnetwork ID of the known address.
|
|
||||||
func (ka *KnownAddress) SubnetworkID() *subnetworkid.SubnetworkID {
|
|
||||||
return ka.subnetworkID
|
|
||||||
}
|
|
||||||
|
|
||||||
// LastAttempt returns the last time the known address was attempted.
|
|
||||||
func (ka *KnownAddress) LastAttempt() mstime.Time {
|
|
||||||
return ka.lastAttempt
|
|
||||||
}
|
|
||||||
|
|
||||||
// chance returns the selection probability for a known address. The priority
|
|
||||||
// depends upon how recently the address has been seen, how recently it was last
|
|
||||||
// attempted and how often attempts to connect to it have failed.
|
|
||||||
func (ka *KnownAddress) chance() float64 {
|
|
||||||
now := mstime.Now()
|
|
||||||
lastAttempt := now.Sub(ka.lastAttempt)
|
|
||||||
|
|
||||||
if lastAttempt < 0 {
|
|
||||||
lastAttempt = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
c := 1.0
|
|
||||||
|
|
||||||
// Very recent attempts are less likely to be retried.
|
|
||||||
if lastAttempt < 10*time.Minute {
|
|
||||||
c *= 0.01
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failed attempts deprioritise.
|
|
||||||
for i := ka.attempts; i > 0; i-- {
|
|
||||||
c /= 1.5
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// isBad returns true if the address in question has not been tried in the last
|
|
||||||
// minute and meets one of the following criteria:
|
|
||||||
// 1) It claims to be from the future
|
|
||||||
// 2) It hasn't been seen in over a month
|
|
||||||
// 3) It has failed at least three times and never succeeded
|
|
||||||
// 4) It has failed ten times in the last week
|
|
||||||
// All addresses that meet these criteria are assumed to be worthless and not
|
|
||||||
// worth keeping hold of.
|
|
||||||
func (ka *KnownAddress) isBad() bool {
|
|
||||||
if ka.lastAttempt.After(mstime.Now().Add(-1 * time.Minute)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// From the future?
|
|
||||||
if ka.netAddress.Timestamp.After(mstime.Now().Add(10 * time.Minute)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Over a month old?
|
|
||||||
if ka.netAddress.Timestamp.Before(mstime.Now().Add(-1 * numMissingDays * time.Hour * 24)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Never succeeded?
|
|
||||||
if ka.lastSuccess.IsZero() && ka.attempts >= numRetries {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hasn't succeeded in too long?
|
|
||||||
if !ka.lastSuccess.After(mstime.Now().Add(-1*minBadDays*time.Hour*24)) &&
|
|
||||||
ka.attempts >= maxFailures {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
// Copyright (c) 2013-2015 The btcsuite developers
|
|
||||||
// Use of this source code is governed by an ISC
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package addressmanager_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
|
||||||
"github.com/kaspanet/kaspad/util/mstime"
|
|
||||||
"math"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestChance(t *testing.T) {
|
|
||||||
now := mstime.Now()
|
|
||||||
var tests = []struct {
|
|
||||||
addr *addressmanager.KnownAddress
|
|
||||||
expected float64
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
//Test normal case
|
|
||||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
|
||||||
0, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0),
|
|
||||||
1.0,
|
|
||||||
}, {
|
|
||||||
//Test case in which lastseen < 0
|
|
||||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(20 * time.Second)},
|
|
||||||
0, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0),
|
|
||||||
1.0,
|
|
||||||
}, {
|
|
||||||
//Test case in which lastAttempt < 0
|
|
||||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
|
||||||
0, mstime.Now().Add(30*time.Minute), mstime.Now(), false, 0),
|
|
||||||
1.0 * .01,
|
|
||||||
}, {
|
|
||||||
//Test case in which lastAttempt < ten minutes
|
|
||||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
|
||||||
0, mstime.Now().Add(-5*time.Minute), mstime.Now(), false, 0),
|
|
||||||
1.0 * .01,
|
|
||||||
}, {
|
|
||||||
//Test case with several failed attempts.
|
|
||||||
addressmanager.TstNewKnownAddress(&appmessage.NetAddress{Timestamp: now.Add(-35 * time.Second)},
|
|
||||||
2, mstime.Now().Add(-30*time.Minute), mstime.Now(), false, 0),
|
|
||||||
1 / 1.5 / 1.5,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := .0001
|
|
||||||
for i, test := range tests {
|
|
||||||
chance := addressmanager.TstKnownAddressChance(test.addr)
|
|
||||||
if math.Abs(test.expected-chance) >= err {
|
|
||||||
t.Errorf("case %d: got %f, expected %f", i, chance, test.expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsBad(t *testing.T) {
|
|
||||||
now := mstime.Now()
|
|
||||||
future := now.Add(35 * time.Minute)
|
|
||||||
monthOld := now.Add(-43 * time.Hour * 24)
|
|
||||||
secondsOld := now.Add(-2 * time.Second)
|
|
||||||
minutesOld := now.Add(-27 * time.Minute)
|
|
||||||
hoursOld := now.Add(-5 * time.Hour)
|
|
||||||
zeroTime := mstime.Time{}
|
|
||||||
|
|
||||||
futureNa := &appmessage.NetAddress{Timestamp: future}
|
|
||||||
minutesOldNa := &appmessage.NetAddress{Timestamp: minutesOld}
|
|
||||||
monthOldNa := &appmessage.NetAddress{Timestamp: monthOld}
|
|
||||||
currentNa := &appmessage.NetAddress{Timestamp: secondsOld}
|
|
||||||
|
|
||||||
//Test addresses that have been tried in the last minute.
|
|
||||||
if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(futureNa, 3, secondsOld, zeroTime, false, 0)) {
|
|
||||||
t.Errorf("test case 1: addresses that have been tried in the last minute are not bad.")
|
|
||||||
}
|
|
||||||
if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(monthOldNa, 3, secondsOld, zeroTime, false, 0)) {
|
|
||||||
t.Errorf("test case 2: addresses that have been tried in the last minute are not bad.")
|
|
||||||
}
|
|
||||||
if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(currentNa, 3, secondsOld, zeroTime, false, 0)) {
|
|
||||||
t.Errorf("test case 3: addresses that have been tried in the last minute are not bad.")
|
|
||||||
}
|
|
||||||
if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(currentNa, 3, secondsOld, monthOld, true, 0)) {
|
|
||||||
t.Errorf("test case 4: addresses that have been tried in the last minute are not bad.")
|
|
||||||
}
|
|
||||||
if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(currentNa, 2, secondsOld, secondsOld, true, 0)) {
|
|
||||||
t.Errorf("test case 5: addresses that have been tried in the last minute are not bad.")
|
|
||||||
}
|
|
||||||
|
|
||||||
//Test address that claims to be from the future.
|
|
||||||
if !addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(futureNa, 0, minutesOld, hoursOld, true, 0)) {
|
|
||||||
t.Errorf("test case 6: addresses that claim to be from the future are bad.")
|
|
||||||
}
|
|
||||||
|
|
||||||
//Test address that has not been seen in over a month.
|
|
||||||
if !addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(monthOldNa, 0, minutesOld, hoursOld, true, 0)) {
|
|
||||||
t.Errorf("test case 7: addresses more than a month old are bad.")
|
|
||||||
}
|
|
||||||
|
|
||||||
//It has failed at least three times and never succeeded.
|
|
||||||
if !addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(minutesOldNa, 3, minutesOld, zeroTime, true, 0)) {
|
|
||||||
t.Errorf("test case 8: addresses that have never succeeded are bad.")
|
|
||||||
}
|
|
||||||
|
|
||||||
//It has failed ten times in the last week
|
|
||||||
if !addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(minutesOldNa, 10, minutesOld, monthOld, true, 0)) {
|
|
||||||
t.Errorf("test case 9: addresses that have not succeeded in too long are bad.")
|
|
||||||
}
|
|
||||||
|
|
||||||
//Test an address that should work.
|
|
||||||
if addressmanager.TstKnownAddressIsBad(addressmanager.TstNewKnownAddress(minutesOldNa, 2, minutesOld, hoursOld, true, 0)) {
|
|
||||||
t.Errorf("test case 10: This should be a valid address.")
|
|
||||||
}
|
|
||||||
}
|
|
400
infrastructure/network/addressmanager/localaddressmanager.go
Normal file
400
infrastructure/network/addressmanager/localaddressmanager.go
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
package addressmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddressPriority type is used to describe the hierarchy of local address
|
||||||
|
// discovery methods.
|
||||||
|
type AddressPriority int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// InterfacePrio signifies the address is on a local interface
|
||||||
|
InterfacePrio AddressPriority = iota
|
||||||
|
|
||||||
|
// BoundPrio signifies the address has been explicitly bounded to.
|
||||||
|
BoundPrio
|
||||||
|
|
||||||
|
// UpnpPrio signifies the address was obtained from UPnP.
|
||||||
|
UpnpPrio
|
||||||
|
|
||||||
|
// HTTPPrio signifies the address was obtained from an external HTTP service.
|
||||||
|
HTTPPrio
|
||||||
|
|
||||||
|
// ManualPrio signifies the address was provided by --externalip.
|
||||||
|
ManualPrio
|
||||||
|
)
|
||||||
|
|
||||||
|
type localAddress struct {
|
||||||
|
netAddress *appmessage.NetAddress
|
||||||
|
score AddressPriority
|
||||||
|
}
|
||||||
|
|
||||||
|
type localAddressManager struct {
|
||||||
|
localAddresses map[AddressKey]*localAddress
|
||||||
|
lookupFunc func(string) ([]net.IP, error)
|
||||||
|
cfg *Config
|
||||||
|
mutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLocalAddressManager(cfg *Config) (*localAddressManager, error) {
|
||||||
|
localAddressManager := localAddressManager{
|
||||||
|
localAddresses: map[AddressKey]*localAddress{},
|
||||||
|
cfg: cfg,
|
||||||
|
lookupFunc: cfg.Lookup,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := localAddressManager.initListeners()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &localAddressManager, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addLocalNetAddress adds netAddress to the list of known local addresses to advertise
|
||||||
|
// with the given priority.
|
||||||
|
func (lam *localAddressManager) addLocalNetAddress(netAddress *appmessage.NetAddress, priority AddressPriority) error {
|
||||||
|
if !IsRoutable(netAddress, lam.cfg.AcceptUnroutable) {
|
||||||
|
return errors.Errorf("address %s is not routable", netAddress.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
lam.mutex.Lock()
|
||||||
|
defer lam.mutex.Unlock()
|
||||||
|
|
||||||
|
addressKey := netAddressKey(netAddress)
|
||||||
|
address, ok := lam.localAddresses[addressKey]
|
||||||
|
if !ok || address.score < priority {
|
||||||
|
if ok {
|
||||||
|
address.score = priority + 1
|
||||||
|
} else {
|
||||||
|
lam.localAddresses[addressKey] = &localAddress{
|
||||||
|
netAddress: netAddress,
|
||||||
|
score: priority,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bestLocalAddress returns the most appropriate local address to use
|
||||||
|
// for the given remote address.
|
||||||
|
func (lam *localAddressManager) bestLocalAddress(remoteAddress *appmessage.NetAddress) *appmessage.NetAddress {
|
||||||
|
lam.mutex.Lock()
|
||||||
|
defer lam.mutex.Unlock()
|
||||||
|
|
||||||
|
bestReach := 0
|
||||||
|
var bestScore AddressPriority
|
||||||
|
var bestAddress *appmessage.NetAddress
|
||||||
|
for _, localAddress := range lam.localAddresses {
|
||||||
|
reach := reachabilityFrom(localAddress.netAddress, remoteAddress, lam.cfg.AcceptUnroutable)
|
||||||
|
if reach > bestReach ||
|
||||||
|
(reach == bestReach && localAddress.score > bestScore) {
|
||||||
|
bestReach = reach
|
||||||
|
bestScore = localAddress.score
|
||||||
|
bestAddress = localAddress.netAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bestAddress == nil {
|
||||||
|
// Send something unroutable if nothing suitable.
|
||||||
|
var ip net.IP
|
||||||
|
if !IsIPv4(remoteAddress) {
|
||||||
|
ip = net.IPv6zero
|
||||||
|
} else {
|
||||||
|
ip = net.IPv4zero
|
||||||
|
}
|
||||||
|
services := appmessage.SFNodeNetwork | appmessage.SFNodeBloom
|
||||||
|
bestAddress = appmessage.NewNetAddressIPPort(ip, 0, services)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
// addLocalAddress adds an address that this node is listening on to the
|
||||||
|
// address manager so that it may be relayed to peers.
|
||||||
|
func (lam *localAddressManager) addLocalAddress(addr string) error {
|
||||||
|
host, portStr, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
port, err := strconv.ParseUint(portStr, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip := net.ParseIP(host); ip != nil && ip.IsUnspecified() {
|
||||||
|
// If bound to unspecified address, advertise all local interfaces
|
||||||
|
addrs, err := net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ifaceIP, _, err := net.ParseCIDR(addr.String())
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If bound to 0.0.0.0, do not add IPv6 interfaces and if bound to
|
||||||
|
// ::, do not add IPv4 interfaces.
|
||||||
|
if (ip.To4() == nil) != (ifaceIP.To4() == nil) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
netAddr := appmessage.NewNetAddressIPPort(ifaceIP, uint16(port), appmessage.DefaultServices)
|
||||||
|
lam.addLocalNetAddress(netAddr, BoundPrio)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
netAddr, err := lam.hostToNetAddress(host, uint16(port), appmessage.DefaultServices)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
lam.addLocalNetAddress(netAddr, BoundPrio)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// initListeners initializes the configured net listeners and adds any bound
|
||||||
|
// addresses to the address manager
|
||||||
|
func (lam *localAddressManager) initListeners() error {
|
||||||
|
if len(lam.cfg.ExternalIPs) != 0 {
|
||||||
|
defaultPort, err := strconv.ParseUint(lam.cfg.DefaultPort, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Can not parse default port %s for active DAG: %s",
|
||||||
|
lam.cfg.DefaultPort, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sip := range lam.cfg.ExternalIPs {
|
||||||
|
eport := uint16(defaultPort)
|
||||||
|
host, portstr, err := net.SplitHostPort(sip)
|
||||||
|
if err != nil {
|
||||||
|
// no port, use default.
|
||||||
|
host = sip
|
||||||
|
} else {
|
||||||
|
port, err := strconv.ParseUint(portstr, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Can not parse port from %s for "+
|
||||||
|
"externalip: %s", sip, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
eport = uint16(port)
|
||||||
|
}
|
||||||
|
na, err := lam.hostToNetAddress(host, eport, appmessage.DefaultServices)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Not adding %s as externalip: %s", sip, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = lam.addLocalNetAddress(na, ManualPrio)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Skipping specified external IP: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Listen for TCP connections at the configured addresses
|
||||||
|
netAddrs, err := parseListeners(lam.cfg.Listeners)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add bound addresses to address manager to be advertised to peers.
|
||||||
|
for _, addr := range netAddrs {
|
||||||
|
listener, err := net.Listen(addr.Network(), addr.String())
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Can't listen on %s: %s", addr, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr := listener.Addr().String()
|
||||||
|
err = listener.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = lam.addLocalAddress(addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Skipping bound address %s: %s", addr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hostToNetAddress returns a netaddress given a host address. If
|
||||||
|
// the host is not an IP address it will be resolved.
|
||||||
|
func (lam *localAddressManager) hostToNetAddress(host string, port uint16, services appmessage.ServiceFlag) (*appmessage.NetAddress, error) {
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip == nil {
|
||||||
|
ips, err := lam.lookupFunc(host)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(ips) == 0 {
|
||||||
|
return nil, errors.Errorf("no addresses found for %s", host)
|
||||||
|
}
|
||||||
|
ip = ips[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return appmessage.NewNetAddressIPPort(ip, port, services), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseListeners determines whether each listen address is IPv4 and IPv6 and
|
||||||
|
// returns a slice of appropriate net.Addrs to listen on with TCP. It also
|
||||||
|
// properly detects addresses which apply to "all interfaces" and adds the
|
||||||
|
// address as both IPv4 and IPv6.
|
||||||
|
func parseListeners(addrs []string) ([]net.Addr, error) {
|
||||||
|
netAddrs := make([]net.Addr, 0, len(addrs)*2)
|
||||||
|
for _, addr := range addrs {
|
||||||
|
host, _, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
// Shouldn't happen due to already being normalized.
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty host or host of * on plan9 is both IPv4 and IPv6.
|
||||||
|
if host == "" || (host == "*" && runtime.GOOS == "plan9") {
|
||||||
|
netAddrs = append(netAddrs, simpleAddr{net: "tcp4", addr: addr})
|
||||||
|
netAddrs = append(netAddrs, simpleAddr{net: "tcp6", addr: addr})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip IPv6 zone id if present since net.ParseIP does not
|
||||||
|
// handle it.
|
||||||
|
zoneIndex := strings.LastIndex(host, "%")
|
||||||
|
if zoneIndex > 0 {
|
||||||
|
host = host[:zoneIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the IP.
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip == nil {
|
||||||
|
hostAddrs, err := net.LookupHost(host)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ip = net.ParseIP(hostAddrs[0])
|
||||||
|
if ip == nil {
|
||||||
|
return nil, errors.Errorf("Cannot resolve IP address for host '%s'", host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To4 returns nil when the IP is not an IPv4 address, so use
|
||||||
|
// this determine the address type.
|
||||||
|
if ip.To4() == nil {
|
||||||
|
netAddrs = append(netAddrs, simpleAddr{net: "tcp6", addr: addr})
|
||||||
|
} else {
|
||||||
|
netAddrs = append(netAddrs, simpleAddr{net: "tcp4", addr: addr})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return netAddrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// reachabilityFrom returns the relative reachability of the provided local
|
||||||
|
// address to the provided remote address.
|
||||||
|
func reachabilityFrom(localAddress, remoteAddress *appmessage.NetAddress, acceptUnroutable bool) int {
|
||||||
|
const (
|
||||||
|
Unreachable = 0
|
||||||
|
Default = iota
|
||||||
|
Teredo
|
||||||
|
Ipv6Weak
|
||||||
|
Ipv4
|
||||||
|
Ipv6Strong
|
||||||
|
Private
|
||||||
|
)
|
||||||
|
|
||||||
|
IsRoutable := func(na *appmessage.NetAddress) bool {
|
||||||
|
if acceptUnroutable {
|
||||||
|
return !IsLocal(na)
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsValid(na) && !(IsRFC1918(na) || IsRFC2544(na) ||
|
||||||
|
IsRFC3927(na) || IsRFC4862(na) || IsRFC3849(na) ||
|
||||||
|
IsRFC4843(na) || IsRFC5737(na) || IsRFC6598(na) ||
|
||||||
|
IsLocal(na) || (IsRFC4193(na)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !IsRoutable(remoteAddress) {
|
||||||
|
return Unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsRFC4380(remoteAddress) {
|
||||||
|
if !IsRoutable(localAddress) {
|
||||||
|
return Default
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsRFC4380(localAddress) {
|
||||||
|
return Teredo
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsIPv4(localAddress) {
|
||||||
|
return Ipv4
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ipv6Weak
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsIPv4(remoteAddress) {
|
||||||
|
if IsRoutable(localAddress) && IsIPv4(localAddress) {
|
||||||
|
return Ipv4
|
||||||
|
}
|
||||||
|
return Unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ipv6 */
|
||||||
|
var tunnelled bool
|
||||||
|
// Is our v6 is tunnelled?
|
||||||
|
if IsRFC3964(localAddress) || IsRFC6052(localAddress) || IsRFC6145(localAddress) {
|
||||||
|
tunnelled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !IsRoutable(localAddress) {
|
||||||
|
return Default
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsRFC4380(localAddress) {
|
||||||
|
return Teredo
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsIPv4(localAddress) {
|
||||||
|
return Ipv4
|
||||||
|
}
|
||||||
|
|
||||||
|
if tunnelled {
|
||||||
|
// only prioritise ipv6 if we aren't tunnelling it.
|
||||||
|
return Ipv6Weak
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ipv6Strong
|
||||||
|
}
|
||||||
|
|
||||||
|
// simpleAddr implements the net.Addr interface with two struct fields
|
||||||
|
type simpleAddr struct {
|
||||||
|
net, addr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the address.
|
||||||
|
//
|
||||||
|
// This is part of the net.Addr interface.
|
||||||
|
func (a simpleAddr) String() string {
|
||||||
|
return a.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network returns the network.
|
||||||
|
//
|
||||||
|
// This is part of the net.Addr interface.
|
||||||
|
func (a simpleAddr) Network() string {
|
||||||
|
return a.net
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure simpleAddr implements the net.Addr interface.
|
||||||
|
var _ net.Addr = simpleAddr{}
|
@ -5,8 +5,9 @@
|
|||||||
package addressmanager
|
package addressmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -77,6 +78,13 @@ var (
|
|||||||
heNet = ipNet("2001:470::", 32, 128)
|
heNet = ipNet("2001:470::", 32, 128)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// GetAddressesMax is the most addresses that we will send in response
|
||||||
|
// to a getAddress (in practise the most addresses we will return from a
|
||||||
|
// call to AddressCache()).
|
||||||
|
GetAddressesMax = 2500
|
||||||
|
)
|
||||||
|
|
||||||
// ipNet returns a net.IPNet struct given the passed IP address string, number
|
// ipNet returns a net.IPNet struct given the passed IP address string, number
|
||||||
// of one bits to include at the start of the mask, and the total number of bits
|
// of one bits to include at the start of the mask, and the total number of bits
|
||||||
// for the mask.
|
// for the mask.
|
||||||
@ -199,8 +207,8 @@ func IsValid(na *appmessage.NetAddress) bool {
|
|||||||
// IsRoutable returns whether or not the passed address is routable over
|
// IsRoutable returns whether or not the passed address is routable over
|
||||||
// the public internet. This is true as long as the address is valid and is not
|
// the public internet. This is true as long as the address is valid and is not
|
||||||
// in any reserved ranges.
|
// in any reserved ranges.
|
||||||
func (am *AddressManager) IsRoutable(na *appmessage.NetAddress) bool {
|
func IsRoutable(na *appmessage.NetAddress, acceptUnroutable bool) bool {
|
||||||
if am.cfg.NetParams().AcceptUnroutable {
|
if acceptUnroutable {
|
||||||
return !IsLocal(na)
|
return !IsLocal(na)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +226,7 @@ func (am *AddressManager) GroupKey(na *appmessage.NetAddress) string {
|
|||||||
if IsLocal(na) {
|
if IsLocal(na) {
|
||||||
return "local"
|
return "local"
|
||||||
}
|
}
|
||||||
if !am.IsRoutable(na) {
|
if !IsRoutable(na, am.cfg.AcceptUnroutable) {
|
||||||
return "unroutable"
|
return "unroutable"
|
||||||
}
|
}
|
||||||
if IsIPv4(na) {
|
if IsIPv4(na) {
|
||||||
|
@ -5,15 +5,16 @@
|
|||||||
package addressmanager
|
package addressmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestIPTypes ensures the various functions which determine the type of an IP
|
// TestIPTypes ensures the various functions which determine the type of an IP
|
||||||
// address based on RFCs work as intended.
|
// address based on RFCs work as intended.
|
||||||
func TestIPTypes(t *testing.T) {
|
func TestIPTypes(t *testing.T) {
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP", nil)
|
amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP")
|
||||||
defer teardown()
|
defer teardown()
|
||||||
type ipTest struct {
|
type ipTest struct {
|
||||||
in appmessage.NetAddress
|
in appmessage.NetAddress
|
||||||
@ -136,7 +137,7 @@ func TestIPTypes(t *testing.T) {
|
|||||||
t.Errorf("IsValid %s\n got: %v want: %v", test.in.IP, rv, test.valid)
|
t.Errorf("IsValid %s\n got: %v want: %v", test.in.IP, rv, test.valid)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rv := amgr.IsRoutable(&test.in); rv != test.routable {
|
if rv := IsRoutable(&test.in, amgr.cfg.AcceptUnroutable); rv != test.routable {
|
||||||
t.Errorf("IsRoutable %s\n got: %v want: %v", test.in.IP, rv, test.routable)
|
t.Errorf("IsRoutable %s\n got: %v want: %v", test.in.IP, rv, test.routable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,7 +146,7 @@ func TestIPTypes(t *testing.T) {
|
|||||||
// TestGroupKey tests the GroupKey function to ensure it properly groups various
|
// TestGroupKey tests the GroupKey function to ensure it properly groups various
|
||||||
// IP addresses.
|
// IP addresses.
|
||||||
func TestGroupKey(t *testing.T) {
|
func TestGroupKey(t *testing.T) {
|
||||||
amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP", nil)
|
amgr, teardown := newAddrManagerForTest(t, "TestAddAddressByIP")
|
||||||
defer teardown()
|
defer teardown()
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package addressmanager
|
package addressmanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddAddressByIP adds an address where we are given an ip:port and not a
|
// AddAddressByIP adds an address where we are given an ip:port and not a
|
||||||
@ -26,6 +27,6 @@ func AddAddressByIP(am *AddressManager, addressIP string, subnetworkID *subnetwo
|
|||||||
return errors.Errorf("invalid port %s: %s", portString, err)
|
return errors.Errorf("invalid port %s: %s", portString, err)
|
||||||
}
|
}
|
||||||
netAddress := appmessage.NewNetAddressIPPort(ip, uint16(port), 0)
|
netAddress := appmessage.NewNetAddressIPPort(ip, uint16(port), 0)
|
||||||
am.AddAddress(netAddress, netAddress, subnetworkID)
|
am.AddAddresses(netAddress)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package connmanager
|
package connmanager
|
||||||
|
|
||||||
|
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
|
||||||
// checkOutgoingConnections goes over all activeOutgoing and makes sure they are still active.
|
// checkOutgoingConnections goes over all activeOutgoing and makes sure they are still active.
|
||||||
// Then it opens connections so that we have targetOutgoing active connections
|
// Then it opens connections so that we have targetOutgoing active connections
|
||||||
func (c *ConnectionManager) checkOutgoingConnections(connSet connectionSet) {
|
func (c *ConnectionManager) checkOutgoingConnections(connSet connectionSet) {
|
||||||
@ -14,6 +16,12 @@ func (c *ConnectionManager) checkOutgoingConnections(connSet connectionSet) {
|
|||||||
delete(c.activeOutgoing, address)
|
delete(c.activeOutgoing, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connections := c.netAdapter.P2PConnections()
|
||||||
|
connectedAddresses := make([]*appmessage.NetAddress, len(connections))
|
||||||
|
for i, connection := range connections {
|
||||||
|
connectedAddresses[i] = connection.NetAddress()
|
||||||
|
}
|
||||||
|
|
||||||
liveConnections := len(c.activeOutgoing)
|
liveConnections := len(c.activeOutgoing)
|
||||||
if c.targetOutgoing == liveConnections {
|
if c.targetOutgoing == liveConnections {
|
||||||
return
|
return
|
||||||
@ -23,47 +31,21 @@ func (c *ConnectionManager) checkOutgoingConnections(connSet connectionSet) {
|
|||||||
liveConnections, c.targetOutgoing, c.targetOutgoing-liveConnections)
|
liveConnections, c.targetOutgoing, c.targetOutgoing-liveConnections)
|
||||||
|
|
||||||
connectionsNeededCount := c.targetOutgoing - len(c.activeOutgoing)
|
connectionsNeededCount := c.targetOutgoing - len(c.activeOutgoing)
|
||||||
connectionAttempts := connectionsNeededCount * 2
|
netAddresses := c.addressManager.RandomAddresses(connectionsNeededCount, connectedAddresses)
|
||||||
for i := 0; i < connectionAttempts; i++ {
|
|
||||||
// Return in case we've already reached or surpassed our target
|
|
||||||
if len(c.activeOutgoing) >= c.targetOutgoing {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
address := c.addressManager.GetAddress()
|
for _, netAddress := range netAddresses {
|
||||||
if address == nil {
|
addressString := netAddress.TCPAddress().String()
|
||||||
log.Warnf("No more addresses available")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
netAddress := address.NetAddress()
|
|
||||||
tcpAddress := netAddress.TCPAddress()
|
|
||||||
addressString := tcpAddress.String()
|
|
||||||
|
|
||||||
if c.connectionExists(addressString) {
|
|
||||||
log.Debugf("Fetched address %s from address manager but it's already connected. Skipping...", addressString)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
isBanned, err := c.addressManager.IsBanned(netAddress)
|
|
||||||
if err != nil {
|
|
||||||
log.Infof("Couldn't resolve whether %s is banned: %s", addressString, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if isBanned {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
c.addressManager.Attempt(netAddress)
|
|
||||||
log.Debugf("Connecting to %s because we have %d outgoing connections and the target is "+
|
log.Debugf("Connecting to %s because we have %d outgoing connections and the target is "+
|
||||||
"%d", addressString, len(c.activeOutgoing), c.targetOutgoing)
|
"%d", addressString, len(c.activeOutgoing), c.targetOutgoing)
|
||||||
err = c.initiateConnection(addressString)
|
|
||||||
|
err := c.initiateConnection(addressString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Infof("Couldn't connect to %s: %s", addressString, err)
|
log.Infof("Couldn't connect to %s: %s", addressString, err)
|
||||||
|
c.addressManager.RemoveAddress(netAddress)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
c.addressManager.Connected(netAddress)
|
|
||||||
c.activeOutgoing[addressString] = struct{}{}
|
c.activeOutgoing[addressString] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -74,6 +74,8 @@ message KaspadMessage {
|
|||||||
GetMempoolEntriesResponseMessage getMempoolEntriesResponse = 1044;
|
GetMempoolEntriesResponseMessage getMempoolEntriesResponse = 1044;
|
||||||
ShutDownRequestMessage shutDownRequest = 1045;
|
ShutDownRequestMessage shutDownRequest = 1045;
|
||||||
ShutDownResponseMessage shutDownResponse = 1046;
|
ShutDownResponseMessage shutDownResponse = 1046;
|
||||||
|
GetHeadersRequestMessage getHeadersRequest = 10347;
|
||||||
|
GetHeadersResponseMessage getHeadersResponse = 1048;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,6 +352,7 @@ message GetPeerAddressesRequestMessage{
|
|||||||
|
|
||||||
message GetPeerAddressesResponseMessage{
|
message GetPeerAddressesResponseMessage{
|
||||||
repeated GetPeerAddressesKnownAddressMessage addresses = 1;
|
repeated GetPeerAddressesKnownAddressMessage addresses = 1;
|
||||||
|
repeated GetPeerAddressesKnownAddressMessage bannedAddresses = 2;
|
||||||
RPCError error = 1000;
|
RPCError error = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,6 +624,17 @@ message ShutDownResponseMessage{
|
|||||||
RPCError error = 1000;
|
RPCError error = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetHeadersRequestMessage{
|
||||||
|
string startHash = 1;
|
||||||
|
uint64 limit = 2;
|
||||||
|
bool isAscending = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetHeadersResponseMessage{
|
||||||
|
repeated string headers = 1;
|
||||||
|
RPCError error = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
service RPC {
|
service RPC {
|
||||||
rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {}
|
rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package protowire
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x *KaspadMessage_GetHeadersRequest) toAppMessage() (appmessage.Message, error) {
|
||||||
|
return &appmessage.GetHeadersRequestMessage{
|
||||||
|
StartHash: x.GetHeadersRequest.StartHash,
|
||||||
|
Limit: x.GetHeadersRequest.Limit,
|
||||||
|
IsAscending: x.GetHeadersRequest.IsAscending,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *KaspadMessage_GetHeadersRequest) fromAppMessage(message *appmessage.GetHeadersRequestMessage) error {
|
||||||
|
x.GetHeadersRequest = &GetHeadersRequestMessage{
|
||||||
|
StartHash: message.StartHash,
|
||||||
|
Limit: message.Limit,
|
||||||
|
IsAscending: message.IsAscending,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *KaspadMessage_GetHeadersResponse) toAppMessage() (appmessage.Message, error) {
|
||||||
|
var err *appmessage.RPCError
|
||||||
|
if x.GetHeadersResponse.Error != nil {
|
||||||
|
err = &appmessage.RPCError{Message: x.GetHeadersResponse.Error.Message}
|
||||||
|
}
|
||||||
|
return &appmessage.GetHeadersResponseMessage{
|
||||||
|
Headers: x.GetHeadersResponse.Headers,
|
||||||
|
Error: err,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *KaspadMessage_GetHeadersResponse) fromAppMessage(message *appmessage.GetHeadersResponseMessage) error {
|
||||||
|
var err *RPCError
|
||||||
|
if message.Error != nil {
|
||||||
|
err = &RPCError{Message: message.Error.Message}
|
||||||
|
}
|
||||||
|
x.GetHeadersResponse = &GetHeadersResponseMessage{
|
||||||
|
Headers: message.Headers,
|
||||||
|
Error: err,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -19,9 +19,14 @@ func (x *KaspadMessage_GetPeerAddressesResponse) toAppMessage() (appmessage.Mess
|
|||||||
for i, address := range x.GetPeerAddressesResponse.Addresses {
|
for i, address := range x.GetPeerAddressesResponse.Addresses {
|
||||||
addresses[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: address.Addr}
|
addresses[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: address.Addr}
|
||||||
}
|
}
|
||||||
|
bannedAddresses := make([]*appmessage.GetPeerAddressesKnownAddressMessage, len(x.GetPeerAddressesResponse.BannedAddresses))
|
||||||
|
for i, address := range x.GetPeerAddressesResponse.BannedAddresses {
|
||||||
|
bannedAddresses[i] = &appmessage.GetPeerAddressesKnownAddressMessage{Addr: address.Addr}
|
||||||
|
}
|
||||||
return &appmessage.GetPeerAddressesResponseMessage{
|
return &appmessage.GetPeerAddressesResponseMessage{
|
||||||
Addresses: addresses,
|
Addresses: addresses,
|
||||||
Error: err,
|
BannedAddresses: bannedAddresses,
|
||||||
|
Error: err,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,9 +39,14 @@ func (x *KaspadMessage_GetPeerAddressesResponse) fromAppMessage(message *appmess
|
|||||||
for i, address := range message.Addresses {
|
for i, address := range message.Addresses {
|
||||||
addresses[i] = &GetPeerAddressesKnownAddressMessage{Addr: address.Addr}
|
addresses[i] = &GetPeerAddressesKnownAddressMessage{Addr: address.Addr}
|
||||||
}
|
}
|
||||||
|
bannedAddresses := make([]*GetPeerAddressesKnownAddressMessage, len(message.BannedAddresses))
|
||||||
|
for i, address := range message.BannedAddresses {
|
||||||
|
bannedAddresses[i] = &GetPeerAddressesKnownAddressMessage{Addr: address.Addr}
|
||||||
|
}
|
||||||
x.GetPeerAddressesResponse = &GetPeerAddressesResponseMessage{
|
x.GetPeerAddressesResponse = &GetPeerAddressesResponseMessage{
|
||||||
Addresses: addresses,
|
Addresses: addresses,
|
||||||
Error: err,
|
BannedAddresses: bannedAddresses,
|
||||||
|
Error: err,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -534,6 +534,20 @@ func toRPCPayload(message appmessage.Message) (isKaspadMessage_Payload, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return payload, nil
|
return payload, nil
|
||||||
|
case *appmessage.GetHeadersRequestMessage:
|
||||||
|
payload := new(KaspadMessage_GetHeadersRequest)
|
||||||
|
err := payload.fromAppMessage(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return payload, nil
|
||||||
|
case *appmessage.GetHeadersResponseMessage:
|
||||||
|
payload := new(KaspadMessage_GetHeadersResponse)
|
||||||
|
err := payload.fromAppMessage(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return payload, nil
|
||||||
default:
|
default:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
20
infrastructure/network/rpcclient/rpc_get_headers.go
Normal file
20
infrastructure/network/rpcclient/rpc_get_headers.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package rpcclient
|
||||||
|
|
||||||
|
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
|
||||||
|
// GetHeaders sends an RPC request respective to the function's name and returns the RPC server's response
|
||||||
|
func (c *RPCClient) GetHeaders(startHash string, limit uint64, isAscending bool) (*appmessage.GetHeadersResponseMessage, error) {
|
||||||
|
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetHeadersRequestMessage(startHash, limit, isAscending))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response, err := c.route(appmessage.CmdGetHeadersResponseMessage).DequeueWithTimeout(c.timeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
getHeadersResponse := response.(*appmessage.GetHeadersResponseMessage)
|
||||||
|
if getHeadersResponse.Error != nil {
|
||||||
|
return nil, c.convertRPCError(getHeadersResponse.Error)
|
||||||
|
}
|
||||||
|
return getHeadersResponse, nil
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAddressExchange(t *testing.T) {
|
func TestAddressExchange(t *testing.T) {
|
||||||
|
@ -19,12 +19,12 @@ const HashSize = 32
|
|||||||
// TxIDSize of array used to store TxID. See TxID.
|
// TxIDSize of array used to store TxID. See TxID.
|
||||||
const TxIDSize = HashSize
|
const TxIDSize = HashSize
|
||||||
|
|
||||||
// MaxHashStringSize is the maximum length of a Hash hash string.
|
// HashStringSize is the length of a Hash hash string.
|
||||||
const MaxHashStringSize = HashSize * 2
|
const HashStringSize = HashSize * 2
|
||||||
|
|
||||||
// ErrHashStrSize describes an error that indicates the caller specified a hash
|
// ErrHashStrSize describes an error that indicates the caller specified a hash
|
||||||
// string that has too many characters.
|
// string that hasn't the correct number of characters.
|
||||||
var ErrHashStrSize = errors.Errorf("max hash string length is %d bytes", MaxHashStringSize)
|
var ErrHashStrSize = errors.Errorf("hash string length should be %d bytes", HashStringSize)
|
||||||
|
|
||||||
// Hash is used in several of the kaspa messages and common structures. It
|
// Hash is used in several of the kaspa messages and common structures. It
|
||||||
// typically represents the double sha256 of data.
|
// typically represents the double sha256 of data.
|
||||||
@ -172,7 +172,7 @@ func NewTxIDFromStr(idStr string) (*TxID, error) {
|
|||||||
// destination.
|
// destination.
|
||||||
func Decode(dst *Hash, src string) error {
|
func Decode(dst *Hash, src string) error {
|
||||||
// Return error if hash string is too long.
|
// Return error if hash string is too long.
|
||||||
if len(src) > MaxHashStringSize {
|
if len(src) != HashStringSize {
|
||||||
return ErrHashStrSize
|
return ErrHashStrSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ var mainnetGenesisHash = Hash([HashSize]byte{
|
|||||||
// TestHash tests the Hash API.
|
// TestHash tests the Hash API.
|
||||||
func TestHash(t *testing.T) {
|
func TestHash(t *testing.T) {
|
||||||
// Hash of block 234439.
|
// Hash of block 234439.
|
||||||
blockHashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef"
|
blockHashStr := "d2f0fb908b59cd20d8687fadca033495d355dccf7718d50e2f9b4826a1f853a8"
|
||||||
blockHash, err := NewHashFromStr(blockHashStr)
|
blockHash, err := NewHashFromStr(blockHashStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("NewHashFromStr: %v", err)
|
t.Errorf("NewHashFromStr: %v", err)
|
||||||
@ -158,42 +158,25 @@ func TestNewHashFromStr(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Genesis hash with stripped leading zeros.
|
|
||||||
{
|
|
||||||
"63bbcfdd699ffd8cb19878564b14d3af8ba4d7ee4d1dd54925a7c21d5b5b5fdc",
|
|
||||||
mainnetGenesisHash,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Empty string.
|
// Empty string.
|
||||||
{
|
{
|
||||||
"",
|
"",
|
||||||
Hash{},
|
Hash{},
|
||||||
nil,
|
ErrHashStrSize,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Single digit hash.
|
// Single digit hash.
|
||||||
{
|
{
|
||||||
"1",
|
"1",
|
||||||
Hash([HashSize]byte{
|
Hash{},
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
ErrHashStrSize,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
}),
|
|
||||||
nil,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Block 203707 with stripped leading zeros.
|
// Block 203707 with stripped leading zeros.
|
||||||
{
|
{
|
||||||
"3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc",
|
"3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc",
|
||||||
Hash([HashSize]byte{
|
Hash{},
|
||||||
0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7,
|
ErrHashStrSize,
|
||||||
0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b,
|
|
||||||
0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b,
|
|
||||||
0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
}),
|
|
||||||
nil,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Hash string that is too long.
|
// Hash string that is too long.
|
||||||
@ -205,7 +188,7 @@ func TestNewHashFromStr(t *testing.T) {
|
|||||||
|
|
||||||
// Hash string that is contains non-hex chars.
|
// Hash string that is contains non-hex chars.
|
||||||
{
|
{
|
||||||
"abcdefg",
|
"abcdefgggggggggggggggggggggggggggggggggggggggggggggggggggggggggg",
|
||||||
Hash{},
|
Hash{},
|
||||||
hex.InvalidByteError('g'),
|
hex.InvalidByteError('g'),
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user