Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connecting unstaked AN with the staked AN using DHT for peer discovery #1098

Merged
merged 71 commits into from
Aug 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
0141e0e
using functional options for LibP2PNode to make it more configurable …
vishalchangrani Aug 3, 2021
36c3423
making connection manager optional in WithDefaultLibP2PHost NodeOption
vishalchangrani Aug 3, 2021
8b2b501
extracting out the common libp2p config options
vishalchangrani Aug 3, 2021
9b54112
wip
vishalchangrani Aug 4, 2021
11eaf04
Merge branch 'master' into vishal/network_changes_for_unstaked
vishalchangrani Aug 4, 2021
926b059
Update network/p2p/libp2pNode.go
vishalchangrani Aug 4, 2021
525ac07
modifying the PubSub test to use the new DHT discovery
vishalchangrani Aug 5, 2021
fa880d6
wip
vishalchangrani Aug 5, 2021
5e94cbe
Merge branch 'master' into vishal/network_changes_for_unstaked
vishalchangrani Aug 5, 2021
5f7e4f1
changing NewLibP2PNode to explicitly expect mandatory params host and…
vishalchangrani Aug 5, 2021
303cb37
fixing test and comments
vishalchangrani Aug 6, 2021
822e2fc
Merge branch 'master' into vishal/network_changes_for_unstaked
vishalchangrani Aug 6, 2021
5e8aa0e
comment
vishalchangrani Aug 6, 2021
ff8b012
Merge branch 'vishal/network_changes_for_unstaked' of github.com:onfl…
vishalchangrani Aug 6, 2021
6fa88fd
lint
vishalchangrani Aug 6, 2021
0006b24
wip
vishalchangrani Aug 6, 2021
f3f9dc2
Merge branch 'vishal/network_changes_for_unstaked' into vishal/dht
vishalchangrani Aug 6, 2021
988d98f
wip
vishalchangrani Aug 6, 2021
44b6132
storing the cancel function for the network context in the node builder
vishalchangrani Aug 6, 2021
fb98c6a
changes as per review comments
vishalchangrani Aug 6, 2021
75320b8
removing error return from NodeOption
vishalchangrani Aug 6, 2021
f1e4f81
fix error
vishalchangrani Aug 6, 2021
d7f7afb
Merge branch 'master' into vishal/network_changes_for_unstaked
vishalchangrani Aug 6, 2021
b4494d6
fix error
vishalchangrani Aug 6, 2021
95249d8
adding the upstream connector
vishalchangrani Aug 6, 2021
9c41474
Merge branch 'vishal/network_changes_for_unstaked' into vishal/dht
vishalchangrani Aug 6, 2021
c4a7186
fixing comments
vishalchangrani Aug 7, 2021
0b84f70
reseting go.mod and go.sum
vishalchangrani Aug 7, 2021
92ac71b
wip
vishalchangrani Aug 7, 2021
7813efa
comment
vishalchangrani Aug 7, 2021
f968f65
moving networking metrics further down
vishalchangrani Aug 7, 2021
fee327c
changing upstream connector error reporting and context handling
vishalchangrani Aug 7, 2021
cd2648f
create libp2p node builder
synzhu Aug 8, 2021
4681eee
Update libp2pNode_test.go
synzhu Aug 8, 2021
d22b611
update tests
synzhu Aug 8, 2021
8262650
update test packages
synzhu Aug 8, 2021
c725e61
Revert "update test packages"
synzhu Aug 8, 2021
9dcc4fd
update testnet
synzhu Aug 8, 2021
b49380d
changes as per review comments
vishalchangrani Aug 8, 2021
6e7ff1c
Update mocks
synzhu Aug 9, 2021
f41a22f
Update libp2pNode.go
synzhu Aug 9, 2021
11b7ec6
Merge pull request #1099 from onflow/smnzhu/libp2p-node-builder
synzhu Aug 9, 2021
669ce7b
Merge branch 'master' into vishal/network_changes_for_unstaked
synzhu Aug 9, 2021
8662509
removing untested change to default values of dht.RoutingTableRefresh…
vishalchangrani Aug 9, 2021
a650688
removing unused constants
vishalchangrani Aug 9, 2021
d4072e1
Merge branch 'vishal/network_changes_for_unstaked' into vishal/dht
vishalchangrani Aug 9, 2021
21b84d8
switching to use the new LibP2PNode builder and creating a new Pubsub…
vishalchangrani Aug 9, 2021
999215e
fixing comments
vishalchangrani Aug 9, 2021
d3254bf
wip
vishalchangrani Aug 10, 2021
7c62b31
changes to upstream connector to typ mulitiple bootstrap nodes
vishalchangrani Aug 11, 2021
5b1b6cd
Merge branch 'master' into vishal/dht
vishalchangrani Aug 11, 2021
279e377
lint
vishalchangrani Aug 11, 2021
4c7dead
seending the dht with the bootstrap peers for the unstaked node
vishalchangrani Aug 11, 2021
ad849c7
Update upstream_connector.go
synzhu Aug 11, 2021
f50fb0b
Update upstream_connector.go
synzhu Aug 11, 2021
1930d5c
updating consensus follower to use the bootstrap addresses and keys
vishalchangrani Aug 11, 2021
af519d3
Merge branch 'smnzhu/dht' into vishal/dht
vishalchangrani Aug 11, 2021
43fbdaf
merging in master
vishalchangrani Aug 11, 2021
370b4bb
Merge branch 'master' into vishal/dht
vishalchangrani Aug 11, 2021
26b0c27
go.mod
vishalchangrani Aug 11, 2021
b72ea56
Merge branch 'master' into vishal/dht
vishalchangrani Aug 12, 2021
8385ceb
fixing the unstaked_access_node_builder
vishalchangrani Aug 12, 2021
7f16e42
Merge branch 'vishal/dht' of github.com:onflow/flow-go into vishal/dht
vishalchangrani Aug 12, 2021
5ecf542
lint
vishalchangrani Aug 12, 2021
bc9334f
Merge branch 'master' into vishal/dht
vishalchangrani Aug 13, 2021
ff47c7e
Merge branch 'master' into vishal/dht
vishalchangrani Aug 15, 2021
5aa84f5
fixing typo
vishalchangrani Aug 16, 2021
0f77b68
Merge branch 'master' into vishal/dht
vishalchangrani Aug 16, 2021
c272ae0
adding bootstrap node info to the consensus follower
vishalchangrani Aug 16, 2021
790034b
typo
vishalchangrani Aug 16, 2021
f5c6f0b
Merge branch 'master' into vishal/dht
vishalchangrani Aug 16, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 86 additions & 46 deletions cmd/access/node_builder/access_node_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package node_builder

import (
"context"
"encoding/json"
"fmt"
"strings"
"time"

dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/onflow/flow/protobuf/go/flow/access"
"github.com/spf13/pflag"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"

"github.com/onflow/flow-go/cmd"
"github.com/onflow/flow-go/cmd/build"
"github.com/onflow/flow-go/consensus"
"github.com/onflow/flow-go/consensus/hotstuff"
"github.com/onflow/flow-go/consensus/hotstuff/committees"
Expand Down Expand Up @@ -42,6 +43,7 @@ import (
"github.com/onflow/flow-go/network"
jsoncodec "github.com/onflow/flow-go/network/codec/json"
"github.com/onflow/flow-go/network/p2p"
"github.com/onflow/flow-go/network/validator"
"github.com/onflow/flow-go/state/protocol"
badgerState "github.com/onflow/flow-go/state/protocol/badger"
"github.com/onflow/flow-go/state/protocol/blocktimer"
Expand Down Expand Up @@ -84,7 +86,9 @@ type AccessNodeBuilder interface {
// while for a node running as a library, the config fields are expected to be initialized by the caller.
type AccessNodeConfig struct {
staked bool
stakedAccessNodeIDHex string
bootstrapNodeAddresses []string
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now the unstaked node only needs the bootstrap node addresses and the public keys of those nodes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that is an improvement at all. Now, we have to manage multiple node identities with public keys on the unstaked consensus follower side. That doesn't make sense. Knowing a single access node address should be the only dependency needed. The DHT information should not be information that you need to connect; it should be served by the access node we connect to.

bootstrapNodePublicKeys []string
bootstrapIdentites flow.IdentityList // the identity list of bootstrap peers the node uses to discover other nodes
unstakedNetworkBindAddr string
collectionGRPCPort uint
executionGRPCPort uint
Expand Down Expand Up @@ -131,7 +135,8 @@ func DefaultAccessNodeConfig() *AccessNodeConfig {
apiRatelimits: nil,
apiBurstlimits: nil,
staked: true,
stakedAccessNodeIDHex: "",
bootstrapNodeAddresses: []string{},
bootstrapNodePublicKeys: []string{},
unstakedNetworkBindAddr: cmd.NotSet,
}
}
Expand All @@ -144,6 +149,7 @@ type FlowAccessNodeBuilder struct {
*AccessNodeConfig

// components
UnstakedLibP2PNode *p2p.Node
UnstakedNetwork *p2p.Network
unstakedMiddleware *p2p.Middleware
FollowerState protocol.MutableState
Expand Down Expand Up @@ -483,9 +489,9 @@ func (anb *FlowAccessNodeBuilder) Build() AccessNodeBuilder {

type Option func(*AccessNodeConfig)

func WithUpstreamAccessNodeID(upstreamAccessNodeID flow.Identifier) Option {
func WithBootStrapPeers(bootstrapNodes ...*flow.Identity) Option {
return func(config *AccessNodeConfig) {
config.stakedAccessNodeIDHex = upstreamAccessNodeID.String()
config.bootstrapIdentites = bootstrapNodes
}
}

Expand Down Expand Up @@ -563,71 +569,59 @@ func (builder *FlowAccessNodeBuilder) extraFlags() {
flags.StringToIntVar(&builder.apiRatelimits, "api-rate-limits", defaultConfig.apiRatelimits, "per second rate limits for Access API methods e.g. Ping=300,GetTransaction=500 etc.")
flags.StringToIntVar(&builder.apiBurstlimits, "api-burst-limits", defaultConfig.apiBurstlimits, "burst limits for Access API methods e.g. Ping=100,GetTransaction=100 etc.")
flags.BoolVar(&builder.staked, "staked", defaultConfig.staked, "whether this node is a staked access node or not")
flags.StringVar(&builder.stakedAccessNodeIDHex, "staked-access-node-id", defaultConfig.stakedAccessNodeIDHex, "the node ID of the upstream staked access node if this is an unstaked access node")
flags.StringSliceVar(&builder.bootstrapNodeAddresses, "bootstrap-node-addresses", defaultConfig.bootstrapNodeAddresses, "the network addresses of the bootstrap access node if this is an unstaked access node e.g. access-001.mainnet.flow.org:9653,access-002.mainnet.flow.org:9653")
flags.StringSliceVar(&builder.bootstrapNodePublicKeys, "bootstrap-node-public-keys", defaultConfig.bootstrapNodePublicKeys, "the networking public key of the bootstrap access node if this is an unstaked access node (in the same order as the bootstrap node addresses) e.g. \"d57a5e9c5.....\",\"44ded42d....\"")
flags.StringVar(&builder.unstakedNetworkBindAddr, "unstaked-bind-addr", defaultConfig.unstakedNetworkBindAddr, "address to bind on for the unstaked network")
})
}

// initLibP2PFactory creates the LibP2P factory function for the given node ID and network key.
// The factory function is later passed into the initMiddleware function to eventually instantiate the p2p.LibP2PNode instance
func (builder *FlowAccessNodeBuilder) initLibP2PFactory(
ctx context.Context,
func (builder *FlowAccessNodeBuilder) initLibP2PFactory(ctx context.Context,
nodeID flow.Identifier,
networkMetrics module.NetworkMetrics,
networkKey crypto.PrivateKey,
) (p2p.LibP2PFactoryFunc, error) {
networkKey crypto.PrivateKey) (p2p.LibP2PFactoryFunc, error) {

// setup the Ping provider to return the software version and the sealed block height
pingProvider := p2p.PingInfoProviderImpl{
SoftwareVersionFun: func() string {
return build.Semver()
},
SealedBlockHeightFun: func() (uint64, error) {
head, err := builder.State.Sealed().Head()
if err != nil {
return 0, err
}
return head.Height, nil
},
}
// The staked nodes act as the DHT servers
dhtOptions := []dht.Option{p2p.AsServer(builder.IsStaked())}

libP2PNodeFactory, err := p2p.DefaultLibP2PNodeFactory(
ctx,
builder.Logger,
nodeID,
builder.unstakedNetworkBindAddr,
networkKey,
builder.RootBlock.ID().String(),
p2p.DefaultMaxPubSubMsgSize,
networkMetrics,
pingProvider,
)
if err != nil {
return nil, fmt.Errorf("could not generate libp2p node factory: %w", err)
// if this is an unstaked access node, then seed the DHT with the boostrap identities
if !builder.IsStaked() {
bootstrapPeersOpt, err := p2p.WithBootstrapPeers(builder.bootstrapIdentites)
builder.MustNot(err)
dhtOptions = append(dhtOptions, bootstrapPeersOpt)
}

return libP2PNodeFactory, nil
return func() (*p2p.Node, error) {
libp2pNode, err := p2p.NewDefaultLibP2PNodeBuilder(nodeID, builder.unstakedNetworkBindAddr, networkKey).
SetRootBlockID(builder.RootBlock.ID().String()).
// unlike the staked network where currently all the node addresses are known upfront,
// for the unstaked network the nodes need to discover each other using DHT Discovery.
SetPubsubOptions(p2p.WithDHTDiscovery(dhtOptions...)).
SetLogger(builder.Logger).
Build(ctx)
if err != nil {
return nil, err
}
builder.UnstakedLibP2PNode = libp2pNode
return builder.UnstakedLibP2PNode, nil
}, nil
}

// initMiddleware creates the network.Middleware implementation with the libp2p factory function, metrics, peer update
// interval, and validators. The network.Middleware is then passed into the initNetwork function.
func (builder *FlowAccessNodeBuilder) initMiddleware(nodeID flow.Identifier,
networkMetrics module.NetworkMetrics,
factoryFunc p2p.LibP2PFactoryFunc,
peerUpdateInterval time.Duration,
unicastMessageTimeout time.Duration,
connectionGating bool,
managerPeerConnections bool,
validators ...network.MessageValidator) *p2p.Middleware {
builder.unstakedMiddleware = p2p.NewMiddleware(builder.Logger,
factoryFunc,
nodeID,
networkMetrics,
builder.RootBlock.ID().String(),
peerUpdateInterval,
unicastMessageTimeout,
connectionGating,
managerPeerConnections,
time.Hour, // TODO: this is pretty meaningless since there is no peermanager in play.
p2p.DefaultUnicastTimeout,
false, // no connection gating for the unstaked network
false, // no peer management for the unstaked network (peer discovery will be done via LibP2P discovery mechanism)
validators...)
return builder.unstakedMiddleware
}
Expand Down Expand Up @@ -661,3 +655,49 @@ func (builder *FlowAccessNodeBuilder) initNetwork(nodeID module.Local,

return net, nil
}

func unstakedNetworkMsgValidators(selfID flow.Identifier) []network.MessageValidator {
return []network.MessageValidator{
// filter out messages sent by this node itself
validator.ValidateNotSender(selfID),
}
Comment on lines +660 to +663
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need something better here?

We have two scenarios:

  • Messages coming from staked nodes. For these, the staked AN just gossips them to the network and all unstaked nodes should accept them.
  • Messages sent from unstaked nodes to each other (e.g sync request). For these, we do want to validate that we are one of the targets, otherwise we will respond to all sync requests.

The validation logic should be something like: "If the origin ID is from the Identity list in the protocol state, then accept, otherwise only accept if I am one of the targets".

This relies on #1115 being done, which I think Francois is working on.

This can be done in a later PR though. I'll create an issue for it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, #1126 I can work on this once #1115 is done :)

}

// BootstrapIdentities converts the bootstrap node addresses and keys to a Flow Identity list where
// each Flow Identity is initialized with the passed address, the networking key
// and the Node ID set to ZeroID, role set to Access, 0 stake and no staking key.
func BootstrapIdentities(addresses []string, keys []string) (flow.IdentityList, error) {

if len(addresses) != len(keys) {
return nil, fmt.Errorf("number of addresses and keys provided for the boostrap nodes don't match")
}

ids := make([]*flow.Identity, len(addresses))
for i, address := range addresses {

key := keys[i]
// json unmarshaller needs a quotes before and after the string
// the pflags.StringSliceVar does not retain quotes for the command line arg even if escaped with \"
// hence this additional check to ensure the key is indeed quoted
if !strings.HasPrefix(key, "\"") {
key = fmt.Sprintf("\"%s\"", key)
}
// networking public key
var networkKey encodable.NetworkPubKey
err := json.Unmarshal([]byte(key), &networkKey)
if err != nil {
return nil, err
}

// create the identity of the peer by setting only the relevant fields
id := &flow.Identity{
NodeID: flow.ZeroID, // the NodeID is the hash of the staking key and for the unstaked network it does not apply
Address: address,
Role: flow.RoleAccess, // the upstream node has to be an access node
NetworkPubKey: networkKey,
}

ids = append(ids, id)
}
return ids, nil
}
23 changes: 6 additions & 17 deletions cmd/access/node_builder/staked_access_node_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ package node_builder
import (
"context"
"fmt"
"time"

"github.com/onflow/flow-go/cmd"
pingeng "github.com/onflow/flow-go/engine/access/ping"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module"
"github.com/onflow/flow-go/module/metrics"
"github.com/onflow/flow-go/network/p2p"
"github.com/onflow/flow-go/network/topology"
)

Expand Down Expand Up @@ -83,26 +81,17 @@ func (builder *StakedAccessNodeBuilder) enqueueUnstakedNetworkInit(ctx context.C
// TODO: set a different networking key of the staked access node on the unstaked network
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This todo will probably go away: if we use a single network (2 topics), the staked AN has a single network identity (PeerID) and therefore a single Network PublicKey.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it will go away but ripping it out later will be more easier than changing it here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup

unstakedNetworkKey := builder.NetworkKey

libP2PFactory, err := builder.initLibP2PFactory(ctx, unstakedNodeID, unstakedNetworkKey)
builder.MustNot(err)

msgValidators := unstakedNetworkMsgValidators(unstakedNodeID)

// Network Metrics
// for now we use the empty metrics NoopCollector till we have defined the new unstaked network metrics
// TODO: define new network metrics for the unstaked network
unstakedNetworkMetrics := metrics.NewNoopCollector()

libP2PFactory, err := builder.FlowAccessNodeBuilder.initLibP2PFactory(ctx, unstakedNodeID, unstakedNetworkMetrics, unstakedNetworkKey)
builder.MustNot(err)

// use the default validators for the staked access node unstaked networks
msgValidators := p2p.DefaultValidators(builder.Logger, unstakedNodeID)

// don't need any peer updates since this will be taken care by the DHT discovery mechanism
peerUpdateInterval := time.Hour

middleware := builder.initMiddleware(unstakedNodeID,
unstakedNetworkMetrics, libP2PFactory, peerUpdateInterval,
builder.UnicastMessageTimeout,
false, // no connection gating for the unstaked network
false, // no peer management for the unstaked network (peer discovery will be done via LibP2P discovery mechanism)
msgValidators...)
middleware := builder.initMiddleware(unstakedNodeID, unstakedNetworkMetrics, libP2PFactory, msgValidators...)

// empty list of unstaked network participants since they will be discovered dynamically and are not known upfront
// TODO: this list should be the unstaked addresses of all the staked AN that participate in the unstaked network
Expand Down
64 changes: 34 additions & 30 deletions cmd/access/node_builder/unstaked_access_node_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@ package node_builder

import (
"context"
"strings"
"time"

"github.com/onflow/flow-go/cmd"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module"
"github.com/onflow/flow-go/module/local"
"github.com/onflow/flow-go/module/metrics"
"github.com/onflow/flow-go/network/p2p"
"github.com/onflow/flow-go/network/topology"
)

type UnstakedAccessNodeBuilder struct {
Expand All @@ -31,8 +27,12 @@ func (builder *UnstakedAccessNodeBuilder) Initialize() cmd.NodeBuilder {

builder.validateParams()

builder.deriveBootstrapPeerIdentities()

builder.enqueueUnstakedNetworkInit(ctx)

builder.enqueueConnectWithStakedAN()

builder.EnqueueMetricsServerInit()

builder.RegisterBadgerMetrics()
Expand All @@ -46,15 +46,22 @@ func (builder *UnstakedAccessNodeBuilder) Initialize() cmd.NodeBuilder {

func (builder *UnstakedAccessNodeBuilder) validateParams() {

// for an unstaked access node, the staked access node ID must be provided
if strings.TrimSpace(builder.stakedAccessNodeIDHex) == "" {
builder.Logger.Fatal().Msg("staked access node ID not specified")
}

// and also the unstaked bind address
// for an unstaked access node, the unstaked network bind address must be provided
if builder.unstakedNetworkBindAddr == cmd.NotSet {
builder.Logger.Fatal().Msg("unstaked bind address not set")
}

if len(builder.bootstrapNodeAddresses) != len(builder.bootstrapNodePublicKeys) {
builder.Logger.Fatal().Msg("number of bootstrap node addresses and public keys should match")
}
}

// deriveBootstrapPeerIdentities derives the Flow Identity of the bootstreap peers from the parameters.
// These are the identity of the staked and unstaked AN also acting as the DHT bootstrap server
func (builder *UnstakedAccessNodeBuilder) deriveBootstrapPeerIdentities() {
ids, err := BootstrapIdentities(builder.bootstrapNodeAddresses, builder.bootstrapNodePublicKeys)
builder.MustNot(err)
builder.bootstrapIdentites = ids
}

// initUnstakedLocal initializes the unstaked node ID, network key and network address
Expand Down Expand Up @@ -92,33 +99,18 @@ func (builder *UnstakedAccessNodeBuilder) enqueueUnstakedNetworkInit(ctx context
// for now we use the empty metrics NoopCollector till we have defined the new unstaked network metrics
unstakedNetworkMetrics := metrics.NewNoopCollector()

// intialize the LibP2P factory with an empty metrics NoopCollector for now till we have defined the new unstaked
// network metrics
libP2PFactory, err := builder.FlowAccessNodeBuilder.initLibP2PFactory(ctx, unstakedNodeID, unstakedNetworkMetrics, unstakedNetworkKey)
libP2PFactory, err := builder.initLibP2PFactory(ctx, unstakedNodeID, unstakedNetworkKey)
builder.MustNot(err)

// use the default validators for the staked access node unstaked networks
msgValidators := p2p.DefaultValidators(builder.Logger, unstakedNodeID)
msgValidators := unstakedNetworkMsgValidators(unstakedNodeID)

// don't need any peer updates since this will be taken care by the DHT discovery mechanism
peerUpdateInterval := time.Hour

middleware := builder.initMiddleware(unstakedNodeID, unstakedNetworkMetrics, libP2PFactory, peerUpdateInterval,
node.UnicastMessageTimeout,
false, // no connection gating for the unstaked network
false, // no peer management for the unstaked network (peer discovery will be done via LibP2P discovery mechanism)
msgValidators...)
middleware := builder.initMiddleware(unstakedNodeID, unstakedNetworkMetrics, libP2PFactory, msgValidators...)

// empty list of unstaked network participants since they will be discovered dynamically and are not known upfront
participants := flow.IdentityList{}

upstreamANIdentifier, err := flow.HexStringToIdentifier(builder.stakedAccessNodeIDHex)
builder.MustNot(err)

// topology only consist of the upsteam staked AN
top := topology.NewFixedListTopology(upstreamANIdentifier)

network, err := builder.initNetwork(builder.Me, unstakedNetworkMetrics, middleware, participants, top)
// topology is nil since its automatically managed by libp2p
network, err := builder.initNetwork(builder.Me, unstakedNetworkMetrics, middleware, participants, nil)
builder.MustNot(err)

builder.UnstakedNetwork = network
Expand All @@ -133,3 +125,15 @@ func (builder *UnstakedAccessNodeBuilder) enqueueUnstakedNetworkInit(ctx context
return builder.UnstakedNetwork, err
})
}

// enqueueConnectWithStakedAN enqueues the upstream connector component which connects the libp2p host of the unstaked
// AN with the staked AN.
// Currently, there is an issue with LibP2P stopping advertisements of subscribed topics if no peers are connected
// (https://github.com/libp2p/go-libp2p-pubsub/issues/442). This means that an unstaked AN could end up not being
// discovered by other unstaked ANs if it subscribes to a topic before connecting to the staked AN. Hence, the need
// of an explicit connect to the staked AN before the node attempts to subscribe to topics.
func (builder *UnstakedAccessNodeBuilder) enqueueConnectWithStakedAN() {
builder.Component("unstaked network", func(_ cmd.NodeBuilder, _ *cmd.NodeConfig) (module.ReadyDoneAware, error) {
return newUpstreamConnector(builder.bootstrapIdentites, builder.UnstakedLibP2PNode, builder.Logger), nil
})
}
Loading