Skip to content

Commit d36a16c

Browse files
authored
Node/P2P: Add protected peers list (#4292)
* Node/P2P: Add protected peers list * Add support for spy and CCQ proxy * Add tests
1 parent 8bdc162 commit d36a16c

11 files changed

+145
-20
lines changed

node/cmd/ccq/p2p.go

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
pubsub "github.com/libp2p/go-libp2p-pubsub"
1818
"github.com/libp2p/go-libp2p/core/crypto"
1919
"github.com/libp2p/go-libp2p/core/host"
20+
"github.com/libp2p/go-libp2p/core/peer"
2021
"github.com/wormhole-foundation/wormhole/sdk/vaa"
2122
"go.uber.org/zap"
2223
"google.golang.org/protobuf/proto"
@@ -52,6 +53,7 @@ func runP2P(
5253
monitorPeers bool,
5354
loggingMap *LoggingMap,
5455
gossipAdvertiseAddress string,
56+
protectedPeers []string,
5557
) (*P2PSub, error) {
5658
// p2p setup
5759
components := p2p.DefaultComponents()
@@ -63,6 +65,12 @@ func runP2P(
6365
return nil, err
6466
}
6567

68+
if len(protectedPeers) != 0 {
69+
for _, peerId := range protectedPeers {
70+
components.ConnMgr.Protect(peer.ID(peerId), "configured")
71+
}
72+
}
73+
6674
topic_req := fmt.Sprintf("%s/%s", networkID, "ccq_req")
6775
topic_resp := fmt.Sprintf("%s/%s", networkID, "ccq_resp")
6876

node/cmd/ccq/query_server.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ var (
3232
p2pNetworkID *string
3333
p2pPort *uint
3434
p2pBootstrap *string
35+
protectedPeers []string
3536
listenAddr *string
3637
nodeKeyPath *string
3738
signerKeyPath *string
@@ -57,6 +58,7 @@ func init() {
5758
p2pNetworkID = QueryServerCmd.Flags().String("network", "", "P2P network identifier (optional, overrides default for environment)")
5859
p2pPort = QueryServerCmd.Flags().Uint("port", 8995, "P2P UDP listener port")
5960
p2pBootstrap = QueryServerCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (optional for testnet or mainnet, overrides default, required for devnet)")
61+
QueryServerCmd.Flags().StringSliceVarP(&protectedPeers, "protectedPeers", "", []string{}, "")
6062
nodeKeyPath = QueryServerCmd.Flags().String("nodeKey", "", "Path to node key (will be generated if it doesn't exist)")
6163
signerKeyPath = QueryServerCmd.Flags().String("signerKey", "", "Path to key used to sign unsigned queries")
6264
listenAddr = QueryServerCmd.Flags().String("listenAddr", "[::]:6069", "Listen address for query server (disabled if blank)")
@@ -204,7 +206,7 @@ func runQueryServer(cmd *cobra.Command, args []string) {
204206

205207
// Run p2p
206208
pendingResponses := NewPendingResponses(logger)
207-
p2p, err := runP2P(ctx, priv, *p2pPort, networkID, *p2pBootstrap, *ethRPC, *ethContract, pendingResponses, logger, *monitorPeers, loggingMap, *gossipAdvertiseAddress)
209+
p2p, err := runP2P(ctx, priv, *p2pPort, networkID, *p2pBootstrap, *ethRPC, *ethContract, pendingResponses, logger, *monitorPeers, loggingMap, *gossipAdvertiseAddress, protectedPeers)
208210
if err != nil {
209211
logger.Fatal("Failed to start p2p", zap.Error(err))
210212
}

node/cmd/guardiand/node.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,10 @@ import (
5050
)
5151

5252
var (
53-
p2pNetworkID *string
54-
p2pPort *uint
55-
p2pBootstrap *string
53+
p2pNetworkID *string
54+
p2pPort *uint
55+
p2pBootstrap *string
56+
protectedPeers []string
5657

5758
nodeKeyPath *string
5859

@@ -262,6 +263,7 @@ var (
262263
ccqAllowedRequesters *string
263264
ccqP2pPort *uint
264265
ccqP2pBootstrap *string
266+
ccqProtectedPeers []string
265267
ccqAllowedPeers *string
266268
ccqBackfillCache *bool
267269

@@ -282,6 +284,7 @@ func init() {
282284
p2pNetworkID = NodeCmd.Flags().String("network", "", "P2P network identifier (optional, overrides default for environment)")
283285
p2pPort = NodeCmd.Flags().Uint("port", p2p.DefaultPort, "P2P UDP listener port")
284286
p2pBootstrap = NodeCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (optional for mainnet or testnet, overrides default, required for unsafeDevMode)")
287+
NodeCmd.Flags().StringSliceVarP(&protectedPeers, "protectedPeers", "", []string{}, "")
285288

286289
statusAddr = NodeCmd.Flags().String("statusAddr", "[::]:6060", "Listen address for status server (disabled if blank)")
287290

@@ -491,6 +494,7 @@ func init() {
491494
ccqAllowedRequesters = NodeCmd.Flags().String("ccqAllowedRequesters", "", "Comma separated list of signers allowed to submit cross chain queries")
492495
ccqP2pPort = NodeCmd.Flags().Uint("ccqP2pPort", 8996, "CCQ P2P UDP listener port")
493496
ccqP2pBootstrap = NodeCmd.Flags().String("ccqP2pBootstrap", "", "CCQ P2P bootstrap peers (optional for mainnet or testnet, overrides default, required for unsafeDevMode)")
497+
NodeCmd.Flags().StringSliceVarP(&ccqProtectedPeers, "ccqProtectedPeers", "", []string{}, "")
494498
ccqAllowedPeers = NodeCmd.Flags().String("ccqAllowedPeers", "", "CCQ allowed P2P peers (comma-separated)")
495499
ccqBackfillCache = NodeCmd.Flags().Bool("ccqBackfillCache", true, "Should EVM chains backfill CCQ timestamp cache on startup")
496500
gossipAdvertiseAddress = NodeCmd.Flags().String("gossipAdvertiseAddress", "", "External IP to advertize on Guardian and CCQ p2p (use if behind a NAT or running in k8s)")
@@ -1777,7 +1781,7 @@ func runNode(cmd *cobra.Command, args []string) {
17771781
node.GuardianOptionGatewayRelayer(*gatewayRelayerContract, gatewayRelayerWormchainConn),
17781782
node.GuardianOptionQueryHandler(*ccqEnabled, *ccqAllowedRequesters),
17791783
node.GuardianOptionAdminService(*adminSocketPath, ethRPC, ethContract, rpcMap),
1780-
node.GuardianOptionP2P(p2pKey, *p2pNetworkID, *p2pBootstrap, *nodeName, *subscribeToVAAs, *disableHeartbeatVerify, *p2pPort, *ccqP2pBootstrap, *ccqP2pPort, *ccqAllowedPeers, *gossipAdvertiseAddress, ibc.GetFeatures),
1784+
node.GuardianOptionP2P(p2pKey, *p2pNetworkID, *p2pBootstrap, *nodeName, *subscribeToVAAs, *disableHeartbeatVerify, *p2pPort, *ccqP2pBootstrap, *ccqP2pPort, *ccqAllowedPeers, *gossipAdvertiseAddress, ibc.GetFeatures, protectedPeers, ccqProtectedPeers),
17811785
node.GuardianOptionStatusServer(*statusAddr),
17821786
node.GuardianOptionProcessor(*p2pNetworkID),
17831787
}

node/cmd/spy/spy.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ var (
3636
var (
3737
envStr *string
3838

39-
p2pNetworkID *string
40-
p2pPort *uint
41-
p2pBootstrap *string
39+
p2pNetworkID *string
40+
p2pPort *uint
41+
p2pBootstrap *string
42+
protectedPeers []string
4243

4344
statusAddr *string
4445

@@ -59,6 +60,7 @@ func init() {
5960
p2pNetworkID = SpyCmd.Flags().String("network", "", "P2P network identifier (optional for testnet or mainnet, overrides default, required for devnet)")
6061
p2pPort = SpyCmd.Flags().Uint("port", 8999, "P2P UDP listener port")
6162
p2pBootstrap = SpyCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (optional for testnet or mainnet, overrides default, required for devnet)")
63+
SpyCmd.Flags().StringSliceVarP(&protectedPeers, "protectedPeers", "", []string{}, "")
6264

6365
statusAddr = SpyCmd.Flags().String("statusAddr", "[::]:6060", "Listen address for status server (disabled if blank)")
6466

@@ -396,6 +398,7 @@ func runSpy(cmd *cobra.Command, args []string) {
396398
rootCtxCancel,
397399
p2p.WithSignedVAAListener(signedInC),
398400
p2p.WithComponents(components),
401+
p2p.WithProtectedPeers(protectedPeers),
399402
)
400403
if err != nil {
401404
return err

node/pkg/node/node_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func mockGuardianRunnable(t testing.TB, gs []*mockGuardian, mockGuardianIndex ui
190190
GuardianOptionNoAccountant(), // disable accountant
191191
GuardianOptionGovernor(true, false, ""),
192192
GuardianOptionGatewayRelayer("", nil), // disable gateway relayer
193-
GuardianOptionP2P(gs[mockGuardianIndex].p2pKey, networkID, bootstrapPeers, nodeName, false, false, cfg.p2pPort, "", 0, "", "", func() string { return "" }),
193+
GuardianOptionP2P(gs[mockGuardianIndex].p2pKey, networkID, bootstrapPeers, nodeName, false, false, cfg.p2pPort, "", 0, "", "", func() string { return "" }, []string{}, []string{}),
194194
GuardianOptionPublicRpcSocket(cfg.publicSocket, publicRpcLogDetail),
195195
GuardianOptionPublicrpcTcpService(cfg.publicRpc, publicRpcLogDetail),
196196
GuardianOptionPublicWeb(cfg.publicWeb, cfg.publicSocket, "", false, ""),

node/pkg/node/options.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ func GuardianOptionP2P(
5252
ccqAllowedPeers string,
5353
gossipAdvertiseAddress string,
5454
ibcFeaturesFunc func() string,
55+
protectedPeers []string,
56+
ccqProtectedPeers []string,
5557
) *GuardianOption {
5658
return &GuardianOption{
5759
name: "p2p",
@@ -101,7 +103,10 @@ func GuardianOptionP2P(
101103
g.queryResponsePublicationC.readC,
102104
ccqBootstrapPeers,
103105
ccqPort,
104-
ccqAllowedPeers),
106+
ccqAllowedPeers,
107+
protectedPeers,
108+
ccqProtectedPeers,
109+
),
105110
p2p.WithProcessorFeaturesFunc(processor.GetFeatures),
106111
)
107112
if err != nil {

node/pkg/p2p/ccq_p2p.go

+7
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ func (ccq *ccqP2p) run(
7676
port uint,
7777
signedQueryReqC chan<- *gossipv1.SignedQueryRequest,
7878
queryResponseReadC <-chan *query.QueryResponsePublication,
79+
protectedPeers []string,
7980
errC chan error,
8081
) error {
8182
networkID := p2pNetworkID + "/ccq"
@@ -95,6 +96,12 @@ func (ccq *ccqP2p) run(
9596
return fmt.Errorf("failed to create p2p: %w", err)
9697
}
9798

99+
if len(protectedPeers) != 0 {
100+
for _, peerId := range protectedPeers {
101+
components.ConnMgr.Protect(peer.ID(peerId), "configured")
102+
}
103+
}
104+
98105
// Build a map of bootstrap peers so we can always allow subscribe requests from them.
99106
bootstrapPeersMap := map[string]struct{}{}
100107
bootstrappers, _ := BootstrapAddrs(ccq.logger, bootstrapPeers, ccq.h.ID())

node/pkg/p2p/p2p.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,13 @@ func Run(params *RunParams) func(ctx context.Context) error {
335335
}
336336
}()
337337

338+
if len(params.protectedPeers) != 0 {
339+
for _, peerId := range params.protectedPeers {
340+
logger.Info("protecting peer", zap.String("peerId", peerId))
341+
params.components.ConnMgr.Protect(peer.ID(peerId), "configured")
342+
}
343+
}
344+
338345
nodeIdBytes, err := h.ID().Marshal()
339346
if err != nil {
340347
panic(err)
@@ -462,7 +469,7 @@ func Run(params *RunParams) func(ctx context.Context) error {
462469
if params.ccqEnabled {
463470
ccqErrC := make(chan error)
464471
ccq := newCcqRunP2p(logger, params.ccqAllowedPeers, params.components)
465-
if err := ccq.run(ctx, params.priv, params.guardianSigner, params.networkID, params.ccqBootstrapPeers, params.ccqPort, params.signedQueryReqC, params.queryResponseReadC, ccqErrC); err != nil {
472+
if err := ccq.run(ctx, params.priv, params.guardianSigner, params.networkID, params.ccqBootstrapPeers, params.ccqPort, params.signedQueryReqC, params.queryResponseReadC, params.ccqProtectedPeers, ccqErrC); err != nil {
466473
return fmt.Errorf("failed to start p2p for CCQ: %w", err)
467474
}
468475
defer ccq.close()

node/pkg/p2p/run_params.go

+22
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ type (
6060
ccqBootstrapPeers string
6161
ccqPort uint
6262
ccqAllowedPeers string
63+
protectedPeers []string
64+
ccqProtectedPeers []string
6365
}
6466

6567
// RunOpt is used to specify optional parameters.
@@ -162,6 +164,22 @@ func WithDisableHeartbeatVerify(disableHeartbeatVerify bool) RunOpt {
162164
}
163165
}
164166

167+
// WithProtectedPeers is used to set the protected peers.
168+
func WithProtectedPeers(protectedPeers []string) RunOpt {
169+
return func(p *RunParams) error {
170+
p.protectedPeers = protectedPeers
171+
return nil
172+
}
173+
}
174+
175+
// WithCcqProtectedPeers is used to set the protected peers for CCQ.
176+
func WithCcqProtectedPeers(ccqProtectedPeers []string) RunOpt {
177+
return func(p *RunParams) error {
178+
p.ccqProtectedPeers = ccqProtectedPeers
179+
return nil
180+
}
181+
}
182+
165183
// WithGuardianOptions is used to set options that are only meaningful to the guardian.
166184
func WithGuardianOptions(
167185
nodeName string,
@@ -185,6 +203,8 @@ func WithGuardianOptions(
185203
ccqBootstrapPeers string,
186204
ccqPort uint,
187205
ccqAllowedPeers string,
206+
protectedPeers []string,
207+
ccqProtectedPeers []string,
188208
) RunOpt {
189209
return func(p *RunParams) error {
190210
p.nodeName = nodeName
@@ -208,6 +228,8 @@ func WithGuardianOptions(
208228
p.ccqBootstrapPeers = ccqBootstrapPeers
209229
p.ccqPort = ccqPort
210230
p.ccqAllowedPeers = ccqAllowedPeers
231+
p.protectedPeers = protectedPeers
232+
p.ccqProtectedPeers = ccqProtectedPeers
211233
return nil
212234
}
213235
}

node/pkg/p2p/run_params_test.go

+66-1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,57 @@ func TestRunParamsWithDisableHeartbeatVerify(t *testing.T) {
127127
assert.True(t, params.disableHeartbeatVerify)
128128
}
129129

130+
func TestRunParamsWithProtectedPeers(t *testing.T) {
131+
priv, _, err := p2pcrypto.GenerateKeyPair(p2pcrypto.Ed25519, -1)
132+
require.NoError(t, err)
133+
gst := common.NewGuardianSetState(nil)
134+
_, rootCtxCancel := context.WithCancel(context.Background())
135+
defer rootCtxCancel()
136+
137+
protectedPeers := []string{"peer1", "peer2", "peer3"}
138+
params, err := NewRunParams(
139+
bootstrapPeers,
140+
networkId,
141+
priv,
142+
gst,
143+
rootCtxCancel,
144+
WithProtectedPeers(protectedPeers),
145+
)
146+
147+
require.NoError(t, err)
148+
require.NotNil(t, params)
149+
150+
require.Equal(t, len(protectedPeers), len(params.protectedPeers))
151+
assert.Equal(t, protectedPeers[0], params.protectedPeers[0])
152+
assert.Equal(t, protectedPeers[1], params.protectedPeers[1])
153+
assert.Equal(t, protectedPeers[2], params.protectedPeers[2])
154+
}
155+
156+
func TestRunParamsWithCcqProtectedPeers(t *testing.T) {
157+
priv, _, err := p2pcrypto.GenerateKeyPair(p2pcrypto.Ed25519, -1)
158+
require.NoError(t, err)
159+
gst := common.NewGuardianSetState(nil)
160+
_, rootCtxCancel := context.WithCancel(context.Background())
161+
defer rootCtxCancel()
162+
163+
ccqProtectedPeers := []string{"peerA", "peerB"}
164+
params, err := NewRunParams(
165+
bootstrapPeers,
166+
networkId,
167+
priv,
168+
gst,
169+
rootCtxCancel,
170+
WithCcqProtectedPeers(ccqProtectedPeers),
171+
)
172+
173+
require.NoError(t, err)
174+
require.NotNil(t, params)
175+
176+
require.Equal(t, len(ccqProtectedPeers), len(params.ccqProtectedPeers))
177+
assert.Equal(t, ccqProtectedPeers[0], params.ccqProtectedPeers[0])
178+
assert.Equal(t, ccqProtectedPeers[1], params.ccqProtectedPeers[1])
179+
}
180+
130181
func TestRunParamsWithGuardianOptions(t *testing.T) {
131182
priv, _, err := p2pcrypto.GenerateKeyPair(p2pcrypto.Ed25519, -1)
132183
require.NoError(t, err)
@@ -159,6 +210,8 @@ func TestRunParamsWithGuardianOptions(t *testing.T) {
159210
ccqBootstrapPeers := "some bootstrap string"
160211
ccqPort := uint(4242)
161212
ccqAllowedPeers := "some allowed peers"
213+
protectedPeers := []string{"peer1", "peer2", "peer3"}
214+
ccqProtectedPeers := []string{"peerA", "peerB"}
162215

163216
params, err := NewRunParams(
164217
bootstrapPeers,
@@ -187,7 +240,10 @@ func TestRunParamsWithGuardianOptions(t *testing.T) {
187240
queryResponseReadC,
188241
ccqBootstrapPeers,
189242
ccqPort,
190-
ccqAllowedPeers),
243+
ccqAllowedPeers,
244+
protectedPeers,
245+
ccqProtectedPeers,
246+
),
191247
)
192248

193249
require.NoError(t, err)
@@ -210,4 +266,13 @@ func TestRunParamsWithGuardianOptions(t *testing.T) {
210266
assert.Equal(t, ccqBootstrapPeers, params.ccqBootstrapPeers)
211267
assert.Equal(t, ccqPort, params.ccqPort)
212268
assert.Equal(t, ccqAllowedPeers, params.ccqAllowedPeers)
269+
270+
require.Equal(t, len(protectedPeers), len(params.protectedPeers))
271+
assert.Equal(t, protectedPeers[0], params.protectedPeers[0])
272+
assert.Equal(t, protectedPeers[1], params.protectedPeers[1])
273+
assert.Equal(t, protectedPeers[2], params.protectedPeers[2])
274+
275+
require.Equal(t, len(ccqProtectedPeers), len(params.ccqProtectedPeers))
276+
assert.Equal(t, ccqProtectedPeers[0], params.ccqProtectedPeers[0])
277+
assert.Equal(t, ccqProtectedPeers[1], params.ccqProtectedPeers[1])
213278
}

node/pkg/p2p/watermark_test.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,16 @@ func startGuardian(t *testing.T, ctx context.Context, g *G) {
190190
g.gov,
191191
g.disableHeartbeatVerify,
192192
g.components,
193-
nil, //g.ibcFeaturesFunc,
194-
false, // gateway relayer enabled
195-
false, // ccqEnabled
196-
nil, // signed query request channel
197-
nil, // query response channel
198-
"", // query bootstrap peers
199-
0, // query port
200-
"", // query allowed peers),
193+
nil, //g.ibcFeaturesFunc,
194+
false, // gateway relayer enabled
195+
false, // ccqEnabled
196+
nil, // signed query request channel
197+
nil, // query response channel
198+
"", // query bootstrap peers
199+
0, // query port
200+
"", // query allowed peers),
201+
[]string{}, // protected peers
202+
[]string{}, // ccq protected peers
201203
))
202204
require.NoError(t, err)
203205

0 commit comments

Comments
 (0)