Skip to content

Commit 95710fc

Browse files
committed
audit : align with lumera changes
1 parent 6f3eebf commit 95710fc

11 files changed

Lines changed: 123 additions & 65 deletions

File tree

pkg/lumera/Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Using modules
2626
- `cli.Action()` – query actions (GetAction, GetActionFee, GetParams)
2727
- `cli.ActionMsg()` – send action messages (see below)
2828
- `cli.Audit()` – query `x/audit` (params/epochs/anchors/assignments/reports)
29-
- `cli.AuditMsg()` – submit `x/audit` txs (`MsgSubmitAuditReport`, `MsgSubmitEvidence`)
29+
- `cli.AuditMsg()` – submit `x/audit` txs (`MsgSubmitEpochReport`, `MsgSubmitEvidence`)
3030
- `cli.Auth()` – accounts/verify
3131
- `cli.SuperNode()` – supernode queries
3232
- `cli.Tx()` – tx internals (shared by helpers)

pkg/lumera/modules/audit/impl.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ func (m *module) GetAssignedTargets(ctx context.Context, supernodeAccount string
6363
return resp, nil
6464
}
6565

66-
func (m *module) GetAuditReport(ctx context.Context, epochID uint64, supernodeAccount string) (*types.QueryAuditReportResponse, error) {
67-
resp, err := m.client.AuditReport(ctx, &types.QueryAuditReportRequest{
66+
func (m *module) GetEpochReport(ctx context.Context, epochID uint64, supernodeAccount string) (*types.QueryEpochReportResponse, error) {
67+
resp, err := m.client.EpochReport(ctx, &types.QueryEpochReportRequest{
6868
EpochId: epochID,
6969
SupernodeAccount: supernodeAccount,
7070
})
7171
if err != nil {
72-
return nil, fmt.Errorf("failed to get audit report: %w", err)
72+
return nil, fmt.Errorf("failed to get epoch report: %w", err)
7373
}
7474
return resp, nil
7575
}

pkg/lumera/modules/audit/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Module interface {
1414
GetCurrentEpochAnchor(ctx context.Context) (*types.QueryCurrentEpochAnchorResponse, error)
1515
GetCurrentEpoch(ctx context.Context) (*types.QueryCurrentEpochResponse, error)
1616
GetAssignedTargets(ctx context.Context, supernodeAccount string, epochID uint64) (*types.QueryAssignedTargetsResponse, error)
17-
GetAuditReport(ctx context.Context, epochID uint64, supernodeAccount string) (*types.QueryAuditReportResponse, error)
17+
GetEpochReport(ctx context.Context, epochID uint64, supernodeAccount string) (*types.QueryEpochReportResponse, error)
1818
}
1919

2020
// NewModule creates a new Audit module client.

pkg/lumera/modules/audit_msg/audit_msg_mock.go

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/lumera/modules/audit_msg/impl.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,24 +78,23 @@ func (m *module) SubmitEvidence(ctx context.Context, subjectAddress string, evid
7878
})
7979
}
8080

81-
func (m *module) SubmitAuditReport(ctx context.Context, epochID uint64, peerObservations []*audittypes.AuditPeerObservation) (*sdktx.BroadcastTxResponse, error) {
81+
func (m *module) SubmitEpochReport(ctx context.Context, epochID uint64, hostReport audittypes.HostReport, storageChallengeObservations []*audittypes.StorageChallengeObservation) (*sdktx.BroadcastTxResponse, error) {
8282
m.mu.Lock()
8383
defer m.mu.Unlock()
8484

85-
// Intentionally submit 0% usage for CPU/memory/disk so the chain treats these as "unknown"
85+
// Intentionally submit 0% usage for CPU/memory so the chain treats these as "unknown"
8686
// (see x/audit enforcement semantics).
87-
selfReport := audittypes.AuditSelfReport{
88-
CpuUsagePercent: 0,
89-
MemUsagePercent: 0,
90-
DiskUsagePercent: 0,
91-
}
87+
//
88+
// Disk usage is expected to be reported accurately (legacy-aligned); callers provide it.
89+
hostReport.CpuUsagePercent = 0
90+
hostReport.MemUsagePercent = 0
9291

9392
return m.txHelper.ExecuteTransaction(ctx, func(creator string) (sdktypes.Msg, error) {
94-
return &audittypes.MsgSubmitAuditReport{
95-
SupernodeAccount: creator,
96-
EpochId: epochID,
97-
SelfReport: selfReport,
98-
PeerObservations: peerObservations,
93+
return &audittypes.MsgSubmitEpochReport{
94+
Creator: creator,
95+
EpochId: epochID,
96+
HostReport: hostReport,
97+
StorageChallengeObservations: storageChallengeObservations,
9998
}, nil
10099
})
101100
}

pkg/lumera/modules/audit_msg/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
// Module defines the interface for audit-related transactions.
1616
type Module interface {
1717
SubmitEvidence(ctx context.Context, subjectAddress string, evidenceType audittypes.EvidenceType, actionID string, metadataJSON string) (*sdktx.BroadcastTxResponse, error)
18-
SubmitAuditReport(ctx context.Context, epochID uint64, peerObservations []*audittypes.AuditPeerObservation) (*sdktx.BroadcastTxResponse, error)
18+
SubmitEpochReport(ctx context.Context, epochID uint64, hostReport audittypes.HostReport, storageChallengeObservations []*audittypes.StorageChallengeObservation) (*sdktx.BroadcastTxResponse, error)
1919
}
2020

2121
// NewModule creates a new audit_msg module instance.

pkg/testutil/lumera.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,8 @@ func (m *MockAuditModule) GetAssignedTargets(ctx context.Context, supernodeAccou
213213
return &audittypes.QueryAssignedTargetsResponse{}, nil
214214
}
215215

216-
func (m *MockAuditModule) GetAuditReport(ctx context.Context, epochID uint64, supernodeAccount string) (*audittypes.QueryAuditReportResponse, error) {
217-
return &audittypes.QueryAuditReportResponse{}, nil
216+
func (m *MockAuditModule) GetEpochReport(ctx context.Context, epochID uint64, supernodeAccount string) (*audittypes.QueryEpochReportResponse, error) {
217+
return &audittypes.QueryEpochReportResponse{}, nil
218218
}
219219

220220
type MockAuditMsgModule struct{}
@@ -223,7 +223,7 @@ func (m *MockAuditMsgModule) SubmitEvidence(ctx context.Context, subjectAddress
223223
return &sdktx.BroadcastTxResponse{}, nil
224224
}
225225

226-
func (m *MockAuditMsgModule) SubmitAuditReport(ctx context.Context, epochID uint64, peerObservations []*audittypes.AuditPeerObservation) (*sdktx.BroadcastTxResponse, error) {
226+
func (m *MockAuditMsgModule) SubmitEpochReport(ctx context.Context, epochID uint64, hostReport audittypes.HostReport, storageChallengeObservations []*audittypes.StorageChallengeObservation) (*sdktx.BroadcastTxResponse, error) {
227227
return &sdktx.BroadcastTxResponse{}, nil
228228
}
229229

supernode/cmd/start.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import (
2121
"github.com/LumeraProtocol/supernode/v2/pkg/storage/queries"
2222
"github.com/LumeraProtocol/supernode/v2/pkg/storage/rqstore"
2323
"github.com/LumeraProtocol/supernode/v2/pkg/task"
24-
auditReporterService "github.com/LumeraProtocol/supernode/v2/supernode/audit_reporter"
2524
cascadeService "github.com/LumeraProtocol/supernode/v2/supernode/cascade"
2625
"github.com/LumeraProtocol/supernode/v2/supernode/config"
26+
hostReporterService "github.com/LumeraProtocol/supernode/v2/supernode/host_reporter"
2727
statusService "github.com/LumeraProtocol/supernode/v2/supernode/status"
2828
storageChallengeService "github.com/LumeraProtocol/supernode/v2/supernode/storage_challenge"
2929
// Legacy supernode metrics reporter (MsgReportSupernodeMetrics) has been superseded by
@@ -162,14 +162,15 @@ The supernode will connect to the Lumera network and begin participating in the
162162
// Create supernode status service with injected tracker
163163
statusSvc := statusService.NewSupernodeStatusService(p2pService, lumeraClient, appConfig, tr)
164164

165-
auditReporter, err := auditReporterService.NewService(
165+
hostReporter, err := hostReporterService.NewService(
166166
appConfig.SupernodeConfig.Identity,
167167
lumeraClient,
168168
kr,
169169
appConfig.SupernodeConfig.KeyName,
170+
appConfig.BaseDir,
170171
)
171172
if err != nil {
172-
logtrace.Fatal(ctx, "Failed to initialize audit reporter", logtrace.Fields{"error": err.Error()})
173+
logtrace.Fatal(ctx, "Failed to initialize host reporter", logtrace.Fields{"error": err.Error()})
173174
}
174175

175176
// Legacy on-chain supernode metrics reporting has been superseded by `x/audit`.
@@ -247,7 +248,7 @@ The supernode will connect to the Lumera network and begin participating in the
247248
// Start the services using the standard runner and capture exit
248249
servicesErr := make(chan error, 1)
249250
go func() {
250-
services := []service{grpcServer, cService, p2pService, gatewayServer, auditReporter}
251+
services := []service{grpcServer, cService, p2pService, gatewayServer, hostReporter}
251252
if storageChallengeRunner != nil {
252253
services = append(services, storageChallengeRunner)
253254
}
Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package audit_reporter
1+
package host_reporter
22

33
import (
44
"context"
@@ -12,6 +12,7 @@ import (
1212
"github.com/LumeraProtocol/supernode/v2/pkg/logtrace"
1313
"github.com/LumeraProtocol/supernode/v2/pkg/lumera"
1414
"github.com/LumeraProtocol/supernode/v2/pkg/reachability"
15+
statussvc "github.com/LumeraProtocol/supernode/v2/supernode/status"
1516
"github.com/cosmos/cosmos-sdk/crypto/keyring"
1617
"google.golang.org/grpc/codes"
1718
"google.golang.org/grpc/status"
@@ -24,7 +25,7 @@ const (
2425
maxConcurrentTargets = 8
2526
)
2627

27-
// Service submits one MsgSubmitAuditReport per epoch for the local supernode.
28+
// Service submits one MsgSubmitEpochReport per epoch for the local supernode.
2829
// All runtime behavior is driven by on-chain params/queries; there are no local config knobs.
2930
type Service struct {
3031
identity string
@@ -35,9 +36,12 @@ type Service struct {
3536

3637
pollInterval time.Duration
3738
dialTimeout time.Duration
39+
40+
metrics *statussvc.MetricsCollector
41+
storagePaths []string
3842
}
3943

40-
func NewService(identity string, lumeraClient lumera.Client, kr keyring.Keyring, keyName string) (*Service, error) {
44+
func NewService(identity string, lumeraClient lumera.Client, kr keyring.Keyring, keyName string, baseDir string) (*Service, error) {
4145
identity = strings.TrimSpace(identity)
4246
if identity == "" {
4347
return nil, fmt.Errorf("identity is empty")
@@ -66,13 +70,21 @@ func NewService(identity string, lumeraClient lumera.Client, kr keyring.Keyring,
6670
return nil, fmt.Errorf("identity mismatch: config.identity=%s key(%s)=%s", identity, keyName, got)
6771
}
6872

73+
storagePaths := []string{}
74+
if baseDir = strings.TrimSpace(baseDir); baseDir != "" {
75+
// Match legacy disk reporting behavior: measure the volume where the supernode stores its data.
76+
storagePaths = []string{baseDir}
77+
}
78+
6979
return &Service{
7080
identity: identity,
7181
lumera: lumeraClient,
7282
keyring: kr,
7383
keyName: keyName,
7484
pollInterval: defaultPollInterval,
7585
dialTimeout: defaultDialTimeout,
86+
metrics: statussvc.NewMetricsCollector(),
87+
storagePaths: storagePaths,
7688
}, nil
7789
}
7890

@@ -105,7 +117,7 @@ func (s *Service) tick(ctx context.Context) {
105117
}
106118

107119
// Idempotency: if a report exists for this epoch, do nothing.
108-
if _, err := s.lumera.Audit().GetAuditReport(ctx, epochID, s.identity); err == nil {
120+
if _, err := s.lumera.Audit().GetEpochReport(ctx, epochID, s.identity); err == nil {
109121
return
110122
} else if status.Code(err) != codes.NotFound {
111123
return
@@ -116,28 +128,49 @@ func (s *Service) tick(ctx context.Context) {
116128
return
117129
}
118130

119-
peerObservations := s.buildPeerObservations(ctx, epochID, assignResp.RequiredOpenPorts, assignResp.TargetSupernodeAccounts)
131+
storageChallengeObservations := s.buildStorageChallengeObservations(ctx, epochID, assignResp.RequiredOpenPorts, assignResp.TargetSupernodeAccounts)
132+
133+
hostReport := audittypes.HostReport{
134+
// Intentionally submit 0% usage for CPU/memory so the chain treats these as "unknown".
135+
// Disk usage is reported accurately (legacy-aligned) so disk-based enforcement can work.
136+
CpuUsagePercent: 0,
137+
MemUsagePercent: 0,
138+
}
139+
if diskUsagePercent, ok := s.diskUsagePercent(ctx); ok {
140+
hostReport.DiskUsagePercent = diskUsagePercent
141+
}
120142

121-
if _, err := s.lumera.AuditMsg().SubmitAuditReport(ctx, epochID, peerObservations); err != nil {
122-
logtrace.Warn(ctx, "audit report submit failed", logtrace.Fields{
143+
if _, err := s.lumera.AuditMsg().SubmitEpochReport(ctx, epochID, hostReport, storageChallengeObservations); err != nil {
144+
logtrace.Warn(ctx, "epoch report submit failed", logtrace.Fields{
123145
"epoch_id": epochID,
124146
"error": err.Error(),
125147
})
126148
return
127149
}
128150

129-
logtrace.Info(ctx, "audit report submitted", logtrace.Fields{
130-
"epoch_id": epochID,
131-
"peer_observations_count": len(peerObservations),
151+
logtrace.Info(ctx, "epoch report submitted", logtrace.Fields{
152+
"epoch_id": epochID,
153+
"storage_challenge_observations_count": len(storageChallengeObservations),
132154
})
133155
}
134156

135-
func (s *Service) buildPeerObservations(ctx context.Context, epochID uint64, requiredOpenPorts []uint32, targets []string) []*audittypes.AuditPeerObservation {
157+
func (s *Service) diskUsagePercent(ctx context.Context) (float64, bool) {
158+
if s.metrics == nil || len(s.storagePaths) == 0 {
159+
return 0, false
160+
}
161+
infos := s.metrics.CollectStorageMetrics(ctx, s.storagePaths)
162+
if len(infos) == 0 {
163+
return 0, false
164+
}
165+
return infos[0].UsagePercent, true
166+
}
167+
168+
func (s *Service) buildStorageChallengeObservations(ctx context.Context, epochID uint64, requiredOpenPorts []uint32, targets []string) []*audittypes.StorageChallengeObservation {
136169
if len(targets) == 0 {
137170
return nil
138171
}
139172

140-
out := make([]*audittypes.AuditPeerObservation, len(targets))
173+
out := make([]*audittypes.StorageChallengeObservation, len(targets))
141174

142175
type workItem struct {
143176
index int
@@ -171,8 +204,8 @@ func (s *Service) buildPeerObservations(ctx context.Context, epochID uint64, req
171204
<-done
172205
}
173206

174-
// ensure no nil elements (MsgSubmitAuditReport rejects nil observations)
175-
final := make([]*audittypes.AuditPeerObservation, 0, len(out))
207+
// ensure no nil elements (MsgSubmitEpochReport rejects nil observations)
208+
final := make([]*audittypes.StorageChallengeObservation, 0, len(out))
176209
for i := range out {
177210
if out[i] != nil {
178211
final = append(final, out[i])
@@ -181,15 +214,15 @@ func (s *Service) buildPeerObservations(ctx context.Context, epochID uint64, req
181214
return final
182215
}
183216

184-
func (s *Service) observeTarget(ctx context.Context, epochID uint64, requiredOpenPorts []uint32, target string) *audittypes.AuditPeerObservation {
217+
func (s *Service) observeTarget(ctx context.Context, epochID uint64, requiredOpenPorts []uint32, target string) *audittypes.StorageChallengeObservation {
185218
target = strings.TrimSpace(target)
186219
if target == "" {
187220
return nil
188221
}
189222

190223
host, err := s.targetHost(ctx, target)
191224
if err != nil {
192-
logtrace.Warn(ctx, "audit observe target: resolve host failed", logtrace.Fields{
225+
logtrace.Warn(ctx, "storage challenge observe target: resolve host failed", logtrace.Fields{
193226
"epoch_id": epochID,
194227
"target": target,
195228
"error": err.Error(),
@@ -202,7 +235,7 @@ func (s *Service) observeTarget(ctx context.Context, epochID uint64, requiredOpe
202235
portStates = append(portStates, probeTCP(ctx, host, p, s.dialTimeout))
203236
}
204237

205-
return &audittypes.AuditPeerObservation{
238+
return &audittypes.StorageChallengeObservation{
206239
TargetSupernodeAccount: target,
207240
PortStates: portStates,
208241
}

supernode/storage_challenge/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ For each selected `file_key`:
3434

3535
On failure conditions (recipient error/unreachable, invalid proof, observer quorum failure), and only when enabled:
3636
- Build `StorageChallengeFailureEvidenceMetadata` JSON.
37-
- Enforce `sc_evidence_max_bytes` locally before submission.
3837
- Submit `MsgSubmitEvidence` to `x/audit` using the Supernode’s Cosmos key.
3938

4039
Evidence is chain-verifiable at the policy/assignment level (epoch anchor + deterministic rules), while full transcripts remain
@@ -48,4 +47,3 @@ off-chain (supernode logs and local stores).
4847
service retries on the next tick.
4948
- Candidate key lookback: lookback is computed as `lookback_epochs * estimated_epoch_duration`, where epoch duration is
5049
estimated from recent blocks. If estimation fails, it falls back to `24h * lookback_epochs`.
51-

0 commit comments

Comments
 (0)