discovery: use a no-op hash accumluator for local networks

If LND is running on a local network, then use deterministic sampling so
that we can have deterministic peer bootstrapping.
This commit is contained in:
Elle Mouton
2025-06-29 16:33:44 +02:00
parent 339dd0c1a7
commit 37d6390642
3 changed files with 51 additions and 8 deletions

View File

@@ -138,13 +138,26 @@ var _ NetworkPeerBootstrapper = (*ChannelGraphBootstrapper)(nil)
// backed by an active autopilot.ChannelGraph instance. This type of network
// peer bootstrapper will use the authenticated nodes within the known channel
// graph to bootstrap connections.
func NewGraphBootstrapper(cg autopilot.ChannelGraph) (NetworkPeerBootstrapper,
error) {
func NewGraphBootstrapper(cg autopilot.ChannelGraph,
deterministicSampling bool) (NetworkPeerBootstrapper, error) {
hashAccumulator, err := newRandomHashAccumulator()
if err != nil {
return nil, fmt.Errorf("unable to create hash accumulator: %w",
err)
var (
hashAccumulator hashAccumulator
err error
)
if deterministicSampling {
// If we're using deterministic sampling, then we'll use a
// no-op hash accumulator that will always return false for
// skipNode.
hashAccumulator = newNoOpHashAccumulator()
} else {
// Otherwise, we'll use a random hash accumulator to sample
// nodes from the channel graph.
hashAccumulator, err = newRandomHashAccumulator()
if err != nil {
return nil, fmt.Errorf("unable to create hash "+
"accumulator: %w", err)
}
}
return &ChannelGraphBootstrapper{
@@ -602,3 +615,29 @@ func (r *randomHashAccumulator) rotate() {
func (r *randomHashAccumulator) skipNode(pub route.Vertex) bool {
return bytes.Compare(r.hash[:], pub[1:]) > 0
}
// noOpHashAccumulator is a no-op implementation of the hashAccumulator
// interface. This is used when we want deterministic behavior and don't
// want to sample nodes randomly from the channel graph.
type noOpHashAccumulator struct{}
// newNoOpHashAccumulator returns a new instance of a noOpHashAccumulator.
func newNoOpHashAccumulator() *noOpHashAccumulator {
return &noOpHashAccumulator{}
}
// rotate is a no-op for the noOpHashAccumulator.
//
// NOTE: this is part of the hashAccumulator interface.
func (*noOpHashAccumulator) rotate() {}
// skipNode always returns false, meaning that no nodes will be skipped.
//
// NOTE: this is part of the hashAccumulator interface.
func (*noOpHashAccumulator) skipNode(route.Vertex) bool {
return false
}
// A compile-time assertion to ensure that noOpHashAccumulator meets the
// hashAccumulator interface.
var _ hashAccumulator = (*noOpHashAccumulator)(nil)

View File

@@ -144,7 +144,9 @@ reader of a payment request.
disabling has now been
[removed](https://github.com/lightningnetwork/lnd/pull/9967) meaning that any
test network scripts that rely on bootstrapping being disabled will need to
explicitly define the `--nobootstrap` flag.
explicitly define the `--nobootstrap` flag. Bootstrapping will now also be
[deterministic](https://github.com/lightningnetwork/lnd/pull/10003) on local
test networks so that bootstrapping behaviour can be tested for.
## Database

View File

@@ -3064,7 +3064,9 @@ func initNetworkBootstrappers(s *server) ([]discovery.NetworkPeerBootstrapper, e
// this can be used by default if we've already partially seeded the
// network.
chanGraph := autopilot.ChannelGraphFromDatabase(s.graphDB)
graphBootstrapper, err := discovery.NewGraphBootstrapper(chanGraph)
graphBootstrapper, err := discovery.NewGraphBootstrapper(
chanGraph, s.cfg.Bitcoin.IsLocalNetwork(),
)
if err != nil {
return nil, err
}