mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00

* [NOD-1125] Write a skeleton for starting IBD. * [NOD-1125] Add WaitForIBDStart to Peer. * [NOD-1125] Move functions around. * [NOD-1125] Fix merge errors. * [NOD-1125] Fix a comment. * [NOD-1125] Implement sendGetBlockLocator. * [NOD-1125] Begin implementing findIBDLowHash. * [NOD-1125] Finish implementing findIBDLowHash. * [NOD-1125] Rename findIBDLowHash to findHighestSharedBlockHash. * [NOD-1125] Implement downloadBlocks. * [NOD-1125] Implement msgIBDBlock. * [NOD-1125] Implement msgIBDBlock. * [NOD-1125] Fix message types for HandleIBD. * [NOD-1125] Write a skeleton for requesting selected tip hashes. * [NOD-1125] Write a skeleton for the rest of the IBD requests. * [NOD-1125] Implement HandleGetBlockLocator. * [NOD-1125] Fix wrong timeout. * [NOD-1125] Fix compilation error. * [NOD-1125] Implement HandleGetBlocks. * [NOD-1125] Fix compilation errors. * [NOD-1125] Fix merge errors. * [NOD-1125] Implement selectPeerForIBD. * [NOD-1125] Implement RequestSelectedTip. * [NOD-1125] Implement HandleGetSelectedTip. * [NOD-1125] Make go lint happy. * [NOD-1125] Add minGetSelectedTipInterval. * [NOD-1125] Call StartIBDIfRequired where needed. * [NOD-1125] Fix merge errors. * [NOD-1125] Remove a redundant line. * [NOD-1125] Rename shouldContinue to shouldStop. * [NOD-1125] Lowercasify an error message. * [NOD-1125] Shuffle statements around in findHighestSharedBlockHash. * [NOD-1125] Rename hasRecentlyReceivedBlock to isDAGTimeCurrent. * [NOD-1125] Scope minGetSelectedTipInterval. * [NOD-1125] Handle an unhandled error. * [NOD-1125] Use AddUint32 instead of LoadUint32 + StoreUint32. * [NOD-1125] Use AddUint32 instead of LoadUint32 + StoreUint32. * [NOD-1125] Use SwapUint32 instead of AddUint32. * [NOD-1125] Remove error from requestSelectedTips. * [NOD-1125] Actually stop IBD when it should stop. * [NOD-1125] Actually stop RequestSelectedTip when it should stop. * [NOD-1125] Don't ban peers that send us delayed blocks during IBD. * [NOD-1125] Make unexpected message type messages nicer. * [NOD-1125] Remove Peer.ready and make HandleHandshake return it to guarantee we never operate on a non-initialized peer. * [NOD-1125] Remove errors associated with Peer.ready. * [NOD-1125] Extract maxHashesInMsgIBDBlocks to a const. * [NOD-1125] Move the ibd package into flows. * [NOD-1125] Start IBD if required after getting an unknown block inv. * [NOD-1125] Don't request blocks during relay if we're in the middle of IBD. * [NOD-1125] Remove AddBlockLocatorHash. * [NOD-1125] Extract runIBD to a seperate function. * [NOD-1125] Extract runSelectedTipRequest to a seperate function. * [NOD-1125] Remove EnqueueWithTimeout. * [NOD-1125] Increase the capacity of the outgoingRoute. * [NOD-1125] Fix some bad names. * [NOD-1125] Fix a comment. * [NOD-1125] Simplify a comment. * [NOD-1125] Move WaitFor... functions into their respective run... functions. * [NOD-1125] Return default values in case of error. * [NOD-1125] Use CmdXXX in error messages. * [NOD-1125] Use MaxInvPerMsg in outgoingRouteMaxMessages instead of MaxBlockLocatorsPerMsg. * [NOD-1125] Fix a comment. * [NOD-1125] Disconnect a peer that sends us a delayed block during IBD. * [NOD-1125] Use StoreUint32 instead of SwapUint32. * [NOD-1125] Add a comment. * [NOD-1125] Don't ban peers that send us delayed blocks.
217 lines
6.6 KiB
Go
217 lines
6.6 KiB
Go
package protocol
|
|
|
|
import (
|
|
"sync/atomic"
|
|
|
|
"github.com/kaspanet/kaspad/protocol/flows/handshake"
|
|
|
|
"github.com/kaspanet/kaspad/protocol/flows/addressexchange"
|
|
"github.com/kaspanet/kaspad/protocol/flows/blockrelay"
|
|
|
|
"github.com/kaspanet/kaspad/addrmgr"
|
|
"github.com/kaspanet/kaspad/blockdag"
|
|
"github.com/kaspanet/kaspad/netadapter"
|
|
routerpkg "github.com/kaspanet/kaspad/netadapter/router"
|
|
"github.com/kaspanet/kaspad/protocol/flows/ibd"
|
|
"github.com/kaspanet/kaspad/protocol/flows/ping"
|
|
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
|
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
|
"github.com/kaspanet/kaspad/wire"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// Init initializes the p2p protocol
|
|
func Init(netAdapter *netadapter.NetAdapter, addressManager *addrmgr.AddrManager, dag *blockdag.BlockDAG) {
|
|
routerInitializer := newRouterInitializer(netAdapter, addressManager, dag)
|
|
netAdapter.SetRouterInitializer(routerInitializer)
|
|
}
|
|
|
|
func newRouterInitializer(netAdapter *netadapter.NetAdapter,
|
|
addressManager *addrmgr.AddrManager, dag *blockdag.BlockDAG) netadapter.RouterInitializer {
|
|
return func() (*routerpkg.Router, error) {
|
|
|
|
router := routerpkg.NewRouter()
|
|
spawn(func() {
|
|
err := startFlows(netAdapter, router, dag, addressManager)
|
|
if err != nil {
|
|
if protocolErr := &(protocolerrors.ProtocolError{}); errors.As(err, &protocolErr) {
|
|
if protocolErr.ShouldBan {
|
|
// TODO(libp2p) Ban peer
|
|
panic("unimplemented")
|
|
}
|
|
err = netAdapter.DisconnectAssociatedConnection(router)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return
|
|
}
|
|
if errors.Is(err, routerpkg.ErrTimeout) {
|
|
err = netAdapter.DisconnectAssociatedConnection(router)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return
|
|
}
|
|
panic(err)
|
|
}
|
|
})
|
|
return router, nil
|
|
}
|
|
}
|
|
|
|
func startFlows(netAdapter *netadapter.NetAdapter, router *routerpkg.Router,
|
|
dag *blockdag.BlockDAG, addressManager *addrmgr.AddrManager) error {
|
|
|
|
stop := make(chan error)
|
|
stopped := uint32(0)
|
|
|
|
peer, closed, err := handshake.HandleHandshake(router, netAdapter, dag, addressManager)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if closed {
|
|
return nil
|
|
}
|
|
|
|
addAddressFlows(router, &stopped, stop, peer, addressManager)
|
|
addBlockRelayFlows(netAdapter, router, &stopped, stop, peer, dag)
|
|
addPingFlows(router, &stopped, stop, peer)
|
|
addIBDFlows(router, &stopped, stop, peer, dag)
|
|
|
|
err = <-stop
|
|
return err
|
|
}
|
|
|
|
func addAddressFlows(router *routerpkg.Router, stopped *uint32, stop chan error,
|
|
peer *peerpkg.Peer, addressManager *addrmgr.AddrManager) {
|
|
|
|
outgoingRoute := router.OutgoingRoute()
|
|
|
|
addOneTimeFlow("SendAddresses", router, []wire.MessageCommand{wire.CmdGetAddresses}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) (routeClosed bool, err error) {
|
|
return addressexchange.SendAddresses(incomingRoute, outgoingRoute, addressManager)
|
|
},
|
|
)
|
|
|
|
addOneTimeFlow("ReceiveAddresses", router, []wire.MessageCommand{wire.CmdAddress}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) (routeClosed bool, err error) {
|
|
return addressexchange.ReceiveAddresses(incomingRoute, outgoingRoute, peer, addressManager)
|
|
},
|
|
)
|
|
}
|
|
|
|
func addBlockRelayFlows(netAdapter *netadapter.NetAdapter, router *routerpkg.Router,
|
|
stopped *uint32, stop chan error, peer *peerpkg.Peer, dag *blockdag.BlockDAG) {
|
|
|
|
outgoingRoute := router.OutgoingRoute()
|
|
|
|
addFlow("HandleRelayInvs", router, []wire.MessageCommand{wire.CmdInvRelayBlock, wire.CmdBlock}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return blockrelay.HandleRelayInvs(incomingRoute, outgoingRoute, peer, netAdapter, dag)
|
|
},
|
|
)
|
|
|
|
addFlow("HandleRelayBlockRequests", router, []wire.MessageCommand{wire.CmdGetRelayBlocks}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return blockrelay.HandleRelayBlockRequests(incomingRoute, outgoingRoute, peer, dag)
|
|
},
|
|
)
|
|
}
|
|
|
|
func addPingFlows(router *routerpkg.Router, stopped *uint32, stop chan error, peer *peerpkg.Peer) {
|
|
outgoingRoute := router.OutgoingRoute()
|
|
|
|
addFlow("ReceivePings", router, []wire.MessageCommand{wire.CmdPing}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return ping.ReceivePings(incomingRoute, outgoingRoute)
|
|
},
|
|
)
|
|
|
|
addFlow("SendPings", router, []wire.MessageCommand{wire.CmdPong}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return ping.SendPings(incomingRoute, outgoingRoute, peer)
|
|
},
|
|
)
|
|
}
|
|
|
|
func addIBDFlows(router *routerpkg.Router, stopped *uint32, stop chan error,
|
|
peer *peerpkg.Peer, dag *blockdag.BlockDAG) {
|
|
|
|
outgoingRoute := router.OutgoingRoute()
|
|
|
|
addFlow("HandleIBD", router, []wire.MessageCommand{wire.CmdBlockLocator, wire.CmdIBDBlock}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return ibd.HandleIBD(incomingRoute, outgoingRoute, peer, dag)
|
|
},
|
|
)
|
|
|
|
addFlow("RequestSelectedTip", router, []wire.MessageCommand{wire.CmdSelectedTip}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return ibd.RequestSelectedTip(incomingRoute, outgoingRoute, peer, dag)
|
|
},
|
|
)
|
|
|
|
addFlow("HandleGetSelectedTip", router, []wire.MessageCommand{wire.CmdGetSelectedTip}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return ibd.HandleGetSelectedTip(incomingRoute, outgoingRoute, dag)
|
|
},
|
|
)
|
|
|
|
addFlow("HandleGetBlockLocator", router, []wire.MessageCommand{wire.CmdGetBlockLocator}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return ibd.HandleGetBlockLocator(incomingRoute, outgoingRoute, dag)
|
|
},
|
|
)
|
|
|
|
addFlow("HandleGetBlocks", router, []wire.MessageCommand{wire.CmdGetBlocks}, stopped, stop,
|
|
func(incomingRoute *routerpkg.Route) error {
|
|
return ibd.HandleGetBlocks(incomingRoute, outgoingRoute, dag)
|
|
},
|
|
)
|
|
}
|
|
|
|
func addFlow(name string, router *routerpkg.Router, messageTypes []wire.MessageCommand, stopped *uint32,
|
|
stopChan chan error, flow func(route *routerpkg.Route) error) {
|
|
|
|
route, err := router.AddIncomingRoute(messageTypes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
spawn(func() {
|
|
err := flow(route)
|
|
if err != nil {
|
|
log.Errorf("error from %s flow: %s", name, err)
|
|
}
|
|
if atomic.AddUint32(stopped, 1) == 1 {
|
|
stopChan <- err
|
|
}
|
|
})
|
|
}
|
|
|
|
func addOneTimeFlow(name string, router *routerpkg.Router, messageTypes []wire.MessageCommand, stopped *uint32,
|
|
stopChan chan error, flow func(route *routerpkg.Route) (routeClosed bool, err error)) {
|
|
|
|
route, err := router.AddIncomingRoute(messageTypes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
spawn(func() {
|
|
defer func() {
|
|
err := router.RemoveRoute(messageTypes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}()
|
|
|
|
closed, err := flow(route)
|
|
if err != nil {
|
|
log.Errorf("error from %s flow: %s", name, err)
|
|
}
|
|
if (err != nil || closed) && atomic.AddUint32(stopped, 1) == 1 {
|
|
stopChan <- err
|
|
}
|
|
})
|
|
}
|