Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 15 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@
"env": {},
"showLog": true,
"trace": "verbose"
},
},
{
"name": "Cascade E2E (test-cascade)",
"type": "go",
"request": "launch",
"mode": "test",
"program": "${workspaceFolder}/tests/system",
"cwd": "${workspaceFolder}/tests/system",
"args": ["-test.run", "TestCascadeE2E", "-test.v"],
"buildFlags": "-tags=system_test",
"env": {},
"showLog": true,
"trace": "verbose"
}
]
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ require (
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/DataDog/datadog-go v4.8.3+incompatible // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ github.com/LumeraProtocol/lumera v1.8.6-rc2 h1:o4f3HOpmpk6VU+PiFOExx6F6doffLCKJU
github.com/LumeraProtocol/lumera v1.8.6-rc2/go.mod h1:DcG+PermGhl5uA51VaSA0EC+FXpDVm2XgifmYL9jJvE=
github.com/LumeraProtocol/rq-go v0.2.1 h1:8B3UzRChLsGMmvZ+UVbJsJj6JZzL9P9iYxbdUwGsQI4=
github.com/LumeraProtocol/rq-go v0.2.1/go.mod h1:APnKCZRh1Es2Vtrd2w4kCLgAyaL5Bqrkz/BURoRJ+O8=
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
Expand Down
18 changes: 18 additions & 0 deletions p2p/kademlia/dht.go
Original file line number Diff line number Diff line change
Expand Up @@ -2114,6 +2114,12 @@ func (s *DHT) IterateBatchStore(ctx context.Context, values [][]byte, typ int, i
knownNodes := make(map[string]*Node)
hashes := make([][]byte, len(values))

// In integration tests we want to exercise the Cascade pipeline and local
// storage without depending on a fully healthy DHT graph. If we cannot
// find any candidate peers to send store RPCs to, we treat this as a
// no-op success instead of failing the whole operation.
isIntegrationTest := os.Getenv("INTEGRATION_TEST") == "true"

{
f := logtrace.Fields{logtrace.FieldModule: "dht", "task_id": id, "keys": len(values), "len_nodes": len(s.ht.nodes()), logtrace.FieldRole: "client"}
if o := logtrace.OriginFromContext(ctx); o != "" {
Expand Down Expand Up @@ -2143,6 +2149,18 @@ func (s *DHT) IterateBatchStore(ctx context.Context, values [][]byte, typ int, i
successful := 0

logtrace.Debug(ctx, "Iterate batch store: dispatching to nodes", logtrace.Fields{"task_id": id, "nodes": len(knownNodes)})

// If there are no candidate nodes and we're running under the integration
// test harness, skip the network fan-out and report success so higher
// layers (Cascade tests) can proceed.
if len(knownNodes) == 0 && isIntegrationTest {
logtrace.Info(ctx, "dht: batch store skipped (no candidate nodes in integration test)", logtrace.Fields{
logtrace.FieldModule: "dht",
"task_id": id,
"keys": len(values),
})
return nil
}
storeResponses := s.batchStoreNetwork(ctx, values, knownNodes, storageMap, typ)
for response := range storeResponses {
requests++
Expand Down
57 changes: 39 additions & 18 deletions pkg/lumera/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,21 @@ import (
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/bank"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/node"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/supernode"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/supernode_msg"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/tx"
)

type lumeraClient struct {
cfg *Config
authMod auth.Module
actionMod action.Module
actionMsgMod action_msg.Module
bankMod bank.Module
supernodeMod supernode.Module
txMod tx.Module
nodeMod node.Module
conn Connection
cfg *Config
authMod auth.Module
actionMod action.Module
actionMsgMod action_msg.Module
bankMod bank.Module
supernodeMod supernode.Module
supernodeMsgMod supernode_msg.Module
txMod tx.Module
nodeMod node.Module
conn Connection
}

func newClient(ctx context.Context, cfg *Config) (Client, error) {
Expand Down Expand Up @@ -93,16 +95,31 @@ func newClient(ctx context.Context, cfg *Config) (Client, error) {
return nil, err
}

supernodeMsgModule, err := supernode_msg.NewModule(
conn.GetConn(),
authModule,
txModule,
supernodeModule,
cfg.keyring,
cfg.KeyName,
cfg.ChainID,
)
if err != nil {
conn.Close()
return nil, err
}

return &lumeraClient{
cfg: cfg,
authMod: authModule,
actionMod: actionModule,
actionMsgMod: actionMsgModule,
bankMod: bankModule,
supernodeMod: supernodeModule,
txMod: txModule,
nodeMod: nodeModule,
conn: conn,
cfg: cfg,
authMod: authModule,
actionMod: actionModule,
actionMsgMod: actionMsgModule,
bankMod: bankModule,
supernodeMod: supernodeModule,
supernodeMsgMod: supernodeMsgModule,
txMod: txModule,
nodeMod: nodeModule,
conn: conn,
}, nil
}

Expand All @@ -126,6 +143,10 @@ func (c *lumeraClient) SuperNode() supernode.Module {
return c.supernodeMod
}

func (c *lumeraClient) SuperNodeMsg() supernode_msg.Module {
return c.supernodeMsgMod
}

func (c *lumeraClient) Tx() tx.Module {
return c.txMod
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/lumera/codec/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"sync"

actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types"
sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
Expand Down Expand Up @@ -49,7 +50,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
cryptocodec.RegisterInterfaces(registry)
authtypes.RegisterInterfaces(registry)
actiontypes.RegisterInterfaces(registry)
// Add more interface registrations here as you add more modules
sntypes.RegisterInterfaces(registry)
}

// GetEncodingConfig returns the standard encoding config for Lumera client
Expand Down
2 changes: 2 additions & 0 deletions pkg/lumera/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/bank"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/node"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/supernode"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/supernode_msg"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/tx"
)

Expand All @@ -19,6 +20,7 @@ type Client interface {
Action() action.Module
ActionMsg() action_msg.Module
SuperNode() supernode.Module
SuperNodeMsg() supernode_msg.Module
Bank() bank.Module
Tx() tx.Module
Node() node.Module
Expand Down
93 changes: 93 additions & 0 deletions pkg/lumera/modules/supernode_msg/impl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package supernode_msg

import (
"context"
"fmt"
"strings"
"sync"

sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/auth"
snquery "github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/supernode"
txmod "github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/tx"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdktypes "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"google.golang.org/grpc"
)

// module implements the Module interface for supernode-related transactions.
type module struct {
client sntypes.MsgClient
query snquery.Module
txHelper *txmod.TxHelper
mu sync.Mutex
}

// newModule creates a new supernode_msg module instance.
func newModule(
conn *grpc.ClientConn,
authmodule auth.Module,
txmodule txmod.Module,
supernodeQuery snquery.Module,
kr keyring.Keyring,
keyName string,
chainID string,
) (Module, error) {
if conn == nil {
return nil, fmt.Errorf("connection cannot be nil")
}
if authmodule == nil {
return nil, fmt.Errorf("auth module cannot be nil")
}
if txmodule == nil {
return nil, fmt.Errorf("tx module cannot be nil")
}
if supernodeQuery == nil {
return nil, fmt.Errorf("supernode query module cannot be nil")
}
if kr == nil {
return nil, fmt.Errorf("keyring cannot be nil")
}
if strings.TrimSpace(keyName) == "" {
return nil, fmt.Errorf("key name cannot be empty")
}
if strings.TrimSpace(chainID) == "" {
return nil, fmt.Errorf("chain ID cannot be empty")
}

return &module{
client: sntypes.NewMsgClient(conn),
query: supernodeQuery,
txHelper: txmod.NewTxHelperWithDefaults(authmodule, txmodule, chainID, keyName, kr),
}, nil
}

// ReportMetrics resolves on-chain supernode info and submits a
// MsgReportSupernodeMetrics transaction containing the provided metrics.
func (m *module) ReportMetrics(ctx context.Context, identity string, metrics sntypes.SupernodeMetrics) (*sdktx.BroadcastTxResponse, error) {

Check failure on line 68 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / unit-tests

undefined: sntypes.SupernodeMetrics

Check failure on line 68 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / integration-tests

undefined: sntypes.SupernodeMetrics

Check failure on line 68 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / cascade-e2e-tests

undefined: sntypes.SupernodeMetrics

Check failure on line 68 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / build

undefined: sntypes.SupernodeMetrics

Check failure on line 68 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / build

undefined: sntypes.SupernodeMetrics
identity = strings.TrimSpace(identity)
if identity == "" {
return nil, fmt.Errorf("identity is empty")
}

m.mu.Lock()
defer m.mu.Unlock()

// Resolve validator and supernode account using the query module.
snInfo, err := m.query.GetSupernodeWithLatestAddress(ctx, identity)
if err != nil {
return nil, fmt.Errorf("failed to resolve supernode info: %w", err)
}
if snInfo == nil || snInfo.ValidatorAddress == "" || snInfo.SupernodeAccount == "" {
return nil, fmt.Errorf("incomplete supernode info for identity %s", identity)
}

return m.txHelper.ExecuteTransaction(ctx, func(_ string) (sdktypes.Msg, error) {
return &sntypes.MsgReportSupernodeMetrics{

Check failure on line 87 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / unit-tests

undefined: sntypes.MsgReportSupernodeMetrics

Check failure on line 87 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / integration-tests

undefined: sntypes.MsgReportSupernodeMetrics

Check failure on line 87 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / cascade-e2e-tests

undefined: sntypes.MsgReportSupernodeMetrics

Check failure on line 87 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / build

undefined: sntypes.MsgReportSupernodeMetrics

Check failure on line 87 in pkg/lumera/modules/supernode_msg/impl.go

View workflow job for this annotation

GitHub Actions / build

undefined: sntypes.MsgReportSupernodeMetrics
ValidatorAddress: snInfo.ValidatorAddress,
SupernodeAccount: snInfo.SupernodeAccount,
Metrics: metrics,
}, nil
})
}
37 changes: 37 additions & 0 deletions pkg/lumera/modules/supernode_msg/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//go:generate mockgen -destination=supernode_msg_mock.go -package=supernode_msg -source=interface.go
package supernode_msg

import (
"context"

"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/auth"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/supernode"
"github.com/LumeraProtocol/supernode/v2/pkg/lumera/modules/tx"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"google.golang.org/grpc"

sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types"
)

// Module defines the interface for sending supernode-related transactions,
// such as reporting metrics for LEP-4 compliance.
type Module interface {
// ReportMetrics resolves on-chain supernode info for the given identity,
// builds a MsgReportSupernodeMetrics, and broadcasts it.
ReportMetrics(ctx context.Context, identity string, metrics sntypes.SupernodeMetrics) (*sdktx.BroadcastTxResponse, error)

Check failure on line 22 in pkg/lumera/modules/supernode_msg/interface.go

View workflow job for this annotation

GitHub Actions / unit-tests

undefined: sntypes.SupernodeMetrics

Check failure on line 22 in pkg/lumera/modules/supernode_msg/interface.go

View workflow job for this annotation

GitHub Actions / integration-tests

undefined: sntypes.SupernodeMetrics

Check failure on line 22 in pkg/lumera/modules/supernode_msg/interface.go

View workflow job for this annotation

GitHub Actions / cascade-e2e-tests

undefined: sntypes.SupernodeMetrics

Check failure on line 22 in pkg/lumera/modules/supernode_msg/interface.go

View workflow job for this annotation

GitHub Actions / build

undefined: sntypes.SupernodeMetrics

Check failure on line 22 in pkg/lumera/modules/supernode_msg/interface.go

View workflow job for this annotation

GitHub Actions / build

undefined: sntypes.SupernodeMetrics
}

// NewModule constructs a supernode_msg Module using the shared auth and tx
// modules, the supernode query module, and keyring configuration.
func NewModule(
conn *grpc.ClientConn,
authmod auth.Module,
txmod tx.Module,
supernodeQuery supernode.Module,
kr keyring.Keyring,
keyName string,
chainID string,
) (Module, error) {
return newModule(conn, authmod, txmod, supernodeQuery, kr, keyName, chainID)
}
Loading
Loading