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
3 changes: 1 addition & 2 deletions .github/workflows/systemtests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,5 @@ jobs:
working-directory: tests/systemtests

- name: Run System Tests
run: go test -tags=system_test -v .
run: go test -tags=system_test -timeout 20m -v .
working-directory: tests/systemtests

2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DO NOT PUSH ANY CHANGES TO REMOTE
DO NOT BUILD OR TEST using cache if sandbox doesnt all building/testing directly
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ release:
###################################################
### Tests and Simulation ###
###################################################
.PHONY: unit-tests integration-tests system-tests simulation-tests all-tests lint
.PHONY: unit-tests integration-tests system-tests simulation-tests all-tests lint system-metrics-test

all-tests: unit-tests integration-tests system-tests simulation-tests

Expand Down Expand Up @@ -143,3 +143,7 @@ simulation-tests:
systemex-tests:
@echo "Running system tests..."
cd ./tests/systemtests/ && go test -tags=system_test -v .

system-metrics-test:
@echo "Running supernode metrics system tests (E2E + staleness)..."
cd ./tests/systemtests/ && go test -tags=system_test -timeout 20m -v . -run 'TestSupernodeMetrics(E2E|StalenessAndRecovery)'
12 changes: 6 additions & 6 deletions buf.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ deps:
commit: dc427cb4519143d8996361c045a29ad7
digest: b5:8693e72e230bfaf58a88a47a4093ba99f6252c1957a45582567959b38a8563e2abd11443372283d75f4f2306a7e3cc9bf63604d284a016c11966fca4b74b7a28
- name: buf.build/cosmwasm/wasmd
commit: eba0d83e199b42cfab463d808663201d
digest: b5:6b018f71041c1db3df0f5d59e2a82fab6eeddf92dc6454e040ea3a138241f25ea3074f71bdb5dce576d3b80d1a426e45ac7a8e9959d40d189582c7d1a0826aeb
commit: 65537c618a924482b0d5ed51230d92dd
digest: b5:318583e5fbf4c8a0f651648509d5ccccb57fd8a6c1c7bb70df261b155367728ba5804450c5ae05b9e60d2c59a62e36a2ec88bf2822d749f54d286c1b0170b9f5
- name: buf.build/googleapis/googleapis
commit: 72c8614f3bd0466ea67931ef2c43d608
digest: b5:13efeea24e633fd45327390bdee941207a8727e96cf01affb84c1e4100fd8f48a42bbd508df11930cd2884629bafad685df1ac3111bc78cdaefcd38c9371c6b1
commit: 004180b77378443887d3b55cabc00384
digest: b5:e8f475fe3330f31f5fd86ac689093bcd274e19611a09db91f41d637cb9197881ce89882b94d13a58738e53c91c6e4bae7dc1feba85f590164c975a89e25115dc
- name: buf.build/protocolbuffers/wellknowntypes
commit: 9220c3cb4fac4bb4a8587d4fd7aa7582
digest: b5:412c81d3f1549cc9ef52b364a11ab41d9ea6ba5e8e22a2b3f1f614c180b991a76503d715574e94ff77e33f216a1614a8026f1fc01aeaefdaf701155cb125e8bc
commit: 4e1ccfa6827947beb55974645a315b8d
digest: b5:eb5228b1abd02064d6ff0248918500c1ec1ce7df69126af3f220c0b67d81ff45bdf9f016a8e66cd9c1e534f18afc6d8e090d400604c5331d551a68d05f7e7be9
4 changes: 2 additions & 2 deletions docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ const (
indexFile = "template/index.tpl"
)

//go:embed static
//go:embed static/*
var Static embed.FS

//go:embed template
//go:embed template/*
var template embed.FS

func RegisterOpenAPIService(appName string, rtr *mux.Router) {
Expand Down
2 changes: 1 addition & 1 deletion docs/static/openapi.yml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ require (
github.com/CosmWasm/wasmd v0.55.0-ibc2.0
github.com/CosmWasm/wasmvm/v3 v3.0.0-ibc2.0
github.com/DataDog/zstd v1.5.7
github.com/Masterminds/semver/v3 v3.3.1
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
github.com/cometbft/cometbft v0.38.18
github.com/cosmos/btcutil v1.0.5
Expand Down Expand Up @@ -102,7 +103,6 @@ require (
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
Expand Down
57 changes: 57 additions & 0 deletions proto/lumera/supernode/v1/metrics.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
syntax = "proto3";
package lumera.supernode.v1;

option go_package = "x/supernode/v1/types";

import "gogoproto/gogo.proto";

// PortState defines tri-state port reporting. UNKNOWN is the default for proto3
// and is treated as "not reported / not measured".
enum PortState {
PORT_STATE_UNKNOWN = 0;
PORT_STATE_OPEN = 1;
PORT_STATE_CLOSED = 2;
}

// PortStatus reports the state of a specific TCP port.
message PortStatus {
uint32 port = 1;
PortState state = 2;
}

// SupernodeMetrics defines the structured metrics reported by a supernode.
message SupernodeMetrics {
// Semantic version of the supernode software.
uint32 version_major = 1;
uint32 version_minor = 2;
uint32 version_patch = 3;

// CPU metrics.
double cpu_cores_total = 4;
double cpu_usage_percent = 5;

// Memory metrics (GB).
double mem_total_gb = 6;
double mem_usage_percent = 7;
double mem_free_gb = 8;

// Storage metrics (GB).
double disk_total_gb = 9;
double disk_usage_percent = 10;
double disk_free_gb = 11;

// Uptime and connectivity.
double uptime_seconds = 12;
uint32 peers_count = 13;

// Tri-state port reporting for required ports.
repeated PortStatus open_ports = 14 [(gogoproto.nullable) = false];
}

// SupernodeMetricsState stores the latest metrics state for a validator.
message SupernodeMetricsState {
string validator_address = 1 [(gogoproto.moretags) = "yaml:\"validator_address\""];
SupernodeMetrics metrics = 2;
uint64 report_count = 3;
int64 height = 4;
}
23 changes: 22 additions & 1 deletion proto/lumera/supernode/v1/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,25 @@ message Params {
string evidence_retention_period = 5 [(gogoproto.moretags) = "yaml:\"evidence_retention_period\""];
string slashing_fraction = 6 [(gogoproto.moretags) = "yaml:\"slashing_fraction\""];
string inactivity_penalty_period = 7 [(gogoproto.moretags) = "yaml:\"inactivity_penalty_period\""];
}

// Expected cadence (in blocks) between supernode metrics reports. The daemon
// can run on a timer using expected block time, but the chain enforces
// height-based staleness strictly in blocks.
uint64 metrics_update_interval_blocks = 8 [(gogoproto.moretags) = "yaml:\"metrics_update_interval_blocks\""];
// Additional grace (in blocks) before marking metrics overdue/stale.
uint64 metrics_grace_period_blocks = 9 [(gogoproto.moretags) = "yaml:\"metrics_grace_period_blocks\""];
// Maximum acceptable staleness (in blocks) for a metrics report when
// validating freshness.
uint64 metrics_freshness_max_blocks = 10 [(gogoproto.moretags) = "yaml:\"metrics_freshness_max_blocks\""];

string min_supernode_version = 11 [(gogoproto.moretags) = "yaml:\"min_supernode_version\""];

uint64 min_cpu_cores = 12 [(gogoproto.moretags) = "yaml:\"min_cpu_cores\""];
uint64 max_cpu_usage_percent = 13 [(gogoproto.moretags) = "yaml:\"max_cpu_usage_percent\""];
uint64 min_mem_gb = 14 [(gogoproto.moretags) = "yaml:\"min_mem_gb\""];
uint64 max_mem_usage_percent = 15 [(gogoproto.moretags) = "yaml:\"max_mem_usage_percent\""];
uint64 min_storage_gb = 16 [(gogoproto.moretags) = "yaml:\"min_storage_gb\""];
uint64 max_storage_usage_percent = 17 [(gogoproto.moretags) = "yaml:\"max_storage_usage_percent\""];

repeated uint32 required_open_ports = 18 [(gogoproto.moretags) = "yaml:\"required_open_ports\""];
}
16 changes: 16 additions & 0 deletions proto/lumera/supernode/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import "cosmos/base/query/v1beta1/pagination.proto";
import "lumera/supernode/v1/params.proto";
import "lumera/supernode/v1/super_node.proto";
import "lumera/supernode/v1/supernode_state.proto";
import "lumera/supernode/v1/metrics.proto";

// Query defines the gRPC querier service.
service Query {
Expand Down Expand Up @@ -43,6 +44,12 @@ service Query {
option (google.api.http).get = "/LumeraProtocol/lumera/supernode/v1/get_top_super_nodes_for_block/{blockHeight}";

}

// Queries the latest metrics state for a validator.
rpc GetMetrics (QueryGetMetricsRequest) returns (QueryGetMetricsResponse) {
option (google.api.http).get = "/LumeraProtocol/lumera/supernode/v1/metrics/{validatorAddress}";

}
}

// QueryParamsRequest is request type for the Query/Params RPC method.
Expand Down Expand Up @@ -98,3 +105,12 @@ message QueryGetTopSuperNodesForBlockResponse {
repeated SuperNode supernodes = 1;
}

// QueryGetMetricsRequest is request type for the Query/GetMetrics RPC method.
message QueryGetMetricsRequest {
string validatorAddress = 1;
}

// QueryGetMetricsResponse is response type for the Query/GetMetrics RPC method.
message QueryGetMetricsResponse {
SupernodeMetricsState metrics_state = 1;
}
13 changes: 7 additions & 6 deletions proto/lumera/supernode/v1/supernode_state.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ enum SuperNodeState {
option (gogoproto.goproto_enum_prefix) = false;
option (gogoproto.goproto_enum_stringer) = true;

SUPERNODE_STATE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "SuperNodeStateUnspecified"];
SUPERNODE_STATE_ACTIVE = 1 [(gogoproto.enumvalue_customname) = "SuperNodeStateActive"];
SUPERNODE_STATE_DISABLED = 2 [(gogoproto.enumvalue_customname) = "SuperNodeStateDisabled"];
SUPERNODE_STATE_STOPPED = 3 [(gogoproto.enumvalue_customname) = "SuperNodeStateStopped"];
SUPERNODE_STATE_PENALIZED = 4 [(gogoproto.enumvalue_customname) = "SuperNodeStatePenalized"];
}
SUPERNODE_STATE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "SuperNodeStateUnspecified"];
SUPERNODE_STATE_ACTIVE = 1 [(gogoproto.enumvalue_customname) = "SuperNodeStateActive"];
SUPERNODE_STATE_DISABLED = 2 [(gogoproto.enumvalue_customname) = "SuperNodeStateDisabled"];
SUPERNODE_STATE_STOPPED = 3 [(gogoproto.enumvalue_customname) = "SuperNodeStateStopped"];
SUPERNODE_STATE_PENALIZED = 4 [(gogoproto.enumvalue_customname) = "SuperNodeStatePenalized"];
SUPERNODE_STATE_POSTPONED = 5 [(gogoproto.enumvalue_customname) = "SuperNodeStatePostponed"];
}

message SuperNodeStateRecord {
SuperNodeState state = 1 [(gogoproto.moretags) = "yaml:\"state\""];
Expand Down
14 changes: 14 additions & 0 deletions proto/lumera/supernode/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "cosmos/msg/v1/msg.proto";
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
import "lumera/supernode/v1/params.proto";
import "lumera/supernode/v1/metrics.proto";

// Msg defines the Msg service.
service Msg {
Expand All @@ -21,6 +22,7 @@ service Msg {
rpc StartSupernode (MsgStartSupernode ) returns (MsgStartSupernodeResponse );
rpc StopSupernode (MsgStopSupernode ) returns (MsgStopSupernodeResponse );
rpc UpdateSupernode (MsgUpdateSupernode ) returns (MsgUpdateSupernodeResponse );
rpc ReportSupernodeMetrics(MsgReportSupernodeMetrics) returns (MsgReportSupernodeMetricsResponse);
}
// MsgUpdateParams is the Msg/UpdateParams request type.
message MsgUpdateParams {
Expand Down Expand Up @@ -88,3 +90,15 @@ message MsgUpdateSupernode {

message MsgUpdateSupernodeResponse {}

message MsgReportSupernodeMetrics {
option (cosmos.msg.v1.signer) = "supernode_account";

string validator_address = 1 [(cosmos_proto.scalar) = "cosmos.ValidatorAddressString"];
string supernode_account = 2 [(cosmos_proto.scalar) = "cosmos.AccAddressString"];
SupernodeMetrics metrics = 3 [(gogoproto.nullable) = false];
}

message MsgReportSupernodeMetricsResponse {
bool compliant = 1;
repeated string issues = 2;
}
9 changes: 5 additions & 4 deletions tests/systemtests/claims_params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ package system

import (
"fmt"
"strconv"
"testing"
"time"
"strconv"

"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"

claimtypes "github.com/LumeraProtocol/lumera/x/claim/types"
lcfg "github.com/LumeraProtocol/lumera/config"
claimtypes "github.com/LumeraProtocol/lumera/x/claim/types"
)

// Voting Period is set to 10 seconds for faster test execution by default
Expand Down Expand Up @@ -88,9 +88,10 @@ func TestClaimsUpdateParamsProposal(t *testing.T) {
proposalID := cli.SubmitAndVoteGovProposal(proposalJson)
require.NotEmpty(t, proposalID)

// Wait for proposal to be executed
// Wait for proposal to be executed (aligned with the shortened voting period)
var proposalPassed bool
for i := 0; i < 10; i++ {
deadline := time.Now().Add(30 * time.Second)
for time.Now().Before(deadline) {
sut.AwaitNextBlock(t)
status := cli.CustomQuery("q", "gov", "proposal", proposalID)
if gjson.Get(status, "proposal.status").String() == "PROPOSAL_STATUS_PASSED" {
Expand Down
12 changes: 8 additions & 4 deletions tests/systemtests/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ func (c LumeradCli) run(args []string) (output string, ok bool) {
return c.runWithInput(args, nil)
}


func (c LumeradCli) runWithInput(args []string, input io.Reader) (output string, ok bool) {
if c.Debug {
timestamp := time.Now().Format("15:04:05.000")
Expand Down Expand Up @@ -294,16 +293,21 @@ func (c LumeradCli) GetKeyAddr(name string) string {

const defaultSrcAddr = "node0"

// FundAddress sends the token amount to the destination address
func (c LumeradCli) FundAddress(destAddr, amount string) string {
// FundAddressWithNode sends the token amount to the destination address from the given source node key.
func (c LumeradCli) FundAddressWithNode(destAddr, amount string, nodeAddr string) string {
require.NotEmpty(c.t, destAddr)
require.NotEmpty(c.t, amount)
cmd := []string{"tx", "bank", "send", defaultSrcAddr, destAddr, amount}
cmd := []string{"tx", "bank", "send", nodeAddr, destAddr, amount}
rsp := c.CustomCommand(cmd...)
RequireTxSuccess(c.t, rsp)
return rsp
}

// FundAddress sends the token amount to the destination address
func (c LumeradCli) FundAddress(destAddr, amount string) string {
return c.FundAddressWithNode(destAddr, amount, defaultSrcAddr)
}

// GetAccount returns account info for the given address
func (c LumeradCli) GetAccount(addr string) string {
require.NotEmpty(c.t, addr)
Expand Down
16 changes: 11 additions & 5 deletions tests/systemtests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.25.1

replace (
github.com/LumeraProtocol/lumera => ../../

github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.50.14
)

Expand All @@ -29,7 +30,7 @@ require (

require (
cosmossdk.io/math v1.5.3
github.com/LumeraProtocol/lumera v0.0.0-00010101000000-000000000000
github.com/LumeraProtocol/lumera v1.8.5
github.com/cometbft/cometbft v0.38.18
github.com/cosmos/cosmos-sdk v0.53.0
github.com/tidwall/gjson v1.14.2
Expand All @@ -52,6 +53,7 @@ require (
github.com/99designs/keyring v1.2.2 // indirect
github.com/DataDog/datadog-go v4.8.3+incompatible // indirect
github.com/DataDog/zstd v1.5.7 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.2.0 // indirect
Expand Down Expand Up @@ -80,12 +82,14 @@ require (
github.com/desertbit/timer v1.0.1 // indirect
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/getsentry/sentry-go v0.32.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-kit/kit v0.13.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
Expand All @@ -108,6 +112,7 @@ require (
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-metrics v0.5.4 // indirect
github.com/hashicorp/go-plugin v1.6.3 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
Expand All @@ -122,14 +127,15 @@ require (
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/linxGnu/grocksdb v1.9.2 // indirect
github.com/linxGnu/grocksdb v1.9.8 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/minio/highwayhash v1.0.3 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
Expand Down Expand Up @@ -163,9 +169,9 @@ require (
golang.org/x/sys v0.36.0 // indirect
golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.29.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
google.golang.org/protobuf v1.36.9 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 // indirect
google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.2 // indirect
nhooyr.io/websocket v1.8.17 // indirect
Expand Down
Loading
Loading