Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b914ea1
feat(net): remove Boar bootstrap nodes and replace with operator peers
lrsaturnino Mar 25, 2026
f097b5e
chore: remove migration guide from release branch
lrsaturnino Mar 25, 2026
25c1abc
feat(config): set beta staker as mainnet embedded peer
lrsaturnino Mar 25, 2026
c5faea7
fix(ci): run Go tests across all packages
piotr-roslaniec Mar 25, 2026
c33c218
fix(config): correct testnet peer hostnames in test expectations
piotr-roslaniec Mar 25, 2026
68e8c8d
refactor(clientinfo): remove over-specified metric constant tests
piotr-roslaniec Mar 25, 2026
16ea00f
refactor(firewall): make EmptyAllowList a function instead of exporte…
piotr-roslaniec Mar 25, 2026
3b1aee7
docs(clientinfo): document metric rename from connected_bootstrap_count
piotr-roslaniec Mar 25, 2026
8e7712e
chore(cmd): add v3.0 removal timeline for deprecated bootstrap flag
piotr-roslaniec Mar 25, 2026
834b63a
docs(config): document mainnet single-peer SPOF risk
piotr-roslaniec Mar 25, 2026
9508fb5
fix(tbtcpg): use format string in fmt.Errorf to fix go vet error
piotr-roslaniec Mar 25, 2026
57f5358
test(tbtc): stabilize coordination layer assertion
piotr-roslaniec Mar 26, 2026
16ace1b
fix(ci): run Go tests across all packages (#3910)
piotr-roslaniec Mar 27, 2026
14792f6
fix(ci): run Go tests across all packages
piotr-roslaniec Mar 25, 2026
139c7e1
fix(config): correct testnet peer hostnames in test expectations
piotr-roslaniec Mar 25, 2026
6b43715
refactor(clientinfo): remove over-specified metric constant tests
piotr-roslaniec Mar 25, 2026
df8a47d
refactor(firewall): make EmptyAllowList a function instead of exporte…
piotr-roslaniec Mar 25, 2026
b3ad46d
docs(clientinfo): document metric rename from connected_bootstrap_count
piotr-roslaniec Mar 25, 2026
ff48882
chore(cmd): add v3.0 removal timeline for deprecated bootstrap flag
piotr-roslaniec Mar 25, 2026
3f5307e
docs(config): document mainnet single-peer SPOF risk
piotr-roslaniec Mar 25, 2026
3c58b76
fix(tbtcpg): use format string in fmt.Errorf to fix go vet error
piotr-roslaniec Mar 25, 2026
a8bdaeb
test(tbtc): stabilize coordination layer assertion
piotr-roslaniec Mar 26, 2026
5a6bb93
fix(ci): run Go tests across all packages (#3910)
piotr-roslaniec Mar 27, 2026
cc30229
Merge branch 'feature/decouple-firewall-allowlist' of https://github.…
lrsaturnino Apr 3, 2026
2545897
fix(chain/local_v1): prevent double-close panic in block counter watcher
lrsaturnino Apr 3, 2026
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
2 changes: 1 addition & 1 deletion cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func initNetworkFlags(cmd *cobra.Command, cfg *config.Config) {
&cfg.LibP2P.Bootstrap,
"network.bootstrap",
false,
"Run the client in bootstrap mode.",
"[DEPRECATED] Run the client in bootstrap mode. This flag is deprecated and will be removed in a future release.",
)

cmd.Flags().StringSliceVar(
Expand Down
17 changes: 5 additions & 12 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ func start(cmd *cobra.Command) error {
}

func isBootstrap() bool {
if clientConfig.LibP2P.Bootstrap {
logger.Warnf("--network.bootstrap is deprecated and will be removed in a future release")
}
return clientConfig.LibP2P.Bootstrap
}

Expand All @@ -197,19 +200,9 @@ func initializeNetwork(
operatorPrivateKey *operator.PrivateKey,
blockCounter chain.BlockCounter,
) (net.Provider, error) {
bootstrapPeersPublicKeys, err := libp2p.ExtractPeersPublicKeys(
clientConfig.LibP2P.Peers,
)
if err != nil {
return nil, fmt.Errorf(
"error extracting bootstrap peers public keys: [%v]",
err,
)
}

firewall := firewall.AnyApplicationPolicy(
applications,
firewall.NewAllowList(bootstrapPeersPublicKeys),
firewall.EmptyAllowList,
)

netProvider, err := libp2p.Connect(
Expand Down Expand Up @@ -244,7 +237,7 @@ func initializeClientInfo(
config.ClientInfo.NetworkMetricsTick,
)

registry.ObserveConnectedBootstrapCount(
registry.ObserveConnectedWellknownPeersCount(
netProvider,
config.LibP2P.Peers,
config.ClientInfo.NetworkMetricsTick,
Expand Down
59 changes: 59 additions & 0 deletions cmd/start_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cmd

import (
"strings"
"testing"

"github.com/keep-network/keep-core/config"
"github.com/spf13/cobra"
)

func TestNetworkBootstrapFlagDescription_ContainsDeprecationNotice(t *testing.T) {
cmd := &cobra.Command{Use: "test"}
cfg := &config.Config{}

initNetworkFlags(cmd, cfg)

flag := cmd.Flags().Lookup("network.bootstrap")
if flag == nil {
t.Fatal("expected network.bootstrap flag to be registered")
}

usageLower := strings.ToLower(flag.Usage)
if !strings.Contains(usageLower, "deprecated") {
t.Errorf(
"expected flag description to contain deprecation notice, got: %q",
flag.Usage,
)
}
}

func TestIsBootstrap(t *testing.T) {
tests := map[string]struct {
bootstrapValue bool
expected bool
}{
"returns true when bootstrap flag is set": {
bootstrapValue: true,
expected: true,
},
"returns false when bootstrap flag is not set": {
bootstrapValue: false,
expected: false,
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
originalBootstrap := clientConfig.LibP2P.Bootstrap
defer func() { clientConfig.LibP2P.Bootstrap = originalBootstrap }()

clientConfig.LibP2P.Bootstrap = tc.bootstrapValue

got := isBootstrap()
if got != tc.expected {
t.Errorf("expected isBootstrap() to return %v, got %v", tc.expected, got)
}
})
}
}
3 changes: 1 addition & 2 deletions config/_peers/mainnet
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
/dns4/bst-a01.tbtc.boar.network/tcp/5001/ipfs/16Uiu2HAmAmCrLuUmnBgpavU8y8JBUN6jWAQ93JwydZy3ABRyY6wU
/dns4/bst-b01.tbtc.boar.network/tcp/5001/ipfs/16Uiu2HAm4w5HdJQxBnadGRepaiGfWVvtMzhdAGZVcrf9i71mv69V
/ip4/143.198.18.229/tcp/3919/ipfs/16Uiu2HAmDP4Z6LCogRMictJ6deGs4DRo99A5JTz5u3CLMg7URxC6
3 changes: 2 additions & 1 deletion config/_peers/testnet
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/dns4/bst-a01.test.keep.boar.network/tcp/6001/ipfs/16Uiu2HAmSLDSahiKyTbCNNu8wJmZAsiKF7wuYJ8mogY8ZuAG1jhu
/dns4/keep-operator-1.test.keep-nodes.io/tcp/3920/ipfs/16Uiu2HAmDrk2Bh4VNPUJfKRHTE2CvH9xfKzN4KFnmRJbGLkJFDqL
/dns4/keep-operator-2.test.keep-nodes.io/tcp/3920/ipfs/16Uiu2HAm3ex8rGzwFpWYbRreRUiX9JEYCKxp7KDMzB8RZ6fQWnMa
6 changes: 3 additions & 3 deletions config/peers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ func TestResolvePeers(t *testing.T) {
"mainnet network": {
network: network.Mainnet,
expectedPeers: []string{
"/dns4/bst-a01.tbtc.boar.network/tcp/5001/ipfs/16Uiu2HAmAmCrLuUmnBgpavU8y8JBUN6jWAQ93JwydZy3ABRyY6wU",
"/dns4/bst-b01.tbtc.boar.network/tcp/5001/ipfs/16Uiu2HAm4w5HdJQxBnadGRepaiGfWVvtMzhdAGZVcrf9i71mv69V",
"/ip4/143.198.18.229/tcp/3919/ipfs/16Uiu2HAmDP4Z6LCogRMictJ6deGs4DRo99A5JTz5u3CLMg7URxC6",
}},
"sepolia network": {
network: network.Testnet,
expectedPeers: []string{
"/dns4/bst-a01.test.keep.boar.network/tcp/6001/ipfs/16Uiu2HAmSLDSahiKyTbCNNu8wJmZAsiKF7wuYJ8mogY8ZuAG1jhu",
"/dns4/PLACEHOLDER-operator-1.test.example.com/tcp/3920/ipfs/16Uiu2HAmDrk2Bh4VNPUJfKRHTE2CvH9xfKzN4KFnmRJbGLkJFDqL",
"/dns4/PLACEHOLDER-operator-2.test.example.com/tcp/3920/ipfs/16Uiu2HAm3ex8rGzwFpWYbRreRUiX9JEYCKxp7KDMzB8RZ6fQWnMa",
},
},
"developer network": {
Expand Down
22 changes: 11 additions & 11 deletions pkg/clientinfo/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ type Source func() float64

// Names under which metrics are exposed.
const (
ConnectedPeersCountMetricName = "connected_peers_count"
ConnectedBootstrapCountMetricName = "connected_bootstrap_count"
EthConnectivityMetricName = "eth_connectivity"
BtcConnectivityMetricName = "btc_connectivity"
ClientInfoMetricName = "client_info"
ConnectedPeersCountMetricName = "connected_peers_count"
ConnectedWellknownPeersCountMetricName = "connected_wellknown_peers_count"
EthConnectivityMetricName = "eth_connectivity"
BtcConnectivityMetricName = "btc_connectivity"
ClientInfoMetricName = "client_info"
)

const (
Expand Down Expand Up @@ -55,17 +55,17 @@ func (r *Registry) ObserveConnectedPeersCount(
)
}

// ObserveConnectedBootstrapCount triggers an observation process of the
// connected_bootstrap_count metric.
func (r *Registry) ObserveConnectedBootstrapCount(
// ObserveConnectedWellknownPeersCount triggers an observation process of the
// connected_wellknown_peers_count metric.
func (r *Registry) ObserveConnectedWellknownPeersCount(
netProvider net.Provider,
bootstraps []string,
wellknownPeers []string,
tick time.Duration,
) {
input := func() float64 {
currentCount := 0

for _, address := range bootstraps {
for _, address := range wellknownPeers {
if netProvider.ConnectionManager().IsConnected(address) {
currentCount++
}
Expand All @@ -75,7 +75,7 @@ func (r *Registry) ObserveConnectedBootstrapCount(
}

r.observe(
ConnectedBootstrapCountMetricName,
ConnectedWellknownPeersCountMetricName,
input,
validateTick(tick, DefaultNetworkMetricsTick),
)
Expand Down
159 changes: 159 additions & 0 deletions pkg/clientinfo/metrics_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package clientinfo

import (
"context"
"testing"
"time"

keepclientinfo "github.com/keep-network/keep-common/pkg/clientinfo"
"github.com/keep-network/keep-core/pkg/net"
"github.com/keep-network/keep-core/pkg/operator"
)

// TestConnectedWellknownPeersCountMetricName verifies that the metric constant
// for well-known peers connectivity has the correct string value used by
// Prometheus for metric registration.
func TestConnectedWellknownPeersCountMetricName(t *testing.T) {
expected := "connected_wellknown_peers_count"
actual := ConnectedWellknownPeersCountMetricName

if actual != expected {
t.Errorf(
"expected metric name %q, got %q",
expected,
actual,
)
}
}

// TestMetricConstants verifies that all metric name constants are defined with
// the expected non-empty string values. This ensures no accidental changes to
// metric names that would break Prometheus queries and Grafana dashboards.
func TestMetricConstants(t *testing.T) {
tests := []struct {
name string
constant string
expected string
}{
{
name: "connected peers count",
constant: ConnectedPeersCountMetricName,
expected: "connected_peers_count",
},
{
name: "connected wellknown peers count",
constant: ConnectedWellknownPeersCountMetricName,
expected: "connected_wellknown_peers_count",
},
{
name: "eth connectivity",
constant: EthConnectivityMetricName,
expected: "eth_connectivity",
},
{
name: "btc connectivity",
constant: BtcConnectivityMetricName,
expected: "btc_connectivity",
},
{
name: "client info",
constant: ClientInfoMetricName,
expected: "client_info",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
if tc.constant != tc.expected {
t.Errorf(
"expected metric name %q, got %q",
tc.expected,
tc.constant,
)
}
if tc.constant == "" {
t.Error("metric name constant must not be empty")
}
})
}
}

// mockTransportIdentifier implements net.TransportIdentifier for testing.
type mockTransportIdentifier struct{}

func (m *mockTransportIdentifier) String() string { return "mock-id" }

// mockConnectionManager implements net.ConnectionManager for testing.
type mockConnectionManager struct {
connectedAddresses map[string]bool
}

func (m *mockConnectionManager) ConnectedPeers() []string { return nil }
func (m *mockConnectionManager) ConnectedPeersAddrInfo() map[string][]string {
return nil
}
func (m *mockConnectionManager) GetPeerPublicKey(string) (*operator.PublicKey, error) {
return nil, nil
}
func (m *mockConnectionManager) DisconnectPeer(string) {}
func (m *mockConnectionManager) AddrStrings() []string { return nil }
func (m *mockConnectionManager) IsConnected(address string) bool {
if m.connectedAddresses == nil {
return false
}
return m.connectedAddresses[address]
}

// mockProvider implements net.Provider for testing.
type mockProvider struct {
connectionManager net.ConnectionManager
}

func (m *mockProvider) ID() net.TransportIdentifier { return &mockTransportIdentifier{} }
func (m *mockProvider) Type() string { return "mock" }
func (m *mockProvider) BroadcastChannelFor(string) (net.BroadcastChannel, error) {
return nil, nil
}
func (m *mockProvider) ConnectionManager() net.ConnectionManager {
return m.connectionManager
}
func (m *mockProvider) CreateTransportIdentifier(
*operator.PublicKey,
) (net.TransportIdentifier, error) {
return nil, nil
}
func (m *mockProvider) BroadcastChannelForwarderFor(string) {}

// TestObserveConnectedWellknownPeersCount_Callable verifies that the renamed
// function exists on the Registry type and can be called without panicking.
func TestObserveConnectedWellknownPeersCount_Callable(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

registry := &Registry{keepclientinfo.NewRegistry(), ctx}

provider := &mockProvider{
connectionManager: &mockConnectionManager{
connectedAddresses: map[string]bool{
"/ip4/127.0.0.1/tcp/3919": true,
},
},
}

// The function should execute without panic. We use a recovered call
// to detect if the method does not exist or panics.
defer func() {
if r := recover(); r != nil {
t.Fatalf(
"ObserveConnectedWellknownPeersCount panicked: %v",
r,
)
}
}()

registry.ObserveConnectedWellknownPeersCount(
provider,
[]string{"/ip4/127.0.0.1/tcp/3919"},
1*time.Minute,
)
}
Loading
Loading