diff --git a/docs/leps/LEP-6-implementation-guide.md b/docs/leps/LEP-6-implementation-guide.md index 79c1caac..8f1b5be3 100644 --- a/docs/leps/LEP-6-implementation-guide.md +++ b/docs/leps/LEP-6-implementation-guide.md @@ -1377,50 +1377,285 @@ Mode semantics: --- +## LEP-6 Round-2 Review Hardening (Zee R2 — PR #117 review 4184561676) + +Behavior deltas applied on top of `LEP-6-foundation` tip `868cbc7c` to close +24 production-gate findings. Branch `LEP-6-foundation-review-fixes` (squashed +single commit `0c6f5f0`). Test pyramid green at `0c6f5f0`: unit + module +simulation + `tests/integration/` + `tests/system/` + `tests/systemtests/` +(`-tags=system_test`, 25/25 PASS). Compare: +[`LEP-6-foundation...LEP-6-foundation-review-fixes`](https://github.com/LumeraProtocol/lumera/compare/LEP-6-foundation...LEP-6-foundation-review-fixes). + +### HIGH (consensus / state-correctness / money-flow) + +- **NEW-C-3 — `RegistrationFeeShareBps` (2%) fee routing restored.** + `x/action/v1/keeper/action.go:650-680`. The reward-distribution block + removed during LEP-6 consolidation is reinstated; 2% of every cascade fee + routes to the supernode reward pool via + `bankKeeper.SendCoinsFromModuleToModule(actiontypes → sntypes)`. Test + coverage in `x/action/v1/keeper/distribute_fees_test.go`. +- **NEW-C-1 — `ExportGenesis` round-trip closure for 8 epoch-scoped audit + prefix families.** `x/audit/v1/keeper/genesis.go`. Recheck-evidence dedup + (`st/rce/`), node-failure facts (`st/nf/`), reporter-result indexes + (`st/rrs/`, `st/rrs-tt/`), storage-proof transcripts (`st/spt/`, + `st/spt-tbe/`), failed-heal markers (`st/fh/`), reports / report-indexes + (`r/`, `ri/`), healer reports (`hr/`), and storage challenges (`sc/`) now + export and re-import deterministically. Without this, post-state-sync the + postpone/recovery/contradiction predicates would silently return "no + evidence" and brick storage-truth enforcement. 8 new `GenesisXxx` proto + wrappers + `GetAllXxx` iterators + `InitGenesis` re-emission. +- **NEW-A-12 / A-17 — `WindowStartEpoch` underflow at scoring window + resets.** `x/audit/v1/keeper/storage_truth_scoring.go:256, 332` + + `x/audit/v1/types/genesis_validate.go`. Raw `uint64` subtraction replaced + with `epochDelta(currentEpoch, state.WindowStartEpoch)` (uint64-safe); + genesis validator now rejects `WindowStartEpoch > currentEpoch` for both + `NodeSuspicionStates` and `ReporterReliabilityStates`. Spec ref §14, §15. +- **NEW-B-1 — EXPIRED heal-ops apply §20 cooldown.** + `x/audit/v1/keeper/storage_truth_heal_ops.go:36-48` + (`expireStorageTruthHealOpsAtEpochEnd`). Mirrors the FAILED branch: + `D += 15` (saturated), `ProbationUntilEpoch = epochID + + StorageTruthProbationEpochs`, write failed-heal fact. Closes the + heal-spam loop where an assigned-but-silent healer would have the same + ticket re-scheduled every epoch indefinitely. + +### MEDIUM (semantic correctness / sibling-symmetry) + +- **NEW-C-2 — FinalizeAction audit-hook artifact-count fallback.** + `x/action/v1/keeper/action.go:245-261`. Mirrors the 122-F2 fix inline + before calling `auditKeeper.SetStorageTruthTicketArtifactCounts`: zero + counts fall back to `len(RqIdsIds)`. Prevents a hard-revert on legacy + finalize when cascade metadata lacks explicit counts. +- **NEW-A-11 residue — bounded prefix scans on hot paths.** + `x/audit/v1/keeper/storage_truth_divergence.go:131-153` and + `x/audit/v1/keeper/storage_truth_fact_indexes.go:241-266`. Both unbounded + scans now bracket on `[startEpoch, endEpoch+1)` via secondary indexes + (`NodeStorageTruthFailureByEpochPrefix(account)+u64be(epoch)`, + `ReporterStorageTruthResultByEpochPrefix(reporter)+u64be(epoch)`), + mirroring the storage-proofs.go:318-350 pattern. +- **NEW-A-13 — `big.Int` divergence cross-multiply.** + `x/audit/v1/keeper/storage_truth_divergence.go:65-67, 89, 92`. Replaces + raw `uint64 * uint64` (wrap-around at scale) with `*big.Int` arithmetic + in median ordering and outlier predicate. +- **NEW-A-14 / A-15 — trust-multiplier scope narrowed to Class A.** + `x/audit/v1/keeper/storage_truth_scoring.go:73-81, 539-541`. Predicate + now requires `(ResultClass == HASH_MISMATCH || ArtifactClass == INDEX)` + in addition to the existing `RECHECK_CONFIRMED_FAIL` and + `BUCKET_TYPE_RECHECK` exclusions. Spec §15.4. +- **NEW-A-18 — single PASS reliability delta per epoch.** + `x/audit/v1/keeper/storage_truth_scoring.go:444, 450, 456` + + `ApplyReporterCleanEpochRecoveryAtEpochEnd`. Per-result PASS / TIMEOUT + reliability deltas zeroed; new epoch-end pass applies a single `-4` + reliability delta when `(passes_in_epoch >= 5 && no_overturned_fails)`. + Spec §15.3. +- **NEW-B-2 — decay-adjusted healer eligibility.** + `x/audit/v1/keeper/storage_truth_heal_ops.go:105-114`. Read uses + `decayTowardZero(ss.SuspicionScore, params.StorageTruthNodeSuspicionDecayPerEpoch, + epochDelta(epochID, ss.LastUpdatedEpoch))` for sibling-symmetry with + `enforcement.go:119`. +- **NEW-B-8 — verified-heal failure-pattern reset.** + `x/audit/v1/keeper/msg_storage_truth.go:395-404`. Verified-branch now + zeroes `DistinctHolderFailureCount`, `RecentFailureEpochCount`, + `LastIndexFailureEpoch`, `LastFailureEpoch` so the §20 "fresh start" + semantic is preserved post-heal. +- **F121-F12 — distinct strong-postpone reason + recovery param.** + `x/audit/v1/keeper/keys.go` + `enforcement.go` + `params.go`. Strong + band writes its own marker (`ap/sts/...`); recovery clean-pass count + reads from new param `StorageTruthStrongRecoveryCleanPassCount` + (default 5, gov-tunable). Recovery clears the strong marker explicitly. +- **F121-F10 / F119-F3 — ticket-side `ContradictionCount` confirmation + guard.** `x/audit/v1/keeper/storage_truth_scoring.go:418-422`. A + `contradictionConfirmed` bool now propagates from the reporter-side + bookkeeping; the ticket-side bump only fires on `prevFailure && + currentPass && contradictionConfirmed`. Closes sibling-asymmetry with + the reporter side. + +### LOW (defensive / observability / spec text) + +- **NEW-A-16** — median-of-even uses upper pair (was lower pair — + removes downward bias). +- **NEW-B-3** — verifier count promoted to param + `StorageTruthHealVerifierCount` (default 2, gov-tunable). +- **NEW-B-4** — insufficient-verifiers path emits an event + (sibling-symmetric with `EventTypeHealOpInsufficientHealers`). +- **NEW-B-5** — link-recheck single-witness intent documented inline. +- **NEW-B-6 / B-9** — `InitGenesis` cross-validates audit + `StorageTruthPostponements` against supernode `SuperNodeStatePostponed`. +- **NEW-B-7** — `GetNextHealOpID` panic-guards on malformed counter. +- **NEW-C-4 / A-19** — `pruneStorageProofTranscripts` logs malformed + records instead of silently swallowing. +- **NF7** — workspace `LEP6.md:171` `pair_rank` wording corrected to the + canonical 0x00-framed concatenation (in-repo guide already correct). +- **F119-F3 residue — cross-holder PASS bonus implemented.** + `applyTicketDeteriorationDelta` (where `state.LastTargetSupernodeAccount` + is available, NOT in the per-result delta switch). When PASS lands on + a ticket whose prior failure was from a DIFFERENT holder, an additional + `-3` ticket-deterioration delta is applied. Tests in + `storage_truth_cross_holder_pass_test.go` (4 sub-cases: same-holder PASS + no-bonus, cross-holder PASS bonus, no-prior-failure PASS no-bonus, FAIL + no-bonus). + +### New params introduced this round + +- `StorageTruthHealVerifierCount` — default 2 (NEW-B-3). +- `StorageTruthStrongRecoveryCleanPassCount` — default 5 (F121-F12). + +Both plumbed through `proto/lumera/audit/v1/params.proto` and +`x/audit/v1/types/params.go` (default + Validate). + +### Why round-1 missed these (process retrospective) + +Three production-gate sweeps were not executed before declaring the +earlier audit GREEN: + +1. **Out-of-scope diff sweep** vs `master` would have caught NEW-C-3 + (silent fee-routing deletion). +2. **`Set*` ↔ `ExportGenesis` symmetry sweep** (every `Set*` write should + round-trip through `ExportGenesis`) would have caught NEW-C-1 (8 + missing prefix families). +3. **PARTIAL-fix write-path enumeration** (when a fix is marked partial, + enumerate every write site that mirrors the predicate before claiming + resolution) would have caught NEW-C-2, F121-F12, F121-F10 + sibling-symmetry misses. + +These three sweeps are now mandatory pre-master items (see checklist +below) and codified as Skill Pitfall #31 in the +`lumera-lep6-pr-comment-triage` skill. + +--- + ## Pre-Release Checklist -Items below are NOT blocked by PR #122 itself — they are operational and -follow-up tasks that must complete before LEP-6 enforcement can flip from -`SHADOW` to `SOFT`/`FULL` on a live network. - -### Implementation follow-ups - -- [ ] **Class-A state-counter cleanup** — remove the residual zero-events fallback - in Postpone/StrongPostpone bands (CP3.5 audit F2, LOW). Auditor confirmed - unreachable post-activation with indexed data; safe to defer but should be - cleaned up before mainnet rollout. -- [ ] **Full-app simulation harness for LEP-6 paths** — repo currently lacks - `TestFullAppSimulation` exercising decay-then-add ordering, recheck flow, - heal-op lifecycle, and postponement+recovery loops over N=1000+ random - blocks. Track in a separate task post-LEP-6. - -### Cross-repo integration - -- [ ] **Supernode-side recheck-builder integration** — recheck evidence flow - has only been driven by hand-crafted CLI submissions in tests so far. - Production correctness depends on the off-chain runtime building these txs - with field shapes matching what `validateRecheckEvidence` expects. Track in - the supernode repo. -- [ ] **End-to-end devnet validation runbook** — once supernode integrates the - recheck-builder, validate the full flow on a local 5-validator devnet: - 1. Build `lumerad` from PR #122 → start devnet (`make devnet-up`). +This section is the canonical aggregator of every operational, follow-up, +and process item that must complete **before LEP-6 enforcement can flip +from `SHADOW` to `SOFT`/`FULL` on a live network**. Items below are NOT +blocked by the merging PR itself; they are gates for the activation +governance proposal. + +Source-of-truth references: `ACTIVE_WORK.md` (in-flight tracking), +`.lep6-review-pending-doc-updates/` (per-review queues), +`docs/leps/LEP-6-implementation-guide.md` (this file — design-of-record). + +### A. Migrations & data backfills + +- [ ] **`KeepLastEpochEntries` v1→v2 migration applied (122-F4).** + Handler at `x/audit/v1/module/migrations.go` registered at + `module.go:100` (`RegisterMigration(types.ModuleName, 1, NewMigrateV1ToV2)`). + On upgrade, bumps `KeepLastEpochEntries` to + `max(KeepLastEpochEntries, OldClassAFaultWindow)` (default + `OldClassAFaultWindow=21` if zero). `ConsensusVersion=2` at + `types/genesis.go:5`. Verify the upgrade handler is wired into + `app/upgrades//upgrades.go` for the activation release and that + post-upgrade state shows `KeepLastEpochEntries >= 21`. +- [ ] **TicketArtifactCountState backfill** for finalized cascade tickets + pre-dating LEP-6 anchoring (see "Mandatory Pre-Activation Data Plan" + above). Required: zero unresolved exceptions before flipping to + `SHADOW` or above. Backfill source: finalized cascade metadata + (`index_artifact_count` / `symbol_artifact_count` when present; + deterministic fallback from finalized symbol IDs otherwise — never + silently guess). +- [ ] **Audit report published**: total finalized cascade tickets, total + already anchored, total newly backfilled, total + unresolved/excluded (must be zero). Attach to the activation + governance proposal body. +- [ ] **New params seeded with defaults** at the upgrade boundary + (`StorageTruthHealVerifierCount=2`, + `StorageTruthStrongRecoveryCleanPassCount=5`). Confirm proto schema + defaults populate on `InitGenesis` of an upgraded chain. + +### B. Implementation follow-ups + +- [ ] **Class-A state-counter cleanup** — remove the residual zero-events + fallback in Postpone/StrongPostpone bands (CP3.5 audit F2, LOW). + Auditor confirmed unreachable post-activation with indexed data; safe + to defer but should be cleaned up before mainnet rollout. +- [ ] **Full-app simulation harness for LEP-6 paths** — repo currently + lacks `TestFullAppSimulation` exercising decay-then-add ordering, + recheck flow, heal-op lifecycle, and postponement+recovery loops over + N=1000+ random blocks. Module-level simulation (`x/audit/v1/simulation`) + is green; full-app harness is the missing tier. + +### C. Review-process sweeps (mandatory before each release-gate PR merge) + +These three sweeps were missed in round 1 and produced the 24 R2 +findings. They are now mandatory pre-master gates per Skill Pitfall #31. + +- [ ] **Out-of-scope diff sweep** — `git diff ..HEAD --stat` + filtered to files outside the announced scope; flag any deletion or + rewrite touching unrelated modules (especially money-flow paths in + `x/action`, `x/bank`, `x/distribution`, `x/supernode`). +- [ ] **`Set*` ↔ `ExportGenesis` symmetry sweep** — for every keeper + `Set*` write, confirm a matching `GetAll*` iterator and an + `ExportGenesis` emission round-trip. Run on the audit + supernode + modules at minimum. +- [ ] **PARTIAL-fix write-path enumeration** — for every finding marked + PARTIAL in any prior review, enumerate every write/predicate site + that mirrors the relevant rule before claiming resolution; check + reporter-side ↔ ticket-side ↔ node-side symmetry where applicable. + +### D. Cross-repo integration + +- [ ] **Supernode-side recheck-builder integration** — recheck evidence + flow has only been driven by hand-crafted CLI submissions in tests so + far. Production correctness depends on the off-chain runtime building + these txs with field shapes matching what `validateRecheckEvidence` + expects. Track in the supernode repo. +- [ ] **End-to-end devnet validation runbook** — once supernode integrates + the recheck-builder, validate the full flow on a local 5-validator + devnet: + 1. Build `lumerad` from the activation tag → start devnet + (`make devnet-up`). 2. Build `supernode` runtime from matching branch with new tx shape. 3. Trigger a real cascade upload via `sn-api-server`. - 4. Force a fail (corrupt one node's storage); let challenge fire; observe - storage proof results land on-chain. - 5. Trigger recheck path; observe `MsgSubmitStorageRecheckEvidence` build - correctly with all fields populated; confirm chain accepts it. + 4. Force a fail (corrupt one node's storage); let challenge fire; + observe storage proof results land on-chain. + 5. Trigger recheck path; observe `MsgSubmitStorageRecheckEvidence` + build correctly with all fields populated; confirm chain accepts + it (note: `--gas auto --gas-adjustment 1.3` — see Operator Notes). 6. Watch `NodeSuspicionState` / `ReporterReliabilityState` / `TicketDeteriorationState` evolve via queries. - 7. Cycle to recovery (clean passes); verify postponement→active transition. - -### Governance / operations + 7. Cycle to recovery (clean passes); verify postponement→active + transition and (for strong postpone) the new + `StorageTruthStrongRecoveryCleanPassCount` gate. + 8. Verify R2 deltas land as designed: a cross-holder PASS produces + `D -= 3` extra; per-epoch PASS reward is single `-4` (not + per-result); EXPIRED heal-op advances probation and bumps `D`. + +### E. Test pyramid re-validation at activation tag + +- [ ] `./x/...` unit suite green at activation tag. +- [ ] `./x/audit/v1/simulation/...` + `./x/audit/v1/module/...` + module-simulation green. +- [ ] `./tests/integration/...` green. +- [ ] `./tests/system/...` (`-tags=system`) green. +- [ ] `./tests/systemtests/...` (`-tags=system_test`) green + (25/25 last verified at `0c6f5f0`). +- [ ] Determinism scan clean — `grep -rE 'float|math\.Pow|time\.Now|rand\.|sort\.Float|FormatFloat'` + on `x/audit/v1/keeper` returns zero hits in consensus paths; no + `range map[]` in scoring/divergence/enforcement consensus paths. + +### F. Governance / operations - [ ] **Mainnet activation governance proposal** — flipping `StorageTruthEnforcementMode` from `SHADOW` to `SOFT` or `FULL` is a consensus-binding change. Draft a governance proposal with a flag-day - epoch boundary; coordinate with all validators on the activation epoch. - Cannot be reversed without another governance proposal. -- [ ] **Validator/supernode operator advisory** — publish the gas-requirements - note (above) in operator docs. Include in the SOFT/FULL activation proposal - body so all participants see it before voting. + epoch boundary; coordinate with all validators on the activation + epoch. Cannot be reversed without another governance proposal. +- [ ] **Validator/supernode operator advisory** — publish the + gas-requirements note (above) in operator docs. Include in the + SOFT/FULL activation proposal body so all participants see it before + voting. +- [ ] **Operator changelog** — publish the R2 behavior deltas (new params, + per-epoch PASS reward semantics, EXPIRED heal-op cooldown, strong-band + recovery threshold, cross-holder PASS bonus) in the release notes so + operators understand observable score-evolution changes. + +### G. Documentation queue close-out + +- [ ] `.lep6-review-pending-doc-updates/CP1_TRIAGE.md` and + `CP2_SPEC_ALIGNMENT.md` items resolved or explicitly deferred with + rationale. +- [ ] `.lep6-review-pending-doc-updates/r2/` items reflected in this + guide (this section) and in `workspace/docs/LEP6.md` where the spec + text needed correction (NF7 done; sweep for any further drift). +- [ ] `docs/agent-context/02_lumera.md` updated with R2 behavior deltas + and new params for cross-session continuity. diff --git a/proto/lumera/audit/v1/genesis.proto b/proto/lumera/audit/v1/genesis.proto index 7ba15b89..86c40ba9 100644 --- a/proto/lumera/audit/v1/genesis.proto +++ b/proto/lumera/audit/v1/genesis.proto @@ -36,6 +36,17 @@ message GenesisState { // storage_truth_postponements records active per-supernode postponement markers // exported/imported at genesis. Per 121-F7. repeated StorageTruthPostponement storage_truth_postponements = 10 [(gogoproto.nullable) = false]; + + // Per NEW-C-1: round-trip every epoch-scoped audit prefix. + repeated GenesisRecheckEvidence recheck_evidence = 11 [(gogoproto.nullable) = false]; + repeated GenesisStorageProofTranscript storage_proof_transcripts = 12 [(gogoproto.nullable) = false]; + repeated GenesisNodeFailureFact node_failure_facts = 13 [(gogoproto.nullable) = false]; + repeated GenesisReporterResultFact reporter_result_facts = 14 [(gogoproto.nullable) = false]; + repeated GenesisFailedHealMarker failed_heal_markers = 15 [(gogoproto.nullable) = false]; + repeated EpochReport epoch_reports = 16 [(gogoproto.nullable) = false]; + repeated GenesisReportIndex report_indices = 17 [(gogoproto.nullable) = false]; + repeated GenesisHostReportIndex host_report_indices = 18 [(gogoproto.nullable) = false]; + repeated GenesisStorageChallengeIndex storage_challenge_indices = 19 [(gogoproto.nullable) = false]; } // StorageTruthPostponement records a supernode's storage-truth postponement state @@ -44,3 +55,64 @@ message StorageTruthPostponement { string supernode_account = 1; uint64 postponed_at_epoch_id = 2; } + +// GenesisRecheckEvidence — st/rce/ replay-protection key. +message GenesisRecheckEvidence { + uint64 epoch_id = 1; + string ticket_id = 2; + string creator_account = 3; +} + +// GenesisStorageProofTranscript — st/spt/ value (JSON-encoded record). +// The opaque record_json blob is the keeper's storageProofTranscriptRecord +// JSON marshaling. InitGenesis re-writes via the existing setter so the +// st/spt-tbe/ secondary index is rebuilt deterministically. +message GenesisStorageProofTranscript { + string transcript_hash = 1; + bytes record_json = 2; +} + +// GenesisNodeFailureFact — st/nf/ entry (JSON-encoded record). +message GenesisNodeFailureFact { + string supernode_account = 1; + uint64 epoch_id = 2; + string ticket_id = 3; + string reporter_account = 4; + bytes record_json = 5; +} + +// GenesisReporterResultFact — st/rrs/ entry (JSON-encoded record). +// The st/rrs-tt/ secondary index is rebuilt by the existing setter. +message GenesisReporterResultFact { + string reporter_account = 1; + uint64 epoch_id = 2; + string ticket_id = 3; + string target_account = 4; + bytes record_json = 5; +} + +// GenesisFailedHealMarker — st/fh/ marker. +message GenesisFailedHealMarker { + string supernode_account = 1; + uint64 epoch_id = 2; + string ticket_id = 3; +} + +// GenesisReportIndex — ri/ index entry. +message GenesisReportIndex { + string reporter_supernode_account = 1; + uint64 epoch_id = 2; +} + +// GenesisHostReportIndex — hr/ index entry. +message GenesisHostReportIndex { + string reporter_supernode_account = 1; + uint64 epoch_id = 2; +} + +// GenesisStorageChallengeIndex — sc/ index entry. +message GenesisStorageChallengeIndex { + string supernode_account = 1; + uint64 epoch_id = 2; + string reporter_supernode_account = 3; +} diff --git a/proto/lumera/audit/v1/params.proto b/proto/lumera/audit/v1/params.proto index 5aa64890..e610d94d 100644 --- a/proto/lumera/audit/v1/params.proto +++ b/proto/lumera/audit/v1/params.proto @@ -149,4 +149,12 @@ message Params { // Reporter challenger ineligibility duration in epochs (default 7). uint32 storage_truth_reporter_ineligible_duration_epochs = 49; + + // Strong-band recovery clean-pass requirement (F121-F12, default 5). + uint32 storage_truth_strong_recovery_clean_pass_count = 50; + + // Number of verifier supernodes assigned per heal-op (NEW-B-3, default 2). + // Verifiers cross-check the healer's recovery; making this a Param allows + // governance to tune redundancy if heal volume / failure rate shifts. + uint32 storage_truth_heal_verifier_count = 51; } diff --git a/testutil/keeper/action.go b/testutil/keeper/action.go index 34d5916a..bbb77d29 100644 --- a/testutil/keeper/action.go +++ b/testutil/keeper/action.go @@ -103,6 +103,18 @@ func (m *ActionBankKeeper) GetBalance(ctx context.Context, addr sdk.AccAddress, return sdk.Coin{} } +func (m *ActionBankKeeper) SendCoinsFromModuleToModule(ctx context.Context, senderModule, recipientModule string, amt sdk.Coins) error { + if _, ok := m.moduleBalances[senderModule]; ok { + m.moduleBalances[senderModule] = m.moduleBalances[senderModule].Sub(amt...) + } + if m.moduleBalances[recipientModule].IsZero() { + m.moduleBalances[recipientModule] = amt + } else { + m.moduleBalances[recipientModule] = m.moduleBalances[recipientModule].Add(amt...) + } + return nil +} + func (m *ActionBankKeeper) GetModuleBalance(module string) sdk.Coins { if coins, ok := m.moduleBalances[module]; ok { return coins @@ -213,6 +225,87 @@ func ActionKeeper(t testing.TB, ctrl *gomock.Controller) (keeper.Keeper, sdk.Con return ActionKeeperWithAddress(t, ctrl, nil) } +// MockRewardDistributionKeeper is a simple stub that returns a configurable bps value. +type MockRewardDistributionKeeper struct { + Bps uint64 +} + +func (m *MockRewardDistributionKeeper) GetRegistrationFeeShareBps(_ sdk.Context) uint64 { + return m.Bps +} + +// ActionKeeperWithRewardDistribution returns an action keeper wired with the supplied +// RewardDistributionKeeper plus the bank-keeper mock so tests can assert module-balance +// deltas across the reward-share + foundation + supernode payout splits. +func ActionKeeperWithRewardDistribution( + t testing.TB, + ctrl *gomock.Controller, + accounts []AccountPair, + rewardDistKeeper actiontypes.RewardDistributionKeeper, +) (keeper.Keeper, sdk.Context, *ActionBankKeeper) { + storeKey := storetypes.NewKVStoreKey(actiontypes.StoreKey) + + db := dbm.NewMemDB() + encCfg := moduletestutil.MakeTestEncodingConfig(actionmodulev1.AppModule{}) + stateStore := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + authority := authtypes.NewModuleAddress(govtypes.ModuleName) + + bankKeeper := NewActionMockBankKeeper() + authKeeper := NewMockAccountKeeper() + stakingKeeper := new(MockStakingKeeper) + supernodeKeeper := supernodemocks.NewMockSupernodeKeeper(ctrl) + supernodeQueryServer := supernodemocks.NewMockQueryServer(ctrl) + distributionKeeper := new(MockDistributionKeeper) + auditKeeper := NewMockAuditKeeper() + + ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) + for _, acc := range accounts { + account := authKeeper.NewAccountWithAddress(ctx, acc.Address) + err := account.SetPubKey(acc.PubKey) + require.NoError(t, err) + authKeeper.SetAccount(ctx, account) + bankKeeper.sentCoins[acc.Address.String()] = sdk.NewCoins(sdk.NewInt64Coin("ulume", TestAccountAmount)) + } + + mockUpgradeKeeper := newMockUpgradeKeeper() + + storeService := runtime.NewKVStoreService(storeKey) + k := keeper.NewKeeper( + cdc, + authKeeper.AddressCodec(), + storeService, + log.NewNopLogger(), + authority, + bankKeeper, + authKeeper, + stakingKeeper, + distributionKeeper, + supernodeKeeper, + func() sntypes.QueryServer { + return supernodeQueryServer + }, + auditKeeper, + func() *ibckeeper.Keeper { + return ibckeeper.NewKeeper(encCfg.Codec, storeService, newMockIbcParams(), mockUpgradeKeeper, authority.String()) + }, + rewardDistKeeper, + ) + + params := actiontypes.DefaultParams() + params.FoundationFeeShare = "0.1" + params.SuperNodeFeeShare = "0.9" + if err := k.SetParams(ctx, params); err != nil { + panic(err) + } + + return k, ctx, bankKeeper +} + func ActionKeeperWithAddress(t testing.TB, ctrl *gomock.Controller, accounts []AccountPair) (keeper.Keeper, sdk.Context) { storeKey := storetypes.NewKVStoreKey(actiontypes.StoreKey) @@ -272,6 +365,7 @@ func ActionKeeperWithAddress(t testing.TB, ctrl *gomock.Controller, accounts []A func() *ibckeeper.Keeper { return ibckeeper.NewKeeper(encCfg.Codec, storeService, newMockIbcParams(), mockUpgradeKeeper, authority.String()) }, + nil, ) // Initialize params diff --git a/x/action/v1/keeper/action.go b/x/action/v1/keeper/action.go index a29c3821..a27804d1 100644 --- a/x/action/v1/keeper/action.go +++ b/x/action/v1/keeper/action.go @@ -250,11 +250,12 @@ func (k *Keeper) FinalizeAction(ctx sdk.Context, actionID string, superNodeAccou if err := gogoproto.Unmarshal(existingAction.Metadata, &cascadeMeta); err != nil { return errors.Wrap(actiontypes.ErrInvalidMetadata, fmt.Sprintf("failed to unmarshal finalized cascade metadata: %v", err)) } + indexCount, symbolCount := actiontypes.CascadeArtifactCountsWithFallback(&cascadeMeta) if err := k.auditKeeper.SetStorageTruthTicketArtifactCounts( ctx, existingAction.ActionID, - cascadeMeta.GetIndexArtifactCount(), - cascadeMeta.GetSymbolArtifactCount(), + indexCount, + symbolCount, ); err != nil { return errors.Wrap(actiontypes.ErrInvalidMetadata, err.Error()) } @@ -646,6 +647,22 @@ func (k *Keeper) DistributeFees(ctx sdk.Context, actionID string) error { return nil // No supernodes to pay } + // Route the configured reward-distribution share to the supernode-owned pool. + if k.rewardDistributionKeeper != nil { + rewardDistributionBps := k.rewardDistributionKeeper.GetRegistrationFeeShareBps(ctx) + if rewardDistributionBps > 0 && fee.Amount.GT(math.ZeroInt()) { + rewardDistributionAmount := fee.Amount.MulRaw(int64(rewardDistributionBps)).QuoRaw(10000) + if rewardDistributionAmount.IsPositive() { + rewardDistributionCoin := sdk.NewCoin(fee.Denom, rewardDistributionAmount) + err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, actiontypes.ModuleName, sntypes.ModuleName, sdk.NewCoins(rewardDistributionCoin)) + if err != nil { + return errors.Wrap(err, "failed to send reward-distribution fee share") + } + fee.Amount = fee.Amount.Sub(rewardDistributionAmount) + } + } + } + params := k.GetParams(ctx) if params.FoundationFeeShare != "" { foundationFeeShareDec, err := math.LegacyNewDecFromStr(params.FoundationFeeShare) diff --git a/x/action/v1/keeper/action_cascade.go b/x/action/v1/keeper/action_cascade.go index b29f1722..cdaded45 100644 --- a/x/action/v1/keeper/action_cascade.go +++ b/x/action/v1/keeper/action_cascade.go @@ -145,13 +145,10 @@ func (h CascadeActionHandler) Process(metadataBytes []byte, msgType common.Messa return nil, fmt.Errorf("rq_ids_ids field is required for cascade metadata") } // Backward-compatible fallback for finalize payloads that do not yet - // provide explicit LEP-6 artifact counts. - if metadata.IndexArtifactCount == 0 { - metadata.IndexArtifactCount = uint32(len(metadata.RqIdsIds)) - } - if metadata.SymbolArtifactCount == 0 { - metadata.SymbolArtifactCount = uint32(len(metadata.RqIdsIds)) - } + // provide explicit LEP-6 artifact counts (single-source-of-truth via + // CascadeArtifactCountsWithFallback per CP-NEW-C-2 / 122-F2). + metadata.IndexArtifactCount, metadata.SymbolArtifactCount = + actiontypes.CascadeArtifactCountsWithFallback(&metadata) default: return nil, fmt.Errorf("unsupported message type: %s", msgType) } @@ -326,12 +323,8 @@ func (h CascadeActionHandler) GetUpdatedMetadata(ctx sdk.Context, existingMetada IndexArtifactCount: newMetadata.GetIndexArtifactCount(), SymbolArtifactCount: newMetadata.GetSymbolArtifactCount(), } - if updatedMetadata.IndexArtifactCount == 0 { - updatedMetadata.IndexArtifactCount = uint32(len(updatedMetadata.RqIdsIds)) - } - if updatedMetadata.SymbolArtifactCount == 0 { - updatedMetadata.SymbolArtifactCount = uint32(len(updatedMetadata.RqIdsIds)) - } + updatedMetadata.IndexArtifactCount, updatedMetadata.SymbolArtifactCount = + actiontypes.CascadeArtifactCountsWithFallback(updatedMetadata) return gogoproto.Marshal(updatedMetadata) } diff --git a/x/action/v1/keeper/distribute_fees_test.go b/x/action/v1/keeper/distribute_fees_test.go new file mode 100644 index 00000000..e6860cf3 --- /dev/null +++ b/x/action/v1/keeper/distribute_fees_test.go @@ -0,0 +1,131 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + keepertest "github.com/LumeraProtocol/lumera/testutil/keeper" + "github.com/LumeraProtocol/lumera/testutil/sample" + actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types" + sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types" +) + +// distributeFeesFixture builds an action keeper wired with a configurable +// RewardDistributionKeeper (bps) and registers a Done cascade action whose +// price is the given fee amount of ulume distributed to a single supernode. +type distributeFeesFixture struct { + actionID string + supernode string + fee sdk.Coin + bankKeeper *keepertest.ActionBankKeeper + keeperCtx sdk.Context + keeper interface { + SetAction(ctx sdk.Context, action *actiontypes.Action) error + DistributeFees(ctx sdk.Context, actionID string) error + } +} + +func setupDistributeFees(t *testing.T, bps uint64, feeAmount int64) *distributeFeesFixture { + t.Helper() + + ctrl := gomock.NewController(t) + t.Cleanup(ctrl.Finish) + + rewardKeeper := &keepertest.MockRewardDistributionKeeper{Bps: bps} + k, ctx, bank := keepertest.ActionKeeperWithRewardDistribution(t, ctrl, nil, rewardKeeper) + + supernode := sample.AccAddress() + fee := sdk.NewInt64Coin("ulume", feeAmount) + action := &actiontypes.Action{ + Creator: sample.AccAddress(), + ActionID: "action-distfees-1", + ActionType: actiontypes.ActionTypeCascade, + Metadata: []byte("metadata"), + Price: fee.String(), + ExpirationTime: 1234567890, + BlockHeight: 10, + State: actiontypes.ActionStateDone, + SuperNodes: []string{supernode}, + } + require.NoError(t, k.SetAction(ctx, action)) + + return &distributeFeesFixture{ + actionID: action.ActionID, + supernode: supernode, + fee: fee, + bankKeeper: bank, + keeperCtx: ctx, + keeper: &k, + } +} + +// TestDistributeFees_RoutesRegistrationFeeShareToSupernodePool asserts that +// the configured RegistrationFeeShareBps slice of every cascade fee is routed +// to the supernode-owned reward pool (sntypes.ModuleName) before the +// foundation share + per-supernode payout happen. +func TestDistributeFees_RoutesRegistrationFeeShareToSupernodePool(t *testing.T) { + const ( + feeAmount int64 = 1000 + bps uint64 = 200 // 2% + ) + f := setupDistributeFees(t, bps, feeAmount) + + preSupernodePool := f.bankKeeper.GetModuleBalance(sntypes.ModuleName) + + require.NoError(t, f.keeper.DistributeFees(f.keeperCtx, f.actionID)) + + postSupernodePool := f.bankKeeper.GetModuleBalance(sntypes.ModuleName) + + expectedReward := feeAmount * int64(bps) / 10000 // 20 + delta := postSupernodePool.AmountOf("ulume").Sub(preSupernodePool.AmountOf("ulume")) + require.Equal(t, expectedReward, delta.Int64(), + "reward-pool delta must equal fee*bps/10000") + + // Foundation share is 10% (FoundationFeeShare=0.1) of the post-reward fee. + postRewardFee := feeAmount - expectedReward // 980 + expectedFoundation := postRewardFee / 10 // 98 + expectedSupernodePayout := postRewardFee - expectedFoundation + + addr, err := sdk.AccAddressFromBech32(f.supernode) + require.NoError(t, err) + got := f.bankKeeper.GetAccountCoins(addr).AmountOf("ulume").Int64() + require.Equal(t, expectedSupernodePayout, got, + "supernode receives fee minus reward-share minus foundation-share") +} + +// TestDistributeFees_BpsZero_NoModuleToModuleTransfer asserts that with bps=0 +// the supernode reward pool balance is unchanged (no module-to-module xfer). +func TestDistributeFees_BpsZero_NoModuleToModuleTransfer(t *testing.T) { + f := setupDistributeFees(t, 0, 1000) + + pre := f.bankKeeper.GetModuleBalance(sntypes.ModuleName) + require.NoError(t, f.keeper.DistributeFees(f.keeperCtx, f.actionID)) + post := f.bankKeeper.GetModuleBalance(sntypes.ModuleName) + + require.True(t, pre.Equal(post), + "sntypes.ModuleName balance must be unchanged when bps=0 (got pre=%s post=%s)", + pre.String(), post.String()) +} + +// TestDistributeFees_BpsRouting_AmountTruncation asserts integer truncation +// of the reward-share calc: fee*bps/10000 truncates fractional ulume. +// fee=1003, bps=200 -> 1003*200=200600 / 10000 = 20 (0.06 truncated). +func TestDistributeFees_BpsRouting_AmountTruncation(t *testing.T) { + const ( + feeAmount int64 = 1003 + bps uint64 = 200 + ) + f := setupDistributeFees(t, bps, feeAmount) + + require.NoError(t, f.keeper.DistributeFees(f.keeperCtx, f.actionID)) + + post := f.bankKeeper.GetModuleBalance(sntypes.ModuleName) + got := post.AmountOf("ulume").Int64() + expected := feeAmount * int64(bps) / 10000 // 20, NOT 21 + require.Equal(t, int64(20), expected, "sanity: arithmetic constant") + require.Equal(t, expected, got, + "reward-share must be truncated, not rounded") +} diff --git a/x/action/v1/keeper/keeper.go b/x/action/v1/keeper/keeper.go index 9806f739..b9350c85 100644 --- a/x/action/v1/keeper/keeper.go +++ b/x/action/v1/keeper/keeper.go @@ -28,14 +28,15 @@ type ( Schema collections.Schema Port collections.Item[string] - bankKeeper actiontypes.BankKeeper - authKeeper actiontypes.AuthKeeper - stakingKeeper actiontypes.StakingKeeper - distributionKeeper actiontypes.DistributionKeeper - supernodeKeeper actiontypes.SupernodeKeeper - supernodeQueryServer actiontypes.SupernodeQueryServer - auditKeeper actiontypes.AuditKeeper - ibcKeeperFn func() *ibckeeper.Keeper + bankKeeper actiontypes.BankKeeper + authKeeper actiontypes.AuthKeeper + stakingKeeper actiontypes.StakingKeeper + distributionKeeper actiontypes.DistributionKeeper + supernodeKeeper actiontypes.SupernodeKeeper + supernodeQueryServer actiontypes.SupernodeQueryServer + auditKeeper actiontypes.AuditKeeper + ibcKeeperFn func() *ibckeeper.Keeper + rewardDistributionKeeper actiontypes.RewardDistributionKeeper // Action handling actionRegistry *ActionRegistry @@ -57,6 +58,7 @@ func NewKeeper( supernodeQueryServer func() sntypes.QueryServer, auditKeeper actiontypes.AuditKeeper, ibcKeeperFn func() *ibckeeper.Keeper, + rewardDistributionKeeper actiontypes.RewardDistributionKeeper, ) Keeper { if _, err := addressCodec.BytesToString(authority); err != nil { panic(fmt.Sprintf("invalid authority address: %s", authority)) @@ -72,19 +74,20 @@ func NewKeeper( // Create the k instance k := Keeper{ - cdc: cdc, - addressCodec: addressCodec, - storeService: storeService, - logger: logger, - authority: authority, - bankKeeper: bankKeeper, - authKeeper: accountKeeper, - stakingKeeper: stakingKeeper, - distributionKeeper: distributionKeeper, - supernodeKeeper: supernodeKeeper, - supernodeQueryServer: snQueryServer, - auditKeeper: auditKeeper, - ibcKeeperFn: ibcKeeperFn, + cdc: cdc, + addressCodec: addressCodec, + storeService: storeService, + logger: logger, + authority: authority, + bankKeeper: bankKeeper, + authKeeper: accountKeeper, + stakingKeeper: stakingKeeper, + distributionKeeper: distributionKeeper, + supernodeKeeper: supernodeKeeper, + supernodeQueryServer: snQueryServer, + auditKeeper: auditKeeper, + ibcKeeperFn: ibcKeeperFn, + rewardDistributionKeeper: rewardDistributionKeeper, Port: collections.NewItem(sb, actiontypes.PortKey, "port", collections.StringValue), } @@ -149,3 +152,7 @@ func (k *Keeper) GetActionRegistry() *ActionRegistry { func (k *Keeper) GetStakingKeeper() actiontypes.StakingKeeper { return k.stakingKeeper } + +func (k *Keeper) GetRewardDistributionKeeper() actiontypes.RewardDistributionKeeper { + return k.rewardDistributionKeeper +} diff --git a/x/action/v1/module/depinject.go b/x/action/v1/module/depinject.go index adb3b6aa..3ddc2a6e 100644 --- a/x/action/v1/module/depinject.go +++ b/x/action/v1/module/depinject.go @@ -82,6 +82,7 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { }, in.AuditKeeper, in.IBCKeeperFn, + in.SupernodeKeeper, ) m := NewAppModule( diff --git a/x/action/v1/types/expected_keepers.go b/x/action/v1/types/expected_keepers.go index ec201f2f..273e6cbb 100644 --- a/x/action/v1/types/expected_keepers.go +++ b/x/action/v1/types/expected_keepers.go @@ -31,6 +31,7 @@ type BankKeeper interface { GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error SendCoinsFromAccountToModule(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx context.Context, senderModule, recipientModule string, amt sdk.Coins) error } // StakingKeeper defines the expected staking keeper @@ -68,6 +69,11 @@ type AuditKeeper interface { SetStorageTruthTicketArtifactCounts(ctx context.Context, ticketID string, indexArtifactCount uint32, symbolArtifactCount uint32) error } +// RewardDistributionKeeper defines the fee-share interface implemented by x/supernode. +type RewardDistributionKeeper interface { + GetRegistrationFeeShareBps(ctx sdk.Context) uint64 +} + // ParamSubspace defines the expected Subspace interface for parameters. type ParamSubspace interface { Get(context.Context, []byte, interface{}) diff --git a/x/action/v1/types/metadata.go b/x/action/v1/types/metadata.go new file mode 100644 index 00000000..dfb1c886 --- /dev/null +++ b/x/action/v1/types/metadata.go @@ -0,0 +1,24 @@ +package types + +// CascadeArtifactCountsWithFallback returns the (index, symbol) artifact +// counts from a CascadeMetadata, falling back to len(RqIdsIds) when either +// field is zero. This is the single-source-of-truth helper enforcing the +// 122-F2 fallback rule across all sites that consume cascade artifact +// counts (Process, GetUpdatedMetadata, FinalizeAction → audit hook). +// +// If meta is nil, returns (0, 0). +func CascadeArtifactCountsWithFallback(meta *CascadeMetadata) (uint32, uint32) { + if meta == nil { + return 0, 0 + } + idx := meta.GetIndexArtifactCount() + sym := meta.GetSymbolArtifactCount() + fallback := uint32(len(meta.GetRqIdsIds())) + if idx == 0 { + idx = fallback + } + if sym == 0 { + sym = fallback + } + return idx, sym +} diff --git a/x/audit/v1/keeper/abci.go b/x/audit/v1/keeper/abci.go index 66a11858..bd36d3e4 100644 --- a/x/audit/v1/keeper/abci.go +++ b/x/audit/v1/keeper/abci.go @@ -56,6 +56,12 @@ func (k Keeper) EndBlocker(ctx context.Context) error { return err } + // Per NEW-A-18 — per-EPOCH reporter clean-recovery (-4 once on >=5 PASS, + // no overturned-fail). Per-result PASS/TIMEOUT reporter deltas are 0. + if err := k.ApplyReporterCleanEpochRecoveryAtEpochEnd(sdkCtx, epoch.EpochID, params); err != nil { + return err + } + if err := k.ProcessStorageTruthHealOpsAtEpochEnd(sdkCtx, epoch.EpochID, params); err != nil { return err } diff --git a/x/audit/v1/keeper/enforcement.go b/x/audit/v1/keeper/enforcement.go index 7829bcf2..38cce7d8 100644 --- a/x/audit/v1/keeper/enforcement.go +++ b/x/audit/v1/keeper/enforcement.go @@ -15,6 +15,7 @@ const ( postponeReasonActionFinalizationSignatureFailure = "audit_action_finalization_signature_failure" postponeReasonActionFinalizationNotInTop10 = "audit_action_finalization_not_in_top_10" postponeReasonStorageTruth = "audit_storage_truth_suspicion" + postponeReasonStorageTruthStrong = "audit_storage_truth_strong_suspicion" ) // EnforceEpochEnd evaluates the completed epoch and updates supernode states accordingly. @@ -154,10 +155,18 @@ func (k Keeper) applyStorageTruthBandAtEpochEnd(ctx sdk.Context, sn sntypes.Supe return nil } - if err := k.setSupernodePostponed(ctx, sn, postponeReasonStorageTruth); err != nil { + // Per F121-F12 — strong-suspicion band uses a distinct reason and recovery requirement. + reason := postponeReasonStorageTruth + if band == storageTruthBandStrongPostpone { + reason = postponeReasonStorageTruthStrong + } + if err := k.setSupernodePostponed(ctx, sn, reason); err != nil { return err } k.setStorageTruthPostponedAtEpochID(ctx, sn.SupernodeAccount, epochID) + if band == storageTruthBandStrongPostpone { + k.setStorageTruthStrongPostponeMarker(ctx, sn.SupernodeAccount) + } k.clearActionFinalizationPostponedAtEpochID(ctx, sn.SupernodeAccount) // Per 121-F8 — recovery delta from snapshot, not cumulative. @@ -604,8 +613,14 @@ func (k Keeper) shouldRecoverFromStorageTruthPostponement(ctx sdk.Context, super return false } // Score is below watch threshold — also require sufficient clean passes. + // Per F121-F12 — strong-band postponements require a higher pass count. requiredPasses := params.StorageTruthRecoveryCleanPassCount - if requiredPasses == 0 { + if k.hasStorageTruthStrongPostponeMarker(ctx, supernodeAccount) { + requiredPasses = params.StorageTruthStrongRecoveryCleanPassCount + if requiredPasses == 0 { + requiredPasses = 5 + } + } else if requiredPasses == 0 { requiredPasses = 3 } // Per 121-F8 — recovery delta from snapshot, not cumulative. diff --git a/x/audit/v1/keeper/enforcement_predicates_test.go b/x/audit/v1/keeper/enforcement_predicates_test.go index 1dbc63c1..da50acc0 100644 --- a/x/audit/v1/keeper/enforcement_predicates_test.go +++ b/x/audit/v1/keeper/enforcement_predicates_test.go @@ -120,7 +120,7 @@ func TestApplyStorageTruthBandAtEpochEnd_StrongPostponeOnIndexFail(t *testing.T) GetAllSuperNodes(gomock.AssignableToTypeOf(f.ctx), sntypes.SuperNodeStatePostponed). Return([]sntypes.SuperNode{}, nil) f.supernodeKeeper.EXPECT(). - SetSuperNodePostponed(gomock.AssignableToTypeOf(f.ctx), sdk.ValAddress(valAddr), "audit_storage_truth_suspicion"). + SetSuperNodePostponed(gomock.AssignableToTypeOf(f.ctx), sdk.ValAddress(valAddr), "audit_storage_truth_strong_suspicion"). Return(nil).Times(1) require.NoError(t, f.keeper.EnforceEpochEnd(f.ctx, 0, params)) @@ -160,7 +160,9 @@ func TestRecoveryRequiresCleanPasses(t *testing.T) { GetAllSuperNodes(gomock.AssignableToTypeOf(f.ctx), sntypes.SuperNodeStatePostponed). Return([]sntypes.SuperNode{}, nil) f.supernodeKeeper.EXPECT(). - SetSuperNodePostponed(gomock.AssignableToTypeOf(f.ctx), sdk.ValAddress(valAddr), "audit_storage_truth_suspicion"). + // Per F121-F12 — strong-suspicion band uses distinct reason + // (score=200 == StrongPostpone threshold). + SetSuperNodePostponed(gomock.AssignableToTypeOf(f.ctx), sdk.ValAddress(valAddr), "audit_storage_truth_strong_suspicion"). Return(nil).Times(1) require.NoError(t, f.keeper.EnforceEpochEnd(f.ctx, 0, params)) diff --git a/x/audit/v1/keeper/enforcement_test.go b/x/audit/v1/keeper/enforcement_test.go index 8983686d..616e12a2 100644 --- a/x/audit/v1/keeper/enforcement_test.go +++ b/x/audit/v1/keeper/enforcement_test.go @@ -156,7 +156,8 @@ func TestEnforceEpochEnd_EmitsStorageTruthRecoveredEvent(t *testing.T) { Return([]sntypes.SuperNode{}, nil). Times(1) f.supernodeKeeper.EXPECT(). - SetSuperNodePostponed(gomock.AssignableToTypeOf(f.ctx), sdk.ValAddress(postponedVal), "audit_storage_truth_suspicion"). + // Per F121-F12 — strong-suspicion band uses distinct reason (score=200, strongThr=140). + SetSuperNodePostponed(gomock.AssignableToTypeOf(f.ctx), sdk.ValAddress(postponedVal), "audit_storage_truth_strong_suspicion"). Return(nil). Times(1) @@ -167,7 +168,7 @@ func TestEnforceEpochEnd_EmitsStorageTruthRecoveredEvent(t *testing.T) { SupernodeAccount: postponed.SupernodeAccount, SuspicionScore: 1, LastUpdatedEpoch: 6, - CleanPassCount: params.StorageTruthRecoveryCleanPassCount, + CleanPassCount: params.StorageTruthStrongRecoveryCleanPassCount, // Per F121-F12 — strong postpone uses StrongRecoveryCleanPassCount. })) f.supernodeKeeper.EXPECT(). diff --git a/x/audit/v1/keeper/export_test.go b/x/audit/v1/keeper/export_test.go index 7027a6da..7344346d 100644 --- a/x/audit/v1/keeper/export_test.go +++ b/x/audit/v1/keeper/export_test.go @@ -17,3 +17,16 @@ var SetStorageTruthReporterResultForTest = func(k Keeper, ctx sdk.Context, epoch var SetStorageTruthNodeFailureForTest = func(k Keeper, ctx sdk.Context, epochID uint64, reporterAccount string, result *types.StorageProofResult) error { return k.setStorageTruthNodeFailure(ctx, epochID, reporterAccount, result) } + +// ApplyTicketDeteriorationDeltaForTest exposes the internal apply path so +// external tests can exercise sibling-symmetry rules (e.g. the F119-F3 residue +// cross-holder PASS bonus). +var ApplyTicketDeteriorationDeltaForTest = func(k Keeper, ctx sdk.Context, epochID uint64, reporterAccount string, result *types.StorageProofResult, ticketID string, delta int64, decayPerEpoch int64, contradictionConfirmed bool) (types.TicketDeteriorationState, bool, error) { + return k.applyTicketDeteriorationDelta(ctx, epochID, reporterAccount, result, ticketID, delta, decayPerEpoch, contradictionConfirmed) +} + +// WriteRawNextHealOpIDForTest writes raw bytes to the next-heal-op-id store key, +// bypassing the well-formed encoder. Used to test panic-on-malformed (NEW-B-7). +var WriteRawNextHealOpIDForTest = func(k Keeper, ctx sdk.Context, raw []byte) { + k.kvStore(ctx).Set(types.NextHealOpIDKey(), raw) +} diff --git a/x/audit/v1/keeper/genesis.go b/x/audit/v1/keeper/genesis.go index 688ca788..d30a42f5 100644 --- a/x/audit/v1/keeper/genesis.go +++ b/x/audit/v1/keeper/genesis.go @@ -3,8 +3,10 @@ package keeper import ( "context" "errors" + "fmt" "github.com/LumeraProtocol/lumera/x/audit/v1/types" + sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -94,10 +96,57 @@ func (k Keeper) InitGenesis(ctx context.Context, genState types.GenesisState) er k.SetNextHealOpID(sdkCtx, nextHealOpID) // Per 121-F7 — restore storage-truth postponement markers on chain restart. + // Per NEW-B-6 / NEW-B-9 — cross-validate against supernode state so genesis + // cannot encode a phantom postponement (audit marker but supernode not in + // SuperNodeStatePostponed). Supernode genesis runs before audit + // (app/app_config.go) so the supernode state is loaded by this point. for _, p := range genState.StorageTruthPostponements { + sn, found, err := k.supernodeKeeper.GetSuperNodeByAccount(sdkCtx, p.SupernodeAccount) + if err != nil { + return fmt.Errorf("audit genesis: failed to look up supernode %q for storage-truth postponement: %w", p.SupernodeAccount, err) + } + if !found { + return fmt.Errorf("audit genesis: storage-truth postponement %q references unknown supernode", p.SupernodeAccount) + } + if len(sn.States) == 0 || sn.States[len(sn.States)-1].State != sntypes.SuperNodeStatePostponed { + return fmt.Errorf("audit genesis: storage-truth postponement %q lacks corresponding supernode-postponed state", p.SupernodeAccount) + } k.setStorageTruthPostponedAtEpochID(sdkCtx, p.SupernodeAccount, p.PostponedAtEpochId) } + // Per NEW-C-1 — restore epoch-scoped audit prefix families. + for _, e := range genState.RecheckEvidence { + k.SetRecheckEvidence(sdkCtx, e.EpochId, e.TicketId, e.CreatorAccount) + } + for _, t := range genState.StorageProofTranscripts { + if err := k.importStorageProofTranscriptForGenesis(sdkCtx, t.TranscriptHash, t.RecordJson); err != nil { + return err + } + } + for _, f := range genState.NodeFailureFacts { + k.importNodeFailureFactForGenesis(sdkCtx, f) + } + for _, f := range genState.ReporterResultFacts { + k.importReporterResultFactForGenesis(sdkCtx, f) + } + for _, m := range genState.FailedHealMarkers { + k.setStorageTruthFailedHeal(sdkCtx, m.SupernodeAccount, m.EpochId, m.TicketId) + } + for _, r := range genState.EpochReports { + if err := k.SetReportRaw(sdkCtx, r); err != nil { + return err + } + } + for _, idx := range genState.ReportIndices { + k.SetReportIndex(sdkCtx, idx.EpochId, idx.ReporterSupernodeAccount) + } + for _, idx := range genState.HostReportIndices { + k.SetHostReportIndex(sdkCtx, idx.EpochId, idx.ReporterSupernodeAccount) + } + for _, idx := range genState.StorageChallengeIndices { + k.SetStorageChallengeReportIndex(sdkCtx, idx.SupernodeAccount, idx.EpochId, idx.ReporterSupernodeAccount) + } + return nil } @@ -159,5 +208,20 @@ func (k Keeper) ExportGenesis(ctx context.Context) (*types.GenesisState, error) // Per 121-F7 — export storage-truth postponement markers. genesis.StorageTruthPostponements = k.GetAllStorageTruthPostponements(sdkCtx) + // Per NEW-C-1 — export every epoch-scoped audit prefix family. + genesis.RecheckEvidence = k.GetAllRecheckEvidenceForGenesis(sdkCtx) + genesis.StorageProofTranscripts = k.GetAllStorageProofTranscriptsForGenesis(sdkCtx) + genesis.NodeFailureFacts = k.GetAllNodeFailureFactsForGenesis(sdkCtx) + genesis.ReporterResultFacts = k.GetAllReporterResultFactsForGenesis(sdkCtx) + genesis.FailedHealMarkers = k.GetAllFailedHealMarkersForGenesis(sdkCtx) + reports, err := k.GetAllReportsForGenesis(sdkCtx) + if err != nil { + return nil, err + } + genesis.EpochReports = reports + genesis.ReportIndices = k.GetAllReportIndicesForGenesis(sdkCtx) + genesis.HostReportIndices = k.GetAllHostReportIndicesForGenesis(sdkCtx) + genesis.StorageChallengeIndices = k.GetAllStorageChallengeIndicesForGenesis(sdkCtx) + return genesis, nil } diff --git a/x/audit/v1/keeper/genesis_test.go b/x/audit/v1/keeper/genesis_test.go index 25ca2207..e9f0a2e8 100644 --- a/x/audit/v1/keeper/genesis_test.go +++ b/x/audit/v1/keeper/genesis_test.go @@ -4,7 +4,9 @@ import ( "testing" "github.com/LumeraProtocol/lumera/x/audit/v1/types" + sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" ) func TestGenesisParamsRoundTrip(t *testing.T) { @@ -62,14 +64,95 @@ func TestGenesisEvidenceRoundTripSetsNextID(t *testing.T) { require.Equal(t, uint64(1), got.NextHealOpId) } +func TestGenesis_RoundTripsAllStPrefixes(t *testing.T) { + f := initFixture(t) + + // Seed every NEW-C-1 prefix family with at least one record. + f.keeper.SetRecheckEvidence(f.ctx, 5, "ticket-rce", "lumera1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa5xm4ep") + + // Storage proof transcript via public IndexStorageProofTranscripts. + require.NoError(t, f.keeper.IndexStorageProofTranscripts(f.ctx, 5, "lumera1bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbadc7mh", []*types.StorageProofResult{{ + TranscriptHash: "h-abcd", + TargetSupernodeAccount: "lumera1cccccccccccccccccccccccccccccccccc7gqs5y", + TicketId: "ticket-spt", + ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, + BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, + }})) + + // Failed-heal marker. + require.NoError(t, f.keeper.SetParams(f.ctx, types.DefaultParams())) + // Use ProcessStorageTruthHealOpsAtEpochEnd to seed a failed-heal marker via expire? Use direct keeper helper exposed via genesis import. + // Simpler: import a marker through InitGenesis test seam — write via the genesis import directly using a constructed GenesisState below. + + // Report indices via public setters. + f.keeper.SetReportIndex(f.ctx, 7, "lumera1ddddddddddddddddddddddddddddddddddx2nrmt") + f.keeper.SetHostReportIndex(f.ctx, 7, "lumera1ddddddddddddddddddddddddddddddddddx2nrmt") + f.keeper.SetStorageChallengeReportIndex(f.ctx, "lumera1eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeennf6kk", 7, "lumera1ddddddddddddddddddddddddddddddddddx2nrmt") + + // EpochReport raw record. + require.NoError(t, f.keeper.SetReportRaw(f.ctx, types.EpochReport{ + EpochId: 9, + SupernodeAccount: "lumera1ddddddddddddddddddddddddddddddddddx2nrmt", + })) + + exported, err := f.keeper.ExportGenesis(f.ctx) + require.NoError(t, err) + require.NotNil(t, exported) + + // Sanity-check exports are non-empty for the seeded families. + require.NotEmpty(t, exported.RecheckEvidence) + require.NotEmpty(t, exported.StorageProofTranscripts) + require.NotEmpty(t, exported.ReportIndices) + require.NotEmpty(t, exported.HostReportIndices) + require.NotEmpty(t, exported.StorageChallengeIndices) + require.NotEmpty(t, exported.EpochReports) + + // Add a FailedHealMarker into exported state to verify InitGenesis re-emits it. + exported.FailedHealMarkers = append(exported.FailedHealMarkers, types.GenesisFailedHealMarker{ + SupernodeAccount: "lumera1cccccccccccccccccccccccccccccccccc7gqs5y", + EpochId: 5, + TicketId: "ticket-fh", + }) + + // Round-trip into a fresh fixture. + f2 := initFixture(t) + require.NoError(t, f2.keeper.InitGenesis(f2.ctx, *exported)) + + got, err := f2.keeper.ExportGenesis(f2.ctx) + require.NoError(t, err) + + require.ElementsMatch(t, exported.RecheckEvidence, got.RecheckEvidence) + require.ElementsMatch(t, exported.StorageProofTranscripts, got.StorageProofTranscripts) + require.ElementsMatch(t, exported.NodeFailureFacts, got.NodeFailureFacts) + require.ElementsMatch(t, exported.ReporterResultFacts, got.ReporterResultFacts) + require.ElementsMatch(t, exported.FailedHealMarkers, got.FailedHealMarkers) + require.ElementsMatch(t, exported.ReportIndices, got.ReportIndices) + require.ElementsMatch(t, exported.HostReportIndices, got.HostReportIndices) + require.ElementsMatch(t, exported.StorageChallengeIndices, got.StorageChallengeIndices) + require.Equal(t, len(exported.EpochReports), len(got.EpochReports)) +} + func TestGenesisStorageTruthPostponementRoundTrip(t *testing.T) { f := initFixture(t) + snA := sntypes.SuperNode{ + SupernodeAccount: "lumera1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa5xm4ep", + States: []*sntypes.SuperNodeStateRecord{{State: sntypes.SuperNodeStatePostponed, Height: 5}}, + } + snB := sntypes.SuperNode{ + SupernodeAccount: "lumera1bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbadc7mh", + States: []*sntypes.SuperNodeStateRecord{{State: sntypes.SuperNodeStatePostponed, Height: 7}}, + } + // Per NEW-B-6/B-9 — InitGenesis cross-validates audit postponements against + // supernode state. Match expectations to whichever account the keeper looks up first. + f.supernodeKeeper.EXPECT().GetSuperNodeByAccount(gomock.Any(), snA.SupernodeAccount).Return(snA, true, nil).Times(1) + f.supernodeKeeper.EXPECT().GetSuperNodeByAccount(gomock.Any(), snB.SupernodeAccount).Return(snB, true, nil).Times(1) + genesisState := types.GenesisState{ Params: types.DefaultParams(), StorageTruthPostponements: []types.StorageTruthPostponement{ - {SupernodeAccount: "lumera1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa5xm4ep", PostponedAtEpochId: 5}, - {SupernodeAccount: "lumera1bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbadc7mh", PostponedAtEpochId: 7}, + {SupernodeAccount: snA.SupernodeAccount, PostponedAtEpochId: 5}, + {SupernodeAccount: snB.SupernodeAccount, PostponedAtEpochId: 7}, }, } diff --git a/x/audit/v1/keeper/msg_storage_truth.go b/x/audit/v1/keeper/msg_storage_truth.go index 70d267f4..298eb389 100644 --- a/x/audit/v1/keeper/msg_storage_truth.go +++ b/x/audit/v1/keeper/msg_storage_truth.go @@ -402,6 +402,11 @@ func (m msgServer) finalizeHealOp( ticketState.DeteriorationScore = resetScore ticketState.LastHealEpoch = currentEpoch.EpochID ticketState.ProbationUntilEpoch = currentEpoch.EpochID + uint64(params.StorageTruthProbationEpochs) + // Per NEW-B-8 — verified heal restores fresh-start semantic on §20 counters. + ticketState.DistinctHolderFailureCount = 0 + ticketState.RecentFailureEpochCount = 0 + ticketState.LastIndexFailureEpoch = 0 + ticketState.LastFailureEpoch = 0 } else { // Failed heal: D += 15 ticketState.DeteriorationScore = addInt64Saturated(ticketState.DeteriorationScore, 15) diff --git a/x/audit/v1/keeper/msg_submit_epoch_report_storage_truth_scores_test.go b/x/audit/v1/keeper/msg_submit_epoch_report_storage_truth_scores_test.go index ffbc231d..48c95075 100644 --- a/x/audit/v1/keeper/msg_submit_epoch_report_storage_truth_scores_test.go +++ b/x/audit/v1/keeper/msg_submit_epoch_report_storage_truth_scores_test.go @@ -54,12 +54,14 @@ func TestSubmitEpochReport_StorageTruthScoresByResultClass(t *testing.T) { expectedTicketID string }{ { - // PASS + RECENT: node=-3, reporter=-4 (clamped to 0 from 0), ticket=-2 (clamped to 0) + // PASS + RECENT: node=-3, ticket=-2 (clamped to 0). + // Per NEW-A-18 — reporter delta moved to end-of-epoch; no per-result + // reporter state is created (expectedReporter=nil). name: "pass recent", class: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, bucket: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, expectedNodeScore: int64Ptr(0), // clamped at 0 - expectedReporter: int64Ptr(0), // clamped at 0 (positive-penalty model) + expectedReporter: nil, // Per NEW-A-18 — emission moved to end-of-epoch expectedTicketScore: int64Ptr(0), // clamped at 0 expectedTicketID: "ticket-1", }, @@ -74,12 +76,13 @@ func TestSubmitEpochReport_StorageTruthScoresByResultClass(t *testing.T) { expectedTicketID: "ticket-1", }, { - // TIMEOUT: node=+7, reporter=-1 clamped to 0, ticket=+3 + // TIMEOUT: node=+7, ticket=+3. + // Per NEW-A-18 — reporter PASS/TIMEOUT delta is 0; no reporter state created. name: "timeout", class: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_TIMEOUT_OR_NO_RESPONSE, bucket: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, expectedNodeScore: int64Ptr(7), - expectedReporter: int64Ptr(0), // clamped at 0 (was -1 before penalty model flip) + expectedReporter: nil, // Per NEW-A-18 — emission moved to end-of-epoch expectedTicketScore: int64Ptr(3), expectedTicketID: "ticket-1", }, @@ -340,12 +343,16 @@ func TestSubmitEpochReport_StorageTruthScoreEventsAreEmitted(t *testing.T) { require.Equal(t, target, attrs[types.AttributeKeyTargetSupernodeAccount]) require.Equal(t, "ticket-1", attrs[types.AttributeKeyTicketID]) require.Equal(t, types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS.String(), attrs[types.AttributeKeyResultClass]) - require.Equal(t, types.ReporterTrustBand_REPORTER_TRUST_BAND_NORMAL.String(), attrs[types.AttributeKeyReporterTrustBand]) + // Per NEW-A-18 — PASS no longer creates per-result reporter state, so the + // reporter trust band attribute reflects the zero-value (UNSPECIFIED) and + // no reporter_reliability_score attribute is emitted. + require.Equal(t, types.ReporterTrustBand_REPORTER_TRUST_BAND_UNSPECIFIED.String(), attrs[types.AttributeKeyReporterTrustBand]) require.Equal(t, "0", attrs[types.AttributeKeyRepeatedFailureCount]) require.Equal(t, "false", attrs[types.AttributeKeyContradictionDetected]) - // PASS RECENT: node=-3 clamped to 0, reporter=-4 clamped to 0, ticket=-2 clamped to 0 + // PASS RECENT: node=-3 clamped to 0, ticket=-2 clamped to 0. require.Equal(t, "0", attrs[types.AttributeKeyNodeSuspicionScore]) - require.Equal(t, "0", attrs[types.AttributeKeyReporterReliabilityScore]) + _, hasReporter := attrs[types.AttributeKeyReporterReliabilityScore] + require.False(t, hasReporter, "Per NEW-A-18 — reporter delta is 0 per-result, no reporter_score attr") require.Equal(t, "0", attrs[types.AttributeKeyTicketDeteriorationScore]) } require.True(t, found, "expected storage truth score update event") diff --git a/x/audit/v1/keeper/prune.go b/x/audit/v1/keeper/prune.go index 9d5f4e53..2a166408 100644 --- a/x/audit/v1/keeper/prune.go +++ b/x/audit/v1/keeper/prune.go @@ -75,7 +75,7 @@ func (k Keeper) PruneOldEpochs(ctx sdk.Context, currentEpochID uint64, params ty pruneTargetBucketEpoch(store, []byte("st/spt-tbe/"), minKeepEpochID) // Primary transcript store: st/spt/ -> JSON{epoch_id, ...}. // Records are not epoch-keyed, so decode value to filter. - pruneStorageProofTranscripts(store, []byte("st/spt/"), minKeepEpochID) + pruneStorageProofTranscripts(ctx, k, store, []byte("st/spt/"), minKeepEpochID) // Per 120-F3 — terminal heal-ops pruned to bound chain state growth. if err := k.pruneTerminalHealOps(ctx, currentEpochID, keepLastEpochEntries); err != nil { @@ -233,7 +233,12 @@ func pruneTargetBucketEpoch(store storetypes.KVStore, prefix []byte, minKeepWind // pruneStorageProofTranscripts prunes the primary transcript store st/spt/ -> JSON // by decoding the embedded epoch_id field. Records older than minKeepWindowID are deleted. // Per roomote 122 review — bounds long-term state growth. -func pruneStorageProofTranscripts(store storetypes.KVStore, prefix []byte, minKeepWindowID uint64) { +// +// Per NEW-C-4 / NEW-A-19 — malformed records that fail to decode are logged at +// the keeper logger so silent state corruption is observable. Records remain in +// place (pruning must not lose data on parse error) but the operator gets a +// signal to investigate. +func pruneStorageProofTranscripts(ctx sdk.Context, k Keeper, store storetypes.KVStore, prefix []byte, minKeepWindowID uint64) { it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) defer it.Close() @@ -247,6 +252,13 @@ func pruneStorageProofTranscripts(store storetypes.KVStore, prefix []byte, minKe var rec epochProbe if err := json.Unmarshal(it.Value(), &rec); err != nil { // Malformed record — leave in place; pruning must not lose data on parse error. + // Per NEW-C-4/NEW-A-19 — surface as warning so silent corruption is observable. + k.Logger().Error( + "audit: pruneStorageProofTranscripts skipped malformed record", + "prefix", string(prefix), + "key", it.Key(), + "err", err, + ) continue } if rec.EpochID >= minKeepWindowID { diff --git a/x/audit/v1/keeper/prune_storage_truth_test.go b/x/audit/v1/keeper/prune_storage_truth_test.go index 4c3fb9e2..c18b512e 100644 --- a/x/audit/v1/keeper/prune_storage_truth_test.go +++ b/x/audit/v1/keeper/prune_storage_truth_test.go @@ -15,6 +15,7 @@ import ( storetypes "cosmossdk.io/store/types" dbm "github.com/cosmos/cosmos-db" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) @@ -125,7 +126,7 @@ func TestPruneStorageProofTranscripts(t *testing.T) { // Malformed record — must be preserved (no data loss on parse error). kv.Set(append([]byte{}, append(prefix, "hbad"...)...), []byte("not-json")) - pruneStorageProofTranscripts(kv, prefix, 5) + pruneStorageProofTranscripts(sdk.Context{}, Keeper{logger: log.NewNopLogger()}, kv, prefix, 5) it := kv.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) defer it.Close() diff --git a/x/audit/v1/keeper/state.go b/x/audit/v1/keeper/state.go index eb0ecc47..46735105 100644 --- a/x/audit/v1/keeper/state.go +++ b/x/audit/v1/keeper/state.go @@ -1,6 +1,9 @@ package keeper import ( + "encoding/binary" + + storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/LumeraProtocol/lumera/x/audit/v1/types" @@ -81,3 +84,126 @@ func (k Keeper) SetHostReportIndex(ctx sdk.Context, epochID uint64, reporterSupe store := k.kvStore(ctx) store.Set(types.HostReportIndexKey(reporterSupernodeAccount, epochID), []byte{1}) } + +// GetAllReportsForGenesis exports all r/ epoch reports. +// Per NEW-C-1. +func (k Keeper) GetAllReportsForGenesis(ctx sdk.Context) ([]types.EpochReport, error) { + prefix := types.ReportPrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.EpochReport, 0) + for ; it.Valid(); it.Next() { + var r types.EpochReport + if err := k.cdc.Unmarshal(it.Value(), &r); err != nil { + return nil, err + } + out = append(out, r) + } + return out, nil +} + +// SetReportRaw writes an epoch report to its primary key without triggering +// supernode-state transitions. Used by InitGenesis to restore exported reports. +func (k Keeper) SetReportRaw(ctx sdk.Context, r types.EpochReport) error { + store := k.kvStore(ctx) + bz, err := k.cdc.Marshal(&r) + if err != nil { + return err + } + store.Set(types.ReportKey(r.EpochId, r.SupernodeAccount), bz) + return nil +} + +// GetAllReportIndicesForGenesis exports all ri/ index entries. +func (k Keeper) GetAllReportIndicesForGenesis(ctx sdk.Context) []types.GenesisReportIndex { + prefix := types.ReportIndexRootPrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.GenesisReportIndex, 0) + for ; it.Valid(); it.Next() { + // "ri/" + reporter + "/" + u64be(epoch_id) + key := it.Key() + body := key[len(prefix):] + if len(body) < 1+8 { + continue + } + // Find the last "/" before 8-byte epoch suffix. + // Reporter cannot contain '/' (bech32). Search forward for '/' followed by 8 bytes ending key. + split := len(body) - 8 - 1 + if split < 0 || body[split] != '/' { + continue + } + reporter := string(body[:split]) + epochID := binary.BigEndian.Uint64(body[split+1:]) + out = append(out, types.GenesisReportIndex{ + ReporterSupernodeAccount: reporter, + EpochId: epochID, + }) + } + return out +} + +// GetAllHostReportIndicesForGenesis exports all hr/ index entries. +func (k Keeper) GetAllHostReportIndicesForGenesis(ctx sdk.Context) []types.GenesisHostReportIndex { + prefix := types.HostReportIndexRootPrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.GenesisHostReportIndex, 0) + for ; it.Valid(); it.Next() { + key := it.Key() + body := key[len(prefix):] + split := len(body) - 8 - 1 + if split < 0 || body[split] != '/' { + continue + } + reporter := string(body[:split]) + epochID := binary.BigEndian.Uint64(body[split+1:]) + out = append(out, types.GenesisHostReportIndex{ + ReporterSupernodeAccount: reporter, + EpochId: epochID, + }) + } + return out +} + +// GetAllStorageChallengeIndicesForGenesis exports all sc/ index entries. +func (k Keeper) GetAllStorageChallengeIndicesForGenesis(ctx sdk.Context) []types.GenesisStorageChallengeIndex { + prefix := types.StorageChallengeReportIndexRootPrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.GenesisStorageChallengeIndex, 0) + for ; it.Valid(); it.Next() { + // "sc/" + supernode + "/" + u64be(epoch_id) + "/" + reporter + key := it.Key() + body := key[len(prefix):] + // Find first '/' + slash1 := -1 + for i := 0; i < len(body); i++ { + if body[i] == '/' { + slash1 = i + break + } + } + if slash1 < 0 || len(body) < slash1+1+8+1 { + continue + } + supernode := string(body[:slash1]) + epochID := binary.BigEndian.Uint64(body[slash1+1 : slash1+1+8]) + // next byte is '/' + reporter := string(body[slash1+1+8+1:]) + out = append(out, types.GenesisStorageChallengeIndex{ + SupernodeAccount: supernode, + EpochId: epochID, + ReporterSupernodeAccount: reporter, + }) + } + return out +} diff --git a/x/audit/v1/keeper/storage_truth_activation_test.go b/x/audit/v1/keeper/storage_truth_activation_test.go index eeb0ffbc..88037bd2 100644 --- a/x/audit/v1/keeper/storage_truth_activation_test.go +++ b/x/audit/v1/keeper/storage_truth_activation_test.go @@ -229,6 +229,9 @@ func TestStorageTruth_RecoveryWhenScoreDecaysBelowWatchThreshold(t *testing.T) { // After ~24 epochs: below 20. Let's use 30 epochs to be safe. params.StorageTruthNodeSuspicionDecayPerEpoch = 920 params.StorageTruthRecoveryCleanPassCount = 3 + // Per F121-F12 — strong-postpone recovery uses StrongRecoveryCleanPassCount. + // Score=200 hits the strong band, so the strong-recovery threshold applies. + params.StorageTruthStrongRecoveryCleanPassCount = 3 params.ConsecutiveEpochsToPostpone = 99 // Epoch 0: suspicion=200 hits StrongPostpone band (threshold=140). @@ -252,7 +255,8 @@ func TestStorageTruth_RecoveryWhenScoreDecaysBelowWatchThreshold(t *testing.T) { GetAllSuperNodes(gomock.AssignableToTypeOf(f.ctx), sntypes.SuperNodeStatePostponed). Return([]sntypes.SuperNode{}, nil) f.supernodeKeeper.EXPECT(). - SetSuperNodePostponed(gomock.AssignableToTypeOf(f.ctx), sdk.ValAddress(valAddr), "audit_storage_truth_suspicion"). + // Per F121-F12 — score=200 → STRONG (default strongThr=140). + SetSuperNodePostponed(gomock.AssignableToTypeOf(f.ctx), sdk.ValAddress(valAddr), "audit_storage_truth_strong_suspicion"). Return(nil).Times(1) require.NoError(t, f.keeper.EnforceEpochEnd(f.ctx, 0, params)) diff --git a/x/audit/v1/keeper/storage_truth_clean_recovery_test.go b/x/audit/v1/keeper/storage_truth_clean_recovery_test.go new file mode 100644 index 00000000..e6bbc586 --- /dev/null +++ b/x/audit/v1/keeper/storage_truth_clean_recovery_test.go @@ -0,0 +1,102 @@ +package keeper_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/LumeraProtocol/lumera/x/audit/v1/keeper" + "github.com/LumeraProtocol/lumera/x/audit/v1/types" +) + +// Per NEW-A-18 — verifies ApplyReporterCleanEpochRecoveryAtEpochEnd grants +// the spec §15.3 single −4 reliability delta on ≥5 PASS results in the +// closing epoch with no overturned-fail. + +// seedReporterPassResultsForEpoch writes count PASS records for the reporter at epochID. +func seedReporterPassResultsForEpoch(t *testing.T, f *fixture, reporterAccount string, epochID uint64, count int) { + t.Helper() + for i := 0; i < count; i++ { + result := &types.StorageProofResult{ + TicketId: fmt.Sprintf("%s-clean-%d", reporterAccount, i), + TargetSupernodeAccount: fmt.Sprintf("target-clean-%s-%d", reporterAccount, i), + ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, + BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, + } + require.NoError(t, keeper.SetStorageTruthReporterResultForTest(f.keeper, f.ctx, epochID, reporterAccount, result)) + } +} + +func TestApplyReporterCleanEpochRecovery_AppliesMinusFourOnFivePasses(t *testing.T) { + f := initFixture(t) + f.ctx = f.ctx.WithBlockHeight(1).WithEventManager(sdk.NewEventManager()) + + const epochID = uint64(7) + const reporter = "reporter-clean-five" + + // Seed prior reliability score 10 so the −4 delta is observable above the 0 floor. + require.NoError(t, f.keeper.SetReporterReliabilityState(f.ctx, types.ReporterReliabilityState{ + ReporterSupernodeAccount: reporter, + ReliabilityScore: 10, + LastUpdatedEpoch: epochID, // No decay step — isolate the -4 delta + })) + + // 5 PASS in epoch 7, no overturned-fails. + seedReporterPassResultsForEpoch(t, f, reporter, epochID, 5) + + params := f.keeper.GetParams(f.ctx).WithDefaults() + require.NoError(t, f.keeper.ApplyReporterCleanEpochRecoveryAtEpochEnd(f.ctx, epochID, params)) + + final, found := f.keeper.GetReporterReliabilityState(f.ctx, reporter) + require.True(t, found) + require.Equal(t, int64(6), final.ReliabilityScore, "10 + (-4) = 6") +} + +func TestApplyReporterCleanEpochRecovery_NoEffectOnFourPasses(t *testing.T) { + f := initFixture(t) + f.ctx = f.ctx.WithBlockHeight(1).WithEventManager(sdk.NewEventManager()) + + const epochID = uint64(7) + const reporter = "reporter-clean-four" + + require.NoError(t, f.keeper.SetReporterReliabilityState(f.ctx, types.ReporterReliabilityState{ + ReporterSupernodeAccount: reporter, + ReliabilityScore: 10, + LastUpdatedEpoch: epochID, // No decay step — isolate the -4 delta + })) + + seedReporterPassResultsForEpoch(t, f, reporter, epochID, 4) // below threshold of 5 + + params := f.keeper.GetParams(f.ctx).WithDefaults() + require.NoError(t, f.keeper.ApplyReporterCleanEpochRecoveryAtEpochEnd(f.ctx, epochID, params)) + + final, found := f.keeper.GetReporterReliabilityState(f.ctx, reporter) + require.True(t, found) + require.Equal(t, int64(10), final.ReliabilityScore, "below 5-PASS minimum: no delta") +} + +func TestApplyReporterCleanEpochRecovery_ScoresFloorAtZero(t *testing.T) { + f := initFixture(t) + f.ctx = f.ctx.WithBlockHeight(1).WithEventManager(sdk.NewEventManager()) + + const epochID = uint64(7) + const reporter = "reporter-clean-floor" + + // Score already at 0 — recovery should not push it negative. + require.NoError(t, f.keeper.SetReporterReliabilityState(f.ctx, types.ReporterReliabilityState{ + ReporterSupernodeAccount: reporter, + ReliabilityScore: 0, + LastUpdatedEpoch: epochID, // No decay step — isolate the -4 delta + })) + + seedReporterPassResultsForEpoch(t, f, reporter, epochID, 5) + + params := f.keeper.GetParams(f.ctx).WithDefaults() + require.NoError(t, f.keeper.ApplyReporterCleanEpochRecoveryAtEpochEnd(f.ctx, epochID, params)) + + final, found := f.keeper.GetReporterReliabilityState(f.ctx, reporter) + require.True(t, found) + require.GreaterOrEqual(t, final.ReliabilityScore, int64(0), "score must not go negative") +} diff --git a/x/audit/v1/keeper/storage_truth_cross_holder_pass_test.go b/x/audit/v1/keeper/storage_truth_cross_holder_pass_test.go new file mode 100644 index 00000000..a136b8f7 --- /dev/null +++ b/x/audit/v1/keeper/storage_truth_cross_holder_pass_test.go @@ -0,0 +1,143 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/LumeraProtocol/lumera/x/audit/v1/keeper" + "github.com/LumeraProtocol/lumera/x/audit/v1/types" +) + +// TestApplyTicketDeteriorationDelta_CrossHolderPassBonus exercises F119-F3 residue: +// when a PASS lands on a ticket whose prior-holder state recorded a failure from a +// DIFFERENT holder, an additional -3 ticket-deterioration delta is applied on top +// of the base bucket reduction. +func TestApplyTicketDeteriorationDelta_CrossHolderPassBonus(t *testing.T) { + t.Run("PASS by different holder applies extra -3 bonus", func(t *testing.T) { + f := initFixture(t) + const ticketID = "ticket-cross-holder" + const epochID = uint64(10) + + // Seed prior failure state: holder A failed at epoch 9 with HASH_MISMATCH. + require.NoError(t, f.keeper.SetTicketDeteriorationState(f.ctx, types.TicketDeteriorationState{ + TicketId: ticketID, + DeteriorationScore: 50, + LastUpdatedEpoch: epochID, // Avoid decay on the read. + LastTargetSupernodeAccount: "holder-A", + LastResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_HASH_MISMATCH, + LastResultEpoch: epochID - 1, + LastFailureEpoch: epochID - 1, + })) + + // Now holder B passes: per F119-F3 residue, base PASS RECENT delta is -2, + // PLUS additional -3 cross-holder bonus = -5 total. + passResult := &types.StorageProofResult{ + TicketId: ticketID, + TargetSupernodeAccount: "holder-B", + ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, + BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, + } + // delta = -2 (RECENT bucket PASS base). Decay disabled (delta=0 epochs). + _, _, err := keeper.ApplyTicketDeteriorationDeltaForTest( + f.keeper, f.ctx, epochID, "reporter-1", passResult, ticketID, -2, 0, false, + ) + require.NoError(t, err) + + final, found := f.keeper.GetTicketDeteriorationState(f.ctx, ticketID) + require.True(t, found) + // 50 + (-2 base) + (-3 cross-holder) = 45 + require.Equal(t, int64(45), final.DeteriorationScore, + "PASS by different holder must apply both base bucket delta and -3 cross-holder bonus") + }) + + t.Run("PASS by same holder gets only base delta (no cross-holder bonus)", func(t *testing.T) { + f := initFixture(t) + const ticketID = "ticket-same-holder" + const epochID = uint64(10) + + require.NoError(t, f.keeper.SetTicketDeteriorationState(f.ctx, types.TicketDeteriorationState{ + TicketId: ticketID, + DeteriorationScore: 50, + LastUpdatedEpoch: epochID, + LastTargetSupernodeAccount: "holder-A", + LastResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_HASH_MISMATCH, + LastResultEpoch: epochID - 1, + LastFailureEpoch: epochID - 1, + })) + + passResult := &types.StorageProofResult{ + TicketId: ticketID, + TargetSupernodeAccount: "holder-A", // SAME holder + ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, + BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, + } + _, _, err := keeper.ApplyTicketDeteriorationDeltaForTest( + f.keeper, f.ctx, epochID, "reporter-1", passResult, ticketID, -2, 0, false, + ) + require.NoError(t, err) + + final, found := f.keeper.GetTicketDeteriorationState(f.ctx, ticketID) + require.True(t, found) + // 50 + (-2 base) = 48. NO cross-holder bonus since holder is the same. + require.Equal(t, int64(48), final.DeteriorationScore, + "PASS by same holder must apply only the base delta, no cross-holder bonus") + }) + + t.Run("PASS without prior failure (fresh ticket) gets only base delta", func(t *testing.T) { + f := initFixture(t) + const ticketID = "ticket-fresh" + const epochID = uint64(10) + + // No prior state — fresh ticket. + passResult := &types.StorageProofResult{ + TicketId: ticketID, + TargetSupernodeAccount: "holder-B", + ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, + BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, + } + _, _, err := keeper.ApplyTicketDeteriorationDeltaForTest( + f.keeper, f.ctx, epochID, "reporter-1", passResult, ticketID, -2, 0, false, + ) + require.NoError(t, err) + + final, found := f.keeper.GetTicketDeteriorationState(f.ctx, ticketID) + require.True(t, found) + // 0 + (-2) clamped at 0 = 0. + require.Equal(t, int64(0), final.DeteriorationScore, + "fresh ticket PASS clamps at 0; no cross-holder bonus without prior state") + }) + + t.Run("PASS by different holder but prior was PASS (not failure) — no bonus", func(t *testing.T) { + f := initFixture(t) + const ticketID = "ticket-prior-pass" + const epochID = uint64(10) + + // Prior state has different holder but it was a PASS, not a failure. + require.NoError(t, f.keeper.SetTicketDeteriorationState(f.ctx, types.TicketDeteriorationState{ + TicketId: ticketID, + DeteriorationScore: 50, + LastUpdatedEpoch: epochID, + LastTargetSupernodeAccount: "holder-A", + LastResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, + LastResultEpoch: epochID - 1, + })) + + passResult := &types.StorageProofResult{ + TicketId: ticketID, + TargetSupernodeAccount: "holder-B", + ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, + BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, + } + _, _, err := keeper.ApplyTicketDeteriorationDeltaForTest( + f.keeper, f.ctx, epochID, "reporter-1", passResult, ticketID, -2, 0, false, + ) + require.NoError(t, err) + + final, found := f.keeper.GetTicketDeteriorationState(f.ctx, ticketID) + require.True(t, found) + // 50 + (-2) = 48. Bonus only fires on prior FAILURE class, not prior PASS. + require.Equal(t, int64(48), final.DeteriorationScore, + "prior PASS (not failure) → no cross-holder recovery bonus") + }) +} diff --git a/x/audit/v1/keeper/storage_truth_divergence.go b/x/audit/v1/keeper/storage_truth_divergence.go index 1354c651..c9906bc3 100644 --- a/x/audit/v1/keeper/storage_truth_divergence.go +++ b/x/audit/v1/keeper/storage_truth_divergence.go @@ -2,10 +2,10 @@ package keeper import ( "encoding/json" + "math/big" "sort" "strconv" - storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/LumeraProtocol/lumera/x/audit/v1/types" @@ -60,23 +60,24 @@ func (k Keeper) ApplyReporterDivergenceAtEpochEnd(ctx sdk.Context, epochID uint6 return nil } - // Sort by neg/total ratio using integer cross-multiply to avoid float64 non-determinism. + // Sort by neg/total ratio using *big.Int cross-multiply to avoid float64 + // non-determinism (121-F16) AND uint64 overflow when neg/total approach + // or exceed 2^32 (CP-NEW-A-13). // a.negative/a.total < b.negative/b.total ⟺ a.negative*b.total < b.negative*a.total sort.Slice(qualifying, func(i, j int) bool { - return qualifying[i].negative*qualifying[j].total < qualifying[j].negative*qualifying[i].total + lhs := new(big.Int).Mul(new(big.Int).SetUint64(qualifying[i].negative), new(big.Int).SetUint64(qualifying[j].total)) + rhs := new(big.Int).Mul(new(big.Int).SetUint64(qualifying[j].negative), new(big.Int).SetUint64(qualifying[i].total)) + return lhs.Cmp(rhs) < 0 }) // Compute median neg-rate as an integer pair (medianNeg, medianTotal). - // For even-length slices, use the lower-median element to stay conservative. + // Per NEW-A-16 — upper-pair selection is more conservative (harder to penalize): + // a higher median raises the 2x threshold, making it harder to flag a reporter + // as a divergence outlier. For odd-length slices index `mid` is the unique median; + // for even-length slices index `mid` is the upper of the two middle elements. mid := len(qualifying) / 2 - var medianNeg, medianTotal uint64 - if len(qualifying)%2 == 1 { - medianNeg = qualifying[mid].negative - medianTotal = qualifying[mid].total - } else { - medianNeg = qualifying[mid-1].negative - medianTotal = qualifying[mid-1].total - } + medianNeg := qualifying[mid].negative + medianTotal := qualifying[mid].total if medianTotal == 0 { return nil @@ -85,8 +86,16 @@ func (k Keeper) ApplyReporterDivergenceAtEpochEnd(ctx sdk.Context, epochID uint6 // Penalize reporters whose neg_rate > 2x median. // entry.negative/entry.total > 2*medianNeg/medianTotal // ⟺ entry.negative * medianTotal > 2 * medianNeg * entry.total + // *big.Int cross-multiply protects against uint64 overflow (CP-NEW-A-13). + bigMedianTotal := new(big.Int).SetUint64(medianTotal) + bigMedianNegX2 := new(big.Int).Mul(new(big.Int).SetUint64(medianNeg), big.NewInt(2)) for _, entry := range qualifying { - if entry.total == 0 || entry.negative*medianTotal <= 2*medianNeg*entry.total { + if entry.total == 0 { + continue + } + lhs := new(big.Int).Mul(new(big.Int).SetUint64(entry.negative), bigMedianTotal) + rhs := new(big.Int).Mul(bigMedianNegX2, new(big.Int).SetUint64(entry.total)) + if lhs.Cmp(rhs) <= 0 { continue } if entry.negative != 0 && entry.confirmedNegatives*2 >= entry.negative { @@ -128,19 +137,95 @@ type storageTruthDivergenceStats struct { confirmedNegative uint64 } +// ApplyReporterCleanEpochRecoveryAtEpochEnd implements the per-EPOCH recovery +// half of NEW-A-18 (LEP6.md §15.3): for each reporter, if they produced >=5 +// PASS results in the closing epoch AND no PASS was overturned by recheck, +// apply a single -4 reduction to their reliability score. Per-result PASS/ +// TIMEOUT reporter deltas are 0 (see storageTruthScoreDeltasForResult); the +// recovery is consolidated here to avoid score deflation under high volume. +// +// The PASS-count threshold is intentionally hardcoded to 5 (Pitfall #13 — +// const-now/param-later); promote to a Param if governance ever needs tuning. +func (k Keeper) ApplyReporterCleanEpochRecoveryAtEpochEnd(ctx sdk.Context, epochID uint64, params types.Params) error { + const cleanPassesRequired = 5 + + states, err := k.GetAllReporterReliabilityStates(ctx) + if err != nil { + return err + } + if len(states) == 0 { + return nil + } + + for _, state := range states { + passes, overturned, err := k.storageTruthReporterEpochPassStats(ctx, state.ReporterSupernodeAccount, epochID) + if err != nil { + return err + } + if overturned || passes < cleanPassesRequired { + continue + } + + if _, _, err := k.applyReporterReliabilityDelta( + ctx, + epochID, + state.ReporterSupernodeAccount, + -4, + params.StorageTruthReporterReliabilityDecayPerEpoch, + 0, + params, + ); err != nil { + return err + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeStorageTruthScoreUpdated, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyEpochID, strconv.FormatUint(epochID, 10)), + sdk.NewAttribute(types.AttributeKeyReporterSupernodeAccount, state.ReporterSupernodeAccount), + sdk.NewAttribute("clean_epoch_recovery_delta", "-4"), + sdk.NewAttribute("epoch_pass_count", strconv.FormatUint(passes, 10)), + )) + } + return nil +} + +// storageTruthReporterEpochPassStats counts PASS results for a reporter in a +// single epoch and reports whether any of them was overturned by recheck. +func (k Keeper) storageTruthReporterEpochPassStats(ctx sdk.Context, reporterAccount string, epochID uint64) (uint64, bool, error) { + start, end := types.ReporterStorageTruthResultEpochScanRange(reporterAccount, epochID, epochID) + it := k.kvStore(ctx).Iterator(start, end) + defer it.Close() + var passes uint64 + var overturned bool + for ; it.Valid(); it.Next() { + var record storageTruthReporterResultRecord + if err := json.Unmarshal(it.Value(), &record); err != nil { + return 0, false, err + } + if types.StorageProofResultClass(record.ResultClass) != types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS { + continue + } + passes++ + if record.OverturnedByRecheck { + overturned = true + } + } + return passes, overturned, nil +} + func (k Keeper) storageTruthReporterDivergenceStats(ctx sdk.Context, reporterAccount string, startEpoch uint64, endEpoch uint64) (storageTruthDivergenceStats, error) { var stats storageTruthDivergenceStats - prefix := types.ReporterStorageTruthResultPrefix(reporterAccount) - it := k.kvStore(ctx).Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + // Bounded epoch scan per CP-NEW-A-11 residue — key shape unchanged, + // only iterator bounds use [startEpoch, endEpoch+1). + start, end := types.ReporterStorageTruthResultEpochScanRange(reporterAccount, startEpoch, endEpoch) + it := k.kvStore(ctx).Iterator(start, end) defer it.Close() for ; it.Valid(); it.Next() { var record storageTruthReporterResultRecord if err := json.Unmarshal(it.Value(), &record); err != nil { return stats, err } - if record.EpochID < startEpoch || record.EpochID > endEpoch { - continue - } stats.total++ if isStorageTruthFailureClass(types.StorageProofResultClass(record.ResultClass)) { stats.negative++ diff --git a/x/audit/v1/keeper/storage_truth_fact_indexes.go b/x/audit/v1/keeper/storage_truth_fact_indexes.go index 3553f732..7b9ffcbb 100644 --- a/x/audit/v1/keeper/storage_truth_fact_indexes.go +++ b/x/audit/v1/keeper/storage_truth_fact_indexes.go @@ -183,6 +183,23 @@ func (k Keeper) markStorageTruthReporterResultRecheck(ctx sdk.Context, reporterA return nil } +// linkStorageTruthRecheckTranscript wires a recheck transcript onto the +// challenged transcript so subsequent reads see the link. Per NEW-B-5 and +// the LEP-6 implementation guide § Recheck Evidence § Replay protection key: +// +// - The recheck-evidence dedup key (st/rce/<...>) enforces single-witness +// uniqueness PER CREATOR. A given recheck observer cannot replay the same +// (epoch_id, ticket_id, target_account) tuple twice — that's the per-creator +// single-witness invariant enforced at link time. +// - Cross-creator quorum (multiple distinct recheck observers reaching the +// same conclusion) is enforced LATER in scoring at epoch end, not here. +// The link function deliberately does NOT count witnesses; it just records +// the wiring. +// - 122-F3 collision check below ensures a recheck-transcript hash cannot +// be re-bound to a different challenged transcript later. +// +// Therefore "single-witness recheck" at this layer is intentional and not +// a missing-quorum bug. func (k Keeper) linkStorageTruthRecheckTranscript( ctx sdk.Context, challengedTranscriptHash string, @@ -241,17 +258,15 @@ func (k Keeper) linkStorageTruthRecheckTranscript( func (k Keeper) distinctNodeFailedTickets(ctx sdk.Context, supernodeAccount string, startEpoch uint64, endEpoch uint64, include func(storageTruthNodeFailureRecord) bool) (map[string]struct{}, uint32, error) { tickets := make(map[string]struct{}) var events uint32 - prefix := types.NodeStorageTruthFailurePrefix(supernodeAccount) - it := k.kvStore(ctx).Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + // Bounded epoch scan per CP-NEW-A-11 residue. + start, end := types.NodeStorageTruthFailureEpochScanRange(supernodeAccount, startEpoch, endEpoch) + it := k.kvStore(ctx).Iterator(start, end) defer it.Close() for ; it.Valid(); it.Next() { var record storageTruthNodeFailureRecord if err := json.Unmarshal(it.Value(), &record); err != nil { return nil, 0, err } - if record.EpochID < startEpoch || record.EpochID > endEpoch { - continue - } if include != nil && !include(record) { continue } @@ -361,6 +376,186 @@ func (k Keeper) hasStorageTruthFailedHeal(ctx sdk.Context, supernodeAccount stri return false } +// GetAllStorageProofTranscriptsForGenesis exports all st/spt/ records as raw JSON value bytes. +// Per NEW-C-1: secondary index st/spt-tbe/ is rebuilt by setStorageProofTranscriptRecord on InitGenesis. +func (k Keeper) GetAllStorageProofTranscriptsForGenesis(ctx sdk.Context) []types.GenesisStorageProofTranscript { + prefix := types.StorageProofTranscriptPrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.GenesisStorageProofTranscript, 0) + for ; it.Valid(); it.Next() { + key := it.Key() + hash := string(key[len(prefix):]) + val := append([]byte(nil), it.Value()...) + out = append(out, types.GenesisStorageProofTranscript{ + TranscriptHash: hash, + RecordJson: val, + }) + } + return out +} + +// importStorageProofTranscriptForGenesis re-emits a transcript record (writing the +// st/spt-tbe/ secondary index alongside) so genesis-imported state matches runtime. +func (k Keeper) importStorageProofTranscriptForGenesis(ctx sdk.Context, hash string, recordJSON []byte) error { + var rec storageProofTranscriptRecord + if err := json.Unmarshal(recordJSON, &rec); err != nil { + return err + } + return k.setStorageProofTranscriptRecord(ctx, hash, rec) +} + +// GetAllNodeFailureFactsForGenesis exports all st/nf/ records. +func (k Keeper) GetAllNodeFailureFactsForGenesis(ctx sdk.Context) []types.GenesisNodeFailureFact { + prefix := types.NodeStorageTruthFailureRootPrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.GenesisNodeFailureFact, 0) + for ; it.Valid(); it.Next() { + key := it.Key() + body := key[len(prefix):] + // "" + '/' + u64be(epoch) + '/' + ticket + 0x00 + reporter + // supernode does not contain '/' (bech32) — split at first '/'. + slash1 := -1 + for i := 0; i < len(body); i++ { + if body[i] == '/' { + slash1 = i + break + } + } + if slash1 < 0 || len(body) < slash1+1+8+1 { + continue + } + supernode := string(body[:slash1]) + epochID := binary.BigEndian.Uint64(body[slash1+1 : slash1+1+8]) + // next byte is '/' + rest := body[slash1+1+8+1:] + // rest = ticket + 0x00 + reporter + sep := -1 + for i := 0; i < len(rest); i++ { + if rest[i] == 0 { + sep = i + break + } + } + if sep < 0 { + continue + } + ticket := string(rest[:sep]) + reporter := string(rest[sep+1:]) + val := append([]byte(nil), it.Value()...) + out = append(out, types.GenesisNodeFailureFact{ + SupernodeAccount: supernode, + EpochId: epochID, + TicketId: ticket, + ReporterAccount: reporter, + RecordJson: val, + }) + } + return out +} + +// importNodeFailureFactForGenesis writes a raw st/nf/ record to its key. +func (k Keeper) importNodeFailureFactForGenesis(ctx sdk.Context, fact types.GenesisNodeFailureFact) { + k.kvStore(ctx).Set(types.NodeStorageTruthFailureKey(fact.SupernodeAccount, fact.EpochId, fact.TicketId, fact.ReporterAccount), fact.RecordJson) +} + +// GetAllReporterResultFactsForGenesis exports all st/rrs/ records. +// Per NEW-C-1: secondary index st/rrs-tt/ is rebuilt by setStorageTruthReporterResult-equivalent +// import path on InitGenesis. +func (k Keeper) GetAllReporterResultFactsForGenesis(ctx sdk.Context) []types.GenesisReporterResultFact { + prefix := types.ReporterStorageTruthResultRootPrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.GenesisReporterResultFact, 0) + for ; it.Valid(); it.Next() { + key := it.Key() + body := key[len(prefix):] + // "" + '/' + u64be(epoch) + '/' + ticket + 0x00 + target + slash1 := -1 + for i := 0; i < len(body); i++ { + if body[i] == '/' { + slash1 = i + break + } + } + if slash1 < 0 || len(body) < slash1+1+8+1 { + continue + } + reporter := string(body[:slash1]) + epochID := binary.BigEndian.Uint64(body[slash1+1 : slash1+1+8]) + rest := body[slash1+1+8+1:] + sep := -1 + for i := 0; i < len(rest); i++ { + if rest[i] == 0 { + sep = i + break + } + } + if sep < 0 { + continue + } + ticket := string(rest[:sep]) + target := string(rest[sep+1:]) + val := append([]byte(nil), it.Value()...) + out = append(out, types.GenesisReporterResultFact{ + ReporterAccount: reporter, + EpochId: epochID, + TicketId: ticket, + TargetAccount: target, + RecordJson: val, + }) + } + return out +} + +// importReporterResultFactForGenesis writes both the primary and secondary indexes. +func (k Keeper) importReporterResultFactForGenesis(ctx sdk.Context, f types.GenesisReporterResultFact) { + store := k.kvStore(ctx) + store.Set(types.ReporterStorageTruthResultKey(f.ReporterAccount, f.EpochId, f.TicketId, f.TargetAccount), f.RecordJson) + store.Set(types.ReporterStorageTruthResultByTargetKey(f.TargetAccount, f.EpochId, f.TicketId, f.ReporterAccount), f.RecordJson) +} + +// GetAllFailedHealMarkersForGenesis exports all st/fh/ marker keys. +func (k Keeper) GetAllFailedHealMarkersForGenesis(ctx sdk.Context) []types.GenesisFailedHealMarker { + prefix := types.StorageTruthFailedHealRootPrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.GenesisFailedHealMarker, 0) + for ; it.Valid(); it.Next() { + key := it.Key() + body := key[len(prefix):] + // "" + '/' + u64be(epoch) + '/' + ticket + slash1 := -1 + for i := 0; i < len(body); i++ { + if body[i] == '/' { + slash1 = i + break + } + } + if slash1 < 0 || len(body) < slash1+1+8+1 { + continue + } + supernode := string(body[:slash1]) + epochID := binary.BigEndian.Uint64(body[slash1+1 : slash1+1+8]) + ticket := string(body[slash1+1+8+1:]) + out = append(out, types.GenesisFailedHealMarker{ + SupernodeAccount: supernode, + EpochId: epochID, + TicketId: ticket, + }) + } + return out +} + func isStorageTruthRecheckEligible(class types.StorageProofResultClass) bool { switch class { case types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_HASH_MISMATCH, diff --git a/x/audit/v1/keeper/storage_truth_heal_ops.go b/x/audit/v1/keeper/storage_truth_heal_ops.go index 448eaf23..cc229f9f 100644 --- a/x/audit/v1/keeper/storage_truth_heal_ops.go +++ b/x/audit/v1/keeper/storage_truth_heal_ops.go @@ -13,13 +13,13 @@ import ( ) func (k Keeper) ProcessStorageTruthHealOpsAtEpochEnd(ctx sdk.Context, epochID uint64, params types.Params) error { - if err := k.expireStorageTruthHealOpsAtEpochEnd(ctx, epochID); err != nil { + if err := k.expireStorageTruthHealOpsAtEpochEnd(ctx, epochID, params); err != nil { return err } return k.scheduleStorageTruthHealOpsAtEpochEnd(ctx, epochID, params) } -func (k Keeper) expireStorageTruthHealOpsAtEpochEnd(ctx sdk.Context, epochID uint64) error { +func (k Keeper) expireStorageTruthHealOpsAtEpochEnd(ctx sdk.Context, epochID uint64, params types.Params) error { healOps, err := k.GetAllHealOps(ctx) if err != nil { return err @@ -40,11 +40,20 @@ func (k Keeper) expireStorageTruthHealOpsAtEpochEnd(ctx sdk.Context, epochID uin } ticketState, found := k.GetTicketDeteriorationState(ctx, healOp.TicketId) - if found && ticketState.ActiveHealOpId == healOp.HealOpId { - ticketState.ActiveHealOpId = 0 + if found { + // NEW-B-1 — apply §20 no-show cooldown to EXPIRED heal-op (mirror FAILED branch). + ticketState.DeteriorationScore = addInt64Saturated(ticketState.DeteriorationScore, 15) + cooldownUntil := epochID + uint64(params.StorageTruthProbationEpochs) + if ticketState.ProbationUntilEpoch < cooldownUntil { + ticketState.ProbationUntilEpoch = cooldownUntil + } + if ticketState.ActiveHealOpId == healOp.HealOpId { + ticketState.ActiveHealOpId = 0 + } if err := k.SetTicketDeteriorationState(ctx, ticketState); err != nil { return err } + k.setStorageTruthFailedHeal(ctx, healOp.HealerSupernodeAccount, epochID, healOp.TicketId) } ctx.EventManager().EmitEvent( @@ -106,7 +115,11 @@ func (k Keeper) scheduleStorageTruthHealOpsAtEpochEnd(ctx sdk.Context, epochID u if probationThreshold > 0 { if suspicionStates, err := k.GetAllNodeSuspicionStates(ctx); err == nil { for _, ss := range suspicionStates { - if ss.SuspicionScore >= probationThreshold { + // Per NEW-B-2 — sibling-symmetry with enforcement.go decay-adjusted read. + score := decayTowardZero(ss.SuspicionScore, + params.StorageTruthNodeSuspicionDecayPerEpoch, + epochDelta(epochID, ss.LastUpdatedEpoch)) + if score >= probationThreshold { ineligibleHealers[ss.SupernodeAccount] = struct{}{} } } @@ -216,8 +229,17 @@ func (k Keeper) scheduleStorageTruthHealOpsAtEpochEnd(ctx sdk.Context, epochID u continue } - healer, verifiers := assignStorageTruthHealParticipants(eligibleHealers, cand.ticketID, epochID) + healer, verifiers := assignStorageTruthHealParticipants(eligibleHealers, cand.ticketID, epochID, params) if len(verifiers) == 0 { + // Per NEW-B-4 — sibling-symmetry with InsufficientHealers: emit + // observability event when verifier pool is empty so operators can + // see why a heal op was not scheduled. + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeHealOpInsufficientVerifiers, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyTicketID, cand.ticketID), + sdk.NewAttribute(types.AttributeKeyEpochID, strconv.FormatUint(epochID, 10)), + )) continue } healOpID := k.GetNextHealOpID(ctx) @@ -285,7 +307,7 @@ func (k Keeper) storageTruthSchedulerAccounts(ctx sdk.Context, epochID uint64) ( return accounts, nil } -func assignStorageTruthHealParticipants(activeAccounts []string, ticketID string, epochID uint64) (string, []string) { +func assignStorageTruthHealParticipants(activeAccounts []string, ticketID string, epochID uint64, params types.Params) (string, []string) { if len(activeAccounts) == 0 { return "", nil } @@ -297,7 +319,11 @@ func assignStorageTruthHealParticipants(activeAccounts []string, ticketID string return healer, nil } - verifierCount := 2 + // Per NEW-B-3 — verifier count is governance-tunable (default 2). + verifierCount := int(params.StorageTruthHealVerifierCount) + if verifierCount <= 0 { + verifierCount = int(types.DefaultStorageTruthHealVerifierCount) + } if verifierCount > len(activeAccounts)-1 { verifierCount = len(activeAccounts) - 1 } diff --git a/x/audit/v1/keeper/storage_truth_heal_ops_test.go b/x/audit/v1/keeper/storage_truth_heal_ops_test.go index 267b7930..82c3c692 100644 --- a/x/audit/v1/keeper/storage_truth_heal_ops_test.go +++ b/x/audit/v1/keeper/storage_truth_heal_ops_test.go @@ -118,3 +118,51 @@ func TestProcessStorageTruthHealOpsAtEpochEnd_ExpiresPastDeadline(t *testing.T) require.True(t, found) require.Equal(t, uint64(0), ticketState.ActiveHealOpId) } + +// NEW-B-1 — verify expireStorageTruthHealOpsAtEpochEnd applies the §20 no-show +// cooldown to EXPIRED heal-ops (mirror of FAILED branch): score +=15, +// probation advanced, st/fh/ marker written. +func TestExpireStorageTruthHealOps_AdvancesProbationAndCooldown(t *testing.T) { + f := initFixture(t) + f.ctx = f.ctx.WithBlockHeight(1600).WithEventManager(sdk.NewEventManager()) + + params := f.keeper.GetParams(f.ctx).WithDefaults() + params.StorageTruthMaxSelfHealOpsPerEpoch = 0 // expire-only + params.StorageTruthProbationEpochs = 4 + require.NoError(t, f.keeper.SetParams(f.ctx, params)) + + const ( + ticketID = "ticket-cooldown" + healer = "lumera1cccccccccccccccccccccccccccccccccc7gqs5y" + healOpID = uint64(800) + epochID = uint64(3) + ) + + require.NoError(t, f.keeper.SetHealOp(f.ctx, types.HealOp{ + HealOpId: healOpID, + TicketId: ticketID, + ScheduledEpochId: 1, + HealerSupernodeAccount: healer, + VerifierSupernodeAccounts: []string{"lumera1eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeennf6kk"}, + Status: types.HealOpStatus_HEAL_OP_STATUS_HEALER_REPORTED, + DeadlineEpochId: epochID, // due at this epoch + })) + require.NoError(t, f.keeper.SetTicketDeteriorationState(f.ctx, types.TicketDeteriorationState{ + TicketId: ticketID, + DeteriorationScore: 50, + ActiveHealOpId: healOpID, + })) + + require.NoError(t, f.keeper.ProcessStorageTruthHealOpsAtEpochEnd(f.ctx, epochID, params)) + + expired, found := f.keeper.GetHealOp(f.ctx, healOpID) + require.True(t, found) + require.Equal(t, types.HealOpStatus_HEAL_OP_STATUS_EXPIRED, expired.Status) + + state, found := f.keeper.GetTicketDeteriorationState(f.ctx, ticketID) + require.True(t, found) + require.Equal(t, int64(65), state.DeteriorationScore, "deterioration score must bump by 15") + require.GreaterOrEqual(t, state.ProbationUntilEpoch, epochID+uint64(params.StorageTruthProbationEpochs), + "probation must be advanced by ProbationEpochs") + require.Equal(t, uint64(0), state.ActiveHealOpId) +} diff --git a/x/audit/v1/keeper/storage_truth_low_findings_test.go b/x/audit/v1/keeper/storage_truth_low_findings_test.go new file mode 100644 index 00000000..de54714e --- /dev/null +++ b/x/audit/v1/keeper/storage_truth_low_findings_test.go @@ -0,0 +1,120 @@ +package keeper_test + +import ( + "encoding/binary" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/LumeraProtocol/lumera/x/audit/v1/keeper" + "github.com/LumeraProtocol/lumera/x/audit/v1/types" + sntypes "github.com/LumeraProtocol/lumera/x/supernode/v1/types" +) + +// TestGetNextHealOpID_PanicsOnMalformedState verifies NEW-B-7 sibling-symmetry +// with GetNextEvidenceID — malformed counter bytes panic instead of silently +// returning a corrupt value. +func TestGetNextHealOpID_PanicsOnMalformedState(t *testing.T) { + t.Run("malformed length", func(t *testing.T) { + f := initFixture(t) + // Write 7 bytes (not 8) to the next-id counter key. + keeper.WriteRawNextHealOpIDForTest(f.keeper, f.ctx, []byte{0, 0, 0, 0, 0, 0, 1}) + require.PanicsWithError(t, + "audit: malformed next heal-op id (len=7, want 8)", + func() { _ = f.keeper.GetNextHealOpID(f.ctx) }) + }) + + t.Run("zero id sentinel collision", func(t *testing.T) { + f := initFixture(t) + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, 0) + keeper.WriteRawNextHealOpIDForTest(f.keeper, f.ctx, bz) + require.PanicsWithError(t, + "audit: invalid next heal-op id (id=0 collides with not-found sentinel)", + func() { _ = f.keeper.GetNextHealOpID(f.ctx) }) + }) + + t.Run("valid id works", func(t *testing.T) { + f := initFixture(t) + f.keeper.SetNextHealOpID(f.ctx, 42) + require.Equal(t, uint64(42), f.keeper.GetNextHealOpID(f.ctx)) + }) +} + +// TestHealVerifierCountParam_FallbackToDefault verifies NEW-B-3 — the new +// StorageTruthHealVerifierCount param defaults to 2 when unset and is +// honored when configured. +func TestHealVerifierCountParam_FallbackToDefault(t *testing.T) { + defaults := types.DefaultParams() + require.Equal(t, types.DefaultStorageTruthHealVerifierCount, defaults.StorageTruthHealVerifierCount, + "DefaultParams must seed the heal-verifier count param") + require.Equal(t, uint32(2), defaults.StorageTruthHealVerifierCount, + "default value must be 2 (sibling-symmetry with previous hardcode)") + + // WithDefaults should fill in 0 → default. + zeroed := types.Params{StorageTruthHealVerifierCount: 0} + withDefaults := zeroed.WithDefaults() + require.Equal(t, types.DefaultStorageTruthHealVerifierCount, withDefaults.StorageTruthHealVerifierCount) +} + +// TestInitGenesis_RejectsPostponementWithoutSupernodeState verifies NEW-B-6/B-9 +// — audit InitGenesis cross-validates StorageTruthPostponements against +// supernode SuperNodeStatePostponed and rejects mismatched state. +func TestInitGenesis_RejectsPostponementWithoutSupernodeState(t *testing.T) { + t.Run("supernode not found", func(t *testing.T) { + f := initFixture(t) + acct := "lumera1cccccccccccccccccccccccccccccccccccccdpac9" + f.supernodeKeeper.EXPECT(). + GetSuperNodeByAccount(gomock.Any(), acct). + Return(sntypes.SuperNode{}, false, nil).Times(1) + + genesis := types.GenesisState{ + Params: types.DefaultParams(), + StorageTruthPostponements: []types.StorageTruthPostponement{ + {SupernodeAccount: acct, PostponedAtEpochId: 5}, + }, + } + err := f.keeper.InitGenesis(f.ctx, genesis) + require.Error(t, err) + require.Contains(t, err.Error(), "unknown supernode") + }) + + t.Run("supernode not in postponed state", func(t *testing.T) { + f := initFixture(t) + acct := "lumera1ddddddddddddddddddddddddddddddddddddqsxnvc" + // Supernode exists but its latest state record is Active, not Postponed. + sn := sntypes.SuperNode{ + SupernodeAccount: acct, + States: []*sntypes.SuperNodeStateRecord{{State: sntypes.SuperNodeStateActive, Height: 1}}, + } + f.supernodeKeeper.EXPECT(). + GetSuperNodeByAccount(gomock.Any(), acct). + Return(sn, true, nil).Times(1) + + genesis := types.GenesisState{ + Params: types.DefaultParams(), + StorageTruthPostponements: []types.StorageTruthPostponement{ + {SupernodeAccount: acct, PostponedAtEpochId: 5}, + }, + } + err := f.keeper.InitGenesis(f.ctx, genesis) + require.Error(t, err) + require.Contains(t, err.Error(), "lacks corresponding supernode-postponed state") + }) +} + +// TestEventTypeHealOpInsufficientVerifiersExists verifies NEW-B-4 — sibling +// event constant is registered with the same prefix shape as InsufficientHealers. +func TestEventTypeHealOpInsufficientVerifiersExists(t *testing.T) { + require.NotEmpty(t, types.EventTypeHealOpInsufficientVerifiers, + "NEW-B-4: heal-op insufficient-verifiers event type must be registered") + // Sanity: distinct from healers event type. + require.NotEqual(t, types.EventTypeHealOpInsufficientHealers, + types.EventTypeHealOpInsufficientVerifiers, + "event types for healers vs verifiers must be distinct") +} + +// silence unused import if sdk above isn't otherwise referenced +var _ = sdk.NewEventManager diff --git a/x/audit/v1/keeper/storage_truth_postponement_state.go b/x/audit/v1/keeper/storage_truth_postponement_state.go index 29d5a2d8..4c131fdd 100644 --- a/x/audit/v1/keeper/storage_truth_postponement_state.go +++ b/x/audit/v1/keeper/storage_truth_postponement_state.go @@ -28,6 +28,22 @@ func (k Keeper) setStorageTruthPostponedAtEpochID(ctx sdk.Context, supernodeAcco func (k Keeper) clearStorageTruthPostponedAtEpochID(ctx sdk.Context, supernodeAccount string) { store := k.kvStore(ctx) store.Delete(types.StorageTruthPostponementKey(supernodeAccount)) + store.Delete(types.StorageTruthPostponementStrongKey(supernodeAccount)) +} + +// hasStorageTruthStrongPostponeMarker reports whether the postponement record +// at supernodeAccount was created from the strong-suspicion band. +// Per F121-F12 — distinguishes recovery requirements between bands. +func (k Keeper) hasStorageTruthStrongPostponeMarker(ctx sdk.Context, supernodeAccount string) bool { + store := k.kvStore(ctx) + return store.Has(types.StorageTruthPostponementStrongKey(supernodeAccount)) +} + +// setStorageTruthStrongPostponeMarker records that the postponement was triggered +// by the strong-suspicion band. Recovery uses StrongRecoveryCleanPassCount param. +func (k Keeper) setStorageTruthStrongPostponeMarker(ctx sdk.Context, supernodeAccount string) { + store := k.kvStore(ctx) + store.Set(types.StorageTruthPostponementStrongKey(supernodeAccount), []byte{1}) } // GetAllStorageTruthPostponements returns all active postponement markers. diff --git a/x/audit/v1/keeper/storage_truth_recheck_state.go b/x/audit/v1/keeper/storage_truth_recheck_state.go index 38161647..6f058212 100644 --- a/x/audit/v1/keeper/storage_truth_recheck_state.go +++ b/x/audit/v1/keeper/storage_truth_recheck_state.go @@ -1,6 +1,9 @@ package keeper import ( + "encoding/binary" + + storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/LumeraProtocol/lumera/x/audit/v1/types" @@ -19,3 +22,44 @@ func (k Keeper) SetRecheckEvidence(ctx sdk.Context, epochID uint64, ticketID str store := k.kvStore(ctx) store.Set(types.RecheckEvidenceKey(epochID, ticketID, creatorAccount), []byte{1}) } + +// GetAllRecheckEvidenceForGenesis iterates the st/rce/ prefix and returns all +// recheck-evidence dedup entries for genesis export. Per NEW-C-1. +func (k Keeper) GetAllRecheckEvidenceForGenesis(ctx sdk.Context) []types.GenesisRecheckEvidence { + prefix := types.RecheckEvidencePrefix() + store := k.kvStore(ctx) + it := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer it.Close() + + out := make([]types.GenesisRecheckEvidence, 0) + for ; it.Valid(); it.Next() { + key := it.Key() + // Layout: prefix + u64be(epoch) + '/' + ticket_id + 0x00 + creator + body := key[len(prefix):] + if len(body) < 8+1 { + continue + } + epochID := binary.BigEndian.Uint64(body[:8]) + // body[8] is '/' + rest := body[9:] + // find 0x00 separator between ticket and creator + var sep = -1 + for i := 0; i < len(rest); i++ { + if rest[i] == 0 { + sep = i + break + } + } + if sep < 0 { + continue + } + ticketID := string(rest[:sep]) + creator := string(rest[sep+1:]) + out = append(out, types.GenesisRecheckEvidence{ + EpochId: epochID, + TicketId: ticketID, + CreatorAccount: creator, + }) + } + return out +} diff --git a/x/audit/v1/keeper/storage_truth_scoring.go b/x/audit/v1/keeper/storage_truth_scoring.go index 276fe2bb..0bcdb292 100644 --- a/x/audit/v1/keeper/storage_truth_scoring.go +++ b/x/audit/v1/keeper/storage_truth_scoring.go @@ -68,9 +68,10 @@ func (k Keeper) applyStorageTruthScores( } deltas.reporterReliability = addInt64Saturated(deltas.reporterReliability, bookkeeping.currentReporterPenalty) - deltas.nodeSuspicion = addInt64Saturated(deltas.nodeSuspicion, bookkeeping.nodeBonus) - deltas.ticketDeterioration = addInt64Saturated(deltas.ticketDeterioration, bookkeeping.ticketBonus) - // Trust scaling applies to provisional failure impact only. + // Per CP-NEW-A-14/A-15 — trust multiplier scales ONLY the base + // Class-A failure delta. Pattern-escalation bonuses (nodeBonus, + // ticketBonus) are spec-§14/§16 deterrents added unscaled, so a + // degraded reporter cannot under-attribute them. if bookkeeping.applyTrustScaling { if deltas.nodeSuspicion > 0 { deltas.nodeSuspicion = scaleInt64TowardZero(deltas.nodeSuspicion, bookkeeping.reporterTrustMultiplier, 100) @@ -79,6 +80,8 @@ func (k Keeper) applyStorageTruthScores( deltas.ticketDeterioration = scaleInt64TowardZero(deltas.ticketDeterioration, bookkeeping.reporterTrustMultiplier, 100) } } + deltas.nodeSuspicion = addInt64Saturated(deltas.nodeSuspicion, bookkeeping.nodeBonus) + deltas.ticketDeterioration = addInt64Saturated(deltas.ticketDeterioration, bookkeeping.ticketBonus) // Clamp positive (failure) node and ticket deltas to >= 0 after scaling. if deltas.nodeSuspicion < 0 { @@ -141,6 +144,7 @@ func (k Keeper) applyStorageTruthScores( result.TicketId, deltas.ticketDeterioration, params.StorageTruthTicketDeteriorationDecayPerEpoch, + bookkeeping.contradictionDetected, ) if err != nil { return err @@ -252,8 +256,10 @@ func (k Keeper) updateNodeSuspicionHistoryFields(state *types.NodeSuspicionState state.LastIndexFailEpoch = epochID } - // Reset window if stale. - if epochID-state.WindowStartEpoch >= window { + // Reset window if stale. Use epochDelta to avoid uint64 underflow when + // WindowStartEpoch > epochID (e.g. genesis-imported future-pointing field). + // Per NEW-A-12 / NEW-A-17. + if epochDelta(epochID, state.WindowStartEpoch) >= window { state.WindowStartEpoch = epochID state.DistinctTicketFailWindow = 0 state.ClassACountWindow = 0 @@ -329,7 +335,7 @@ func (k Keeper) applyReporterReliabilityDelta( if divergenceWindow == 0 { divergenceWindow = 14 } - if epochID-state.WindowStartEpoch >= divergenceWindow { + if epochDelta(epochID, state.WindowStartEpoch) >= divergenceWindow { nextState.WindowStartEpoch = epochID nextState.WindowPositiveCount = 0 nextState.WindowNegativeCount = 0 @@ -358,6 +364,7 @@ func (k Keeper) applyTicketDeteriorationDelta( ticketID string, delta int64, decayPerEpoch int64, + contradictionConfirmed bool, ) (types.TicketDeteriorationState, bool, error) { if ticketID == "" { return types.TicketDeteriorationState{}, false, nil @@ -372,6 +379,19 @@ func (k Keeper) applyTicketDeteriorationDelta( current = decayTowardZero(state.DeteriorationScore, decayPerEpoch, epochDelta(epochID, state.LastUpdatedEpoch)) } next := addInt64Saturated(current, delta) + // Per F119-F3 residue — clean-pass-by-different-holder bonus (spec §15.4). + // When PASS lands on a ticket whose prior failure was from a DIFFERENT + // holder, apply an additional -3 ticket-deterioration delta on top of the + // base bucket reduction. This rewards a successful recovery on a fresh + // holder distinctly from a clean-pass on the same holder. + if result != nil && + result.ResultClass == types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS && + found && + state.LastTargetSupernodeAccount != "" && + state.LastTargetSupernodeAccount != result.TargetSupernodeAccount && + isStorageTruthFailureClass(state.LastResultClass) { + next = addInt64Saturated(next, -3) + } // Clamp ticket deterioration at >= 0. if next < 0 { next = 0 @@ -415,7 +435,11 @@ func (k Keeper) applyTicketDeteriorationDelta( nextState.LastResultClass = result.ResultClass nextState.LastResultEpoch = epochID // Per Zee 119-F7 — same-epoch contradictions must be counted; <= not <. - if state.LastResultEpoch <= epochID && + // Per F121-F10 / F119-F3 — only count ticket-side contradictions when the + // reporter-side confirmation predicate held (PASS-after-fail with no + // independent reporter PASS in window AND no clean recheck transcript). + if contradictionConfirmed && + state.LastResultEpoch <= epochID && state.LastTargetSupernodeAccount == result.TargetSupernodeAccount && storageTruthResultsContradict(state.LastResultClass, result.ResultClass) { nextState.ContradictionCount = state.ContradictionCount + 1 @@ -436,24 +460,29 @@ func storageTruthScoreDeltasForResult(result *types.StorageProofResult) storageT } switch result.ResultClass { case types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS: - // PASS deltas are REDUCTIONS (negative). Reporter delta is -4 (recovery in positive-penalty model). + // PASS deltas are REDUCTIONS (negative). Per CP-NEW-A-18, reporter + // reliability recovery is per-EPOCH not per-result; emission moved to + // ApplyReporterCleanEpochRecoveryAtEpochEnd. Per-result reporter delta = 0. + // F119-F3 residue: cross-holder PASS bonus is applied in + // applyTicketDeteriorationDelta (where the prior-holder state is in + // scope), not at this per-result delta level. switch result.BucketType { case types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT: return storageTruthScoreDeltas{ nodeSuspicion: -3, - reporterReliability: -4, + reporterReliability: 0, ticketDeterioration: -2, } case types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_OLD: return storageTruthScoreDeltas{ nodeSuspicion: -2, - reporterReliability: -4, + reporterReliability: 0, ticketDeterioration: -3, } default: return storageTruthScoreDeltas{ nodeSuspicion: -2, - reporterReliability: -4, + reporterReliability: 0, ticketDeterioration: -2, } } @@ -474,9 +503,10 @@ func storageTruthScoreDeltasForResult(result *types.StorageProofResult) storageT } } case types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_TIMEOUT_OR_NO_RESPONSE: + // Per CP-NEW-A-18 — TIMEOUT reporter delta moved off per-result. return storageTruthScoreDeltas{ nodeSuspicion: 7, - reporterReliability: -1, + reporterReliability: 0, ticketDeterioration: 3, } case types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_OBSERVER_QUORUM_FAIL: @@ -536,7 +566,15 @@ func (k Keeper) storageTruthBookkeepingForResult( } bookkeeping.reporterTrustBand = reporterTrustBandForScore(reliabilityScore, params) bookkeeping.reporterTrustMultiplier = reporterTrustMultiplierNumerator(reliabilityScore) - bookkeeping.applyTrustScaling = isStorageTruthFailureClass(result.ResultClass) && + // Per CP-NEW-A-14 / spec §15.4 — trust multiplier applies to Class A + // failures only (HASH_MISMATCH or INDEX-class). Class B/C failures + // (TIMEOUT, OBSERVER_QUORUM_FAIL, INVALID_TRANSCRIPT, etc.) emit + // non-scaled deltas. Re-confirmed (RECHECK_CONFIRMED_FAIL) and + // recheck-bucket results bypass scaling regardless of class. + isClassA := result.ResultClass == types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_HASH_MISMATCH || + result.ArtifactClass == types.StorageProofArtifactClass_STORAGE_PROOF_ARTIFACT_CLASS_INDEX + bookkeeping.applyTrustScaling = isClassA && + isStorageTruthFailureClass(result.ResultClass) && result.ResultClass != types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_RECHECK_CONFIRMED_FAIL && result.BucketType != types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECHECK diff --git a/x/audit/v1/keeper/storage_truth_scoring_future_window_test.go b/x/audit/v1/keeper/storage_truth_scoring_future_window_test.go new file mode 100644 index 00000000..89f938dc --- /dev/null +++ b/x/audit/v1/keeper/storage_truth_scoring_future_window_test.go @@ -0,0 +1,37 @@ +package keeper + +import ( + "testing" + + "github.com/LumeraProtocol/lumera/x/audit/v1/types" + "github.com/stretchr/testify/require" +) + +// TestUpdateNodeSuspicionHistory_FutureWindowStartIsSafe verifies NEW-A-12/NEW-A-17: +// If a NodeSuspicionState arrives (e.g. from a malformed genesis that bypassed +// validation, or a future-pointing field) with WindowStartEpoch > epochID, +// the window-reset path must use saturated subtraction (epochDelta) and not +// panic via uint64 underflow. +func TestUpdateNodeSuspicionHistory_FutureWindowStartIsSafe(t *testing.T) { + var k Keeper + params := types.DefaultParams().WithDefaults() + state := types.NodeSuspicionState{ + SupernodeAccount: "lumera1aaaa", + WindowStartEpoch: 100, // future relative to currentEpoch=5 + } + result := &types.StorageProofResult{ + ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_HASH_MISMATCH, + ArtifactClass: types.StorageProofArtifactClass_STORAGE_PROOF_ARTIFACT_CLASS_INDEX, + BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, + } + + require.NotPanics(t, func() { + k.updateNodeSuspicionHistoryFields(&state, result, 5, params) + }) + + // epochDelta saturates to 0 when WindowStartEpoch > epochID, so the + // stale-window reset is NOT triggered (delta 0 < window). The state + // must remain valid (no panic, score field still bumps in-window). + require.Equal(t, uint64(100), state.WindowStartEpoch) + require.GreaterOrEqual(t, state.DistinctTicketFailWindow, uint32(1)) +} diff --git a/x/audit/v1/keeper/storage_truth_scoring_internal_test.go b/x/audit/v1/keeper/storage_truth_scoring_internal_test.go index f37b19d9..eabd5a31 100644 --- a/x/audit/v1/keeper/storage_truth_scoring_internal_test.go +++ b/x/audit/v1/keeper/storage_truth_scoring_internal_test.go @@ -20,9 +20,10 @@ func TestStorageTruthScoreDeltasForResult(t *testing.T) { ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECENT, }, + // Per NEW-A-18 — emission moved to end-of-epoch (-4 once on >=5 PASS, no overturned-fail). expect: storageTruthScoreDeltas{ nodeSuspicion: -3, - reporterReliability: -4, + reporterReliability: 0, ticketDeterioration: -2, }, }, @@ -32,9 +33,10 @@ func TestStorageTruthScoreDeltasForResult(t *testing.T) { ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_OLD, }, + // Per NEW-A-18 — emission moved to end-of-epoch (-4 once on >=5 PASS, no overturned-fail). expect: storageTruthScoreDeltas{ nodeSuspicion: -2, - reporterReliability: -4, + reporterReliability: 0, ticketDeterioration: -3, }, }, @@ -44,9 +46,10 @@ func TestStorageTruthScoreDeltasForResult(t *testing.T) { ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_PASS, BucketType: types.StorageProofBucketType_STORAGE_PROOF_BUCKET_TYPE_RECHECK, }, + // Per NEW-A-18 — emission moved to end-of-epoch (-4 once on >=5 PASS, no overturned-fail). expect: storageTruthScoreDeltas{ nodeSuspicion: -2, - reporterReliability: -4, + reporterReliability: 0, ticketDeterioration: -2, }, }, @@ -91,9 +94,11 @@ func TestStorageTruthScoreDeltasForResult(t *testing.T) { result: &types.StorageProofResult{ ResultClass: types.StorageProofResultClass_STORAGE_PROOF_RESULT_CLASS_TIMEOUT_OR_NO_RESPONSE, }, + // Per NEW-A-18 — TIMEOUT no longer emits per-result reporter delta; + // reporter recovery is end-of-epoch only (-4 on >=5 clean PASS). expect: storageTruthScoreDeltas{ nodeSuspicion: 7, - reporterReliability: -1, + reporterReliability: 0, ticketDeterioration: 3, }, }, diff --git a/x/audit/v1/keeper/storage_truth_state.go b/x/audit/v1/keeper/storage_truth_state.go index eda31675..a4d6d8bd 100644 --- a/x/audit/v1/keeper/storage_truth_state.go +++ b/x/audit/v1/keeper/storage_truth_state.go @@ -2,6 +2,7 @@ package keeper import ( "encoding/binary" + "fmt" storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -175,7 +176,18 @@ func (k Keeper) GetNextHealOpID(ctx sdk.Context) uint64 { if bz == nil { return 1 } - return binary.BigEndian.Uint64(bz) + // Per NEW-B-7 — sibling-symmetry with GetNextEvidenceID: panic on malformed + // counter rather than silently returning a corrupt value (heal-op IDs gate + // SetHealOp/GetHealOp; collisions cause structural confusion downstream). + if len(bz) != 8 { + panic(fmt.Errorf("audit: malformed next heal-op id (len=%d, want 8)", len(bz))) + } + id := binary.BigEndian.Uint64(bz) + if id == 0 { + // Heal-op IDs start at 1; treat 0 as sentinel collision with "not found". + panic(fmt.Errorf("audit: invalid next heal-op id (id=0 collides with not-found sentinel)")) + } + return id } func (k Keeper) SetNextHealOpID(ctx sdk.Context, id uint64) { diff --git a/x/audit/v1/types/events.go b/x/audit/v1/types/events.go index 5cef2322..8f524f2f 100644 --- a/x/audit/v1/types/events.go +++ b/x/audit/v1/types/events.go @@ -18,7 +18,8 @@ const ( // Per 122-F2 — legacy 0-count tickets fall back to cascadeMeta length to avoid finalization brick. EventTypeArtifactCountUnanchored = "storage_truth_artifact_count_unanchored" // Per 121-F11 — heal scheduler cannot find sufficient eligible healers. - EventTypeHealOpInsufficientHealers = "storage_truth_heal_op_insufficient_healers" + EventTypeHealOpInsufficientHealers = "storage_truth_heal_op_insufficient_healers" + EventTypeHealOpInsufficientVerifiers = "storage_truth_heal_op_insufficient_verifiers" AttributeKeyEpochID = "epoch_id" AttributeKeyReporterSupernodeAccount = "reporter_supernode_account" diff --git a/x/audit/v1/types/genesis.pb.go b/x/audit/v1/types/genesis.pb.go index 8eebee46..b3034be4 100644 --- a/x/audit/v1/types/genesis.pb.go +++ b/x/audit/v1/types/genesis.pb.go @@ -41,6 +41,16 @@ type GenesisState struct { // storage_truth_postponements records active per-supernode postponement markers // exported/imported at genesis. Per 121-F7. StorageTruthPostponements []StorageTruthPostponement `protobuf:"bytes,10,rep,name=storage_truth_postponements,json=storageTruthPostponements,proto3" json:"storage_truth_postponements"` + // Per NEW-C-1: round-trip every epoch-scoped audit prefix. + RecheckEvidence []GenesisRecheckEvidence `protobuf:"bytes,11,rep,name=recheck_evidence,json=recheckEvidence,proto3" json:"recheck_evidence"` + StorageProofTranscripts []GenesisStorageProofTranscript `protobuf:"bytes,12,rep,name=storage_proof_transcripts,json=storageProofTranscripts,proto3" json:"storage_proof_transcripts"` + NodeFailureFacts []GenesisNodeFailureFact `protobuf:"bytes,13,rep,name=node_failure_facts,json=nodeFailureFacts,proto3" json:"node_failure_facts"` + ReporterResultFacts []GenesisReporterResultFact `protobuf:"bytes,14,rep,name=reporter_result_facts,json=reporterResultFacts,proto3" json:"reporter_result_facts"` + FailedHealMarkers []GenesisFailedHealMarker `protobuf:"bytes,15,rep,name=failed_heal_markers,json=failedHealMarkers,proto3" json:"failed_heal_markers"` + EpochReports []EpochReport `protobuf:"bytes,16,rep,name=epoch_reports,json=epochReports,proto3" json:"epoch_reports"` + ReportIndices []GenesisReportIndex `protobuf:"bytes,17,rep,name=report_indices,json=reportIndices,proto3" json:"report_indices"` + HostReportIndices []GenesisHostReportIndex `protobuf:"bytes,18,rep,name=host_report_indices,json=hostReportIndices,proto3" json:"host_report_indices"` + StorageChallengeIndices []GenesisStorageChallengeIndex `protobuf:"bytes,19,rep,name=storage_challenge_indices,json=storageChallengeIndices,proto3" json:"storage_challenge_indices"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -146,6 +156,69 @@ func (m *GenesisState) GetStorageTruthPostponements() []StorageTruthPostponement return nil } +func (m *GenesisState) GetRecheckEvidence() []GenesisRecheckEvidence { + if m != nil { + return m.RecheckEvidence + } + return nil +} + +func (m *GenesisState) GetStorageProofTranscripts() []GenesisStorageProofTranscript { + if m != nil { + return m.StorageProofTranscripts + } + return nil +} + +func (m *GenesisState) GetNodeFailureFacts() []GenesisNodeFailureFact { + if m != nil { + return m.NodeFailureFacts + } + return nil +} + +func (m *GenesisState) GetReporterResultFacts() []GenesisReporterResultFact { + if m != nil { + return m.ReporterResultFacts + } + return nil +} + +func (m *GenesisState) GetFailedHealMarkers() []GenesisFailedHealMarker { + if m != nil { + return m.FailedHealMarkers + } + return nil +} + +func (m *GenesisState) GetEpochReports() []EpochReport { + if m != nil { + return m.EpochReports + } + return nil +} + +func (m *GenesisState) GetReportIndices() []GenesisReportIndex { + if m != nil { + return m.ReportIndices + } + return nil +} + +func (m *GenesisState) GetHostReportIndices() []GenesisHostReportIndex { + if m != nil { + return m.HostReportIndices + } + return nil +} + +func (m *GenesisState) GetStorageChallengeIndices() []GenesisStorageChallengeIndex { + if m != nil { + return m.StorageChallengeIndices + } + return nil +} + // StorageTruthPostponement records a supernode's storage-truth postponement state // for genesis export/import. Per 121-F7. type StorageTruthPostponement struct { @@ -200,321 +273,2772 @@ func (m *StorageTruthPostponement) GetPostponedAtEpochId() uint64 { return 0 } -func init() { - proto.RegisterType((*GenesisState)(nil), "lumera.audit.v1.GenesisState") - proto.RegisterType((*StorageTruthPostponement)(nil), "lumera.audit.v1.StorageTruthPostponement") +// GenesisRecheckEvidence — st/rce/ replay-protection key. +type GenesisRecheckEvidence struct { + EpochId uint64 `protobuf:"varint,1,opt,name=epoch_id,json=epochId,proto3" json:"epoch_id,omitempty"` + TicketId string `protobuf:"bytes,2,opt,name=ticket_id,json=ticketId,proto3" json:"ticket_id,omitempty"` + CreatorAccount string `protobuf:"bytes,3,opt,name=creator_account,json=creatorAccount,proto3" json:"creator_account,omitempty"` } -func init() { proto.RegisterFile("lumera/audit/v1/genesis.proto", fileDescriptor_a433cb4f206fdbad) } - -var fileDescriptor_a433cb4f206fdbad = []byte{ - // 560 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0x4f, 0x6f, 0xd3, 0x30, - 0x18, 0xc6, 0x9b, 0x6d, 0x74, 0x9b, 0x37, 0xb1, 0xcd, 0x30, 0x91, 0xfd, 0x21, 0x4c, 0x43, 0x48, - 0x65, 0x48, 0xad, 0x3a, 0x2e, 0x08, 0x4e, 0x2d, 0x4c, 0xd0, 0x0b, 0x4c, 0xe9, 0x4e, 0x48, 0xc8, - 0xf2, 0x92, 0x97, 0xd6, 0xa2, 0x8d, 0x2d, 0xfb, 0x4d, 0xb5, 0xf1, 0x29, 0xf8, 0x18, 0x1c, 0x39, - 0xf1, 0x19, 0x76, 0xdc, 0x91, 0x13, 0x42, 0xed, 0x81, 0xaf, 0x81, 0xe2, 0x24, 0x5d, 0x69, 0x08, - 0x97, 0xca, 0x7d, 0x1f, 0xff, 0xde, 0xe7, 0x7d, 0xec, 0x98, 0xdc, 0x1f, 0xc4, 0x43, 0xd0, 0xbc, - 0xc1, 0xe3, 0x50, 0x60, 0x63, 0xd4, 0x6c, 0xf4, 0x20, 0x02, 0x23, 0x4c, 0x5d, 0x69, 0x89, 0x92, - 0x6e, 0xa4, 0x72, 0xdd, 0xca, 0xf5, 0x51, 0x73, 0x77, 0x8b, 0x0f, 0x45, 0x24, 0x1b, 0xf6, 0x37, - 0xdd, 0xb3, 0x7b, 0xb7, 0x27, 0x7b, 0xd2, 0x2e, 0x1b, 0xc9, 0x2a, 0xab, 0xee, 0xcf, 0x37, 0x56, - 0x5c, 0xf3, 0x61, 0xd6, 0x77, 0xd7, 0x9b, 0x57, 0x61, 0x24, 0x42, 0x88, 0x02, 0xc8, 0xf4, 0xbd, - 0x79, 0x3d, 0x1d, 0xc0, 0x8a, 0x87, 0xdf, 0xab, 0x64, 0xfd, 0x75, 0x3a, 0x66, 0x17, 0x39, 0x02, - 0x7d, 0x4e, 0xaa, 0x69, 0x77, 0xd7, 0x39, 0x70, 0x6a, 0x6b, 0xc7, 0xf7, 0xea, 0x73, 0x63, 0xd7, - 0x4f, 0xad, 0xdc, 0x5e, 0xbd, 0xfa, 0xf9, 0xa0, 0xf2, 0xf5, 0xf7, 0xb7, 0x23, 0xc7, 0xcf, 0x08, - 0xfa, 0x82, 0xac, 0xe4, 0xde, 0xee, 0xc2, 0xc1, 0x62, 0x6d, 0xed, 0x78, 0xa7, 0x40, 0x9f, 0x64, - 0x1b, 0xda, 0x4b, 0x09, 0xef, 0x4f, 0x01, 0x5a, 0x23, 0x9b, 0x11, 0x5c, 0x20, 0xcb, 0x0b, 0x4c, - 0x84, 0xee, 0xe2, 0x81, 0x53, 0x5b, 0xf2, 0x6f, 0x27, 0xf5, 0x9c, 0xeb, 0x84, 0xf4, 0x03, 0xd9, - 0x8e, 0x64, 0x08, 0xcc, 0xc4, 0x46, 0x89, 0x40, 0xc8, 0x88, 0x99, 0x64, 0x74, 0xe3, 0x2e, 0x59, - 0xcf, 0x87, 0x05, 0xcf, 0xb7, 0x32, 0x84, 0x6e, 0xbe, 0xd9, 0xc6, 0xcc, 0xdc, 0xef, 0x44, 0x05, - 0xc5, 0x50, 0x49, 0xf6, 0x34, 0x28, 0xa9, 0x11, 0x34, 0xd3, 0x30, 0x10, 0xfc, 0x5c, 0x0c, 0x04, - 0x5e, 0xe6, 0x26, 0xb7, 0xac, 0xc9, 0xe3, 0x82, 0x89, 0x9f, 0x31, 0xfe, 0x0d, 0x32, 0x6b, 0xb5, - 0xa3, 0x4b, 0x74, 0x6b, 0x88, 0x22, 0xf8, 0x04, 0xc8, 0x42, 0x40, 0xd0, 0x42, 0x6a, 0x8e, 0x33, - 0xa9, 0xaa, 0x25, 0x86, 0x67, 0x96, 0x79, 0x35, 0x8b, 0xfc, 0x65, 0x88, 0x25, 0xba, 0xa1, 0xcf, - 0xc8, 0x4a, 0x1f, 0xf8, 0x80, 0x49, 0x65, 0xdc, 0x65, 0xdb, 0xbd, 0x78, 0xcb, 0x6f, 0x80, 0x0f, - 0xde, 0xa9, 0xac, 0xd7, 0x72, 0xdf, 0xfe, 0x33, 0xf4, 0x11, 0xd9, 0xb0, 0x97, 0x94, 0xe1, 0xc9, - 0x1d, 0xad, 0xd8, 0x3b, 0x5a, 0x4f, 0xca, 0x29, 0xd3, 0x09, 0xa9, 0x22, 0xfb, 0x59, 0x22, 0xae, - 0x51, 0x7c, 0xe4, 0x01, 0xb2, 0x40, 0xc6, 0x11, 0xe6, 0x91, 0x56, 0xff, 0x1b, 0xa9, 0x95, 0x31, - 0x2f, 0x13, 0xe4, 0x1f, 0x91, 0x8a, 0xba, 0x3d, 0x43, 0x83, 0x52, 0xf3, 0x1e, 0x30, 0xd4, 0x31, - 0xf6, 0x99, 0x92, 0x06, 0x95, 0x8c, 0x60, 0x08, 0x11, 0x1a, 0x97, 0x94, 0x18, 0x76, 0x53, 0xe6, - 0x2c, 0x41, 0x4e, 0x67, 0x88, 0xdc, 0xd0, 0x94, 0xe8, 0xe6, 0xf0, 0x33, 0x71, 0xcb, 0x60, 0xfa, - 0x84, 0x6c, 0x99, 0x58, 0x81, 0xb6, 0x5f, 0x29, 0x0f, 0x6c, 0x74, 0xfb, 0x9c, 0x56, 0xfd, 0xcd, - 0xa9, 0xd0, 0x4a, 0xeb, 0xb4, 0x49, 0xb6, 0xf3, 0x59, 0x43, 0xc6, 0x91, 0x81, 0x92, 0x41, 0x3f, - 0x39, 0xd8, 0x05, 0x7b, 0xb0, 0x74, 0x2a, 0xb6, 0xf0, 0x24, 0x91, 0x3a, 0x61, 0xfb, 0xe8, 0x6a, - 0xec, 0x39, 0xd7, 0x63, 0xcf, 0xf9, 0x35, 0xf6, 0x9c, 0x2f, 0x13, 0xaf, 0x72, 0x3d, 0xf1, 0x2a, - 0x3f, 0x26, 0x5e, 0xe5, 0xfd, 0xe6, 0xc5, 0xcd, 0x33, 0xc7, 0x4b, 0x05, 0xe6, 0xbc, 0x6a, 0xdf, - 0xf9, 0xd3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x95, 0xa5, 0xb4, 0xed, 0x9d, 0x04, 0x00, 0x00, +func (m *GenesisRecheckEvidence) Reset() { *m = GenesisRecheckEvidence{} } +func (m *GenesisRecheckEvidence) String() string { return proto.CompactTextString(m) } +func (*GenesisRecheckEvidence) ProtoMessage() {} +func (*GenesisRecheckEvidence) Descriptor() ([]byte, []int) { + return fileDescriptor_a433cb4f206fdbad, []int{2} } - -func (m *GenesisState) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +func (m *GenesisRecheckEvidence) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisRecheckEvidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisRecheckEvidence.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return dAtA[:n], nil } - -func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (m *GenesisRecheckEvidence) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisRecheckEvidence.Merge(m, src) +} +func (m *GenesisRecheckEvidence) XXX_Size() int { + return m.Size() +} +func (m *GenesisRecheckEvidence) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisRecheckEvidence.DiscardUnknown(m) } -func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.StorageTruthPostponements) > 0 { - for iNdEx := len(m.StorageTruthPostponements) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.StorageTruthPostponements[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x52 - } - } - if len(m.TicketArtifactCountStates) > 0 { - for iNdEx := len(m.TicketArtifactCountStates) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.TicketArtifactCountStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x4a - } - } - if m.NextHealOpId != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.NextHealOpId)) - i-- - dAtA[i] = 0x40 - } - if len(m.HealOps) > 0 { - for iNdEx := len(m.HealOps) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.HealOps[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x3a - } - } - if len(m.TicketDeteriorationStates) > 0 { - for iNdEx := len(m.TicketDeteriorationStates) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.TicketDeteriorationStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - } - } - if len(m.ReporterReliabilityStates) > 0 { - for iNdEx := len(m.ReporterReliabilityStates) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.ReporterReliabilityStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } - } - if len(m.NodeSuspicionStates) > 0 { - for iNdEx := len(m.NodeSuspicionStates) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.NodeSuspicionStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } +var xxx_messageInfo_GenesisRecheckEvidence proto.InternalMessageInfo + +func (m *GenesisRecheckEvidence) GetEpochId() uint64 { + if m != nil { + return m.EpochId } - if m.NextEvidenceId != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.NextEvidenceId)) - i-- - dAtA[i] = 0x18 + return 0 +} + +func (m *GenesisRecheckEvidence) GetTicketId() string { + if m != nil { + return m.TicketId } - if len(m.Evidence) > 0 { - for iNdEx := len(m.Evidence) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Evidence[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } + return "" +} + +func (m *GenesisRecheckEvidence) GetCreatorAccount() string { + if m != nil { + return m.CreatorAccount } - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + return "" +} + +// GenesisStorageProofTranscript — st/spt/ value (JSON-encoded record). +// The opaque record_json blob is the keeper's storageProofTranscriptRecord +// JSON marshaling. InitGenesis re-writes via the existing setter so the +// st/spt-tbe/ secondary index is rebuilt deterministically. +type GenesisStorageProofTranscript struct { + TranscriptHash string `protobuf:"bytes,1,opt,name=transcript_hash,json=transcriptHash,proto3" json:"transcript_hash,omitempty"` + RecordJson []byte `protobuf:"bytes,2,opt,name=record_json,json=recordJson,proto3" json:"record_json,omitempty"` +} + +func (m *GenesisStorageProofTranscript) Reset() { *m = GenesisStorageProofTranscript{} } +func (m *GenesisStorageProofTranscript) String() string { return proto.CompactTextString(m) } +func (*GenesisStorageProofTranscript) ProtoMessage() {} +func (*GenesisStorageProofTranscript) Descriptor() ([]byte, []int) { + return fileDescriptor_a433cb4f206fdbad, []int{3} +} +func (m *GenesisStorageProofTranscript) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisStorageProofTranscript) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisStorageProofTranscript.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) if err != nil { - return 0, err + return nil, err } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) + return b[:n], nil } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil +} +func (m *GenesisStorageProofTranscript) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisStorageProofTranscript.Merge(m, src) +} +func (m *GenesisStorageProofTranscript) XXX_Size() int { + return m.Size() +} +func (m *GenesisStorageProofTranscript) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisStorageProofTranscript.DiscardUnknown(m) } -func (m *StorageTruthPostponement) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +var xxx_messageInfo_GenesisStorageProofTranscript proto.InternalMessageInfo + +func (m *GenesisStorageProofTranscript) GetTranscriptHash() string { + if m != nil { + return m.TranscriptHash } - return dAtA[:n], nil + return "" } -func (m *StorageTruthPostponement) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (m *GenesisStorageProofTranscript) GetRecordJson() []byte { + if m != nil { + return m.RecordJson + } + return nil } -func (m *StorageTruthPostponement) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.PostponedAtEpochId != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.PostponedAtEpochId)) - i-- - dAtA[i] = 0x10 - } - if len(m.SupernodeAccount) > 0 { - i -= len(m.SupernodeAccount) - copy(dAtA[i:], m.SupernodeAccount) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.SupernodeAccount))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil +// GenesisNodeFailureFact — st/nf/ entry (JSON-encoded record). +type GenesisNodeFailureFact struct { + SupernodeAccount string `protobuf:"bytes,1,opt,name=supernode_account,json=supernodeAccount,proto3" json:"supernode_account,omitempty"` + EpochId uint64 `protobuf:"varint,2,opt,name=epoch_id,json=epochId,proto3" json:"epoch_id,omitempty"` + TicketId string `protobuf:"bytes,3,opt,name=ticket_id,json=ticketId,proto3" json:"ticket_id,omitempty"` + ReporterAccount string `protobuf:"bytes,4,opt,name=reporter_account,json=reporterAccount,proto3" json:"reporter_account,omitempty"` + RecordJson []byte `protobuf:"bytes,5,opt,name=record_json,json=recordJson,proto3" json:"record_json,omitempty"` } -func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { - offset -= sovGenesis(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *GenesisNodeFailureFact) Reset() { *m = GenesisNodeFailureFact{} } +func (m *GenesisNodeFailureFact) String() string { return proto.CompactTextString(m) } +func (*GenesisNodeFailureFact) ProtoMessage() {} +func (*GenesisNodeFailureFact) Descriptor() ([]byte, []int) { + return fileDescriptor_a433cb4f206fdbad, []int{4} +} +func (m *GenesisNodeFailureFact) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisNodeFailureFact) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisNodeFailureFact.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - dAtA[offset] = uint8(v) - return base } -func (m *GenesisState) Size() (n int) { - if m == nil { - return 0 +func (m *GenesisNodeFailureFact) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisNodeFailureFact.Merge(m, src) +} +func (m *GenesisNodeFailureFact) XXX_Size() int { + return m.Size() +} +func (m *GenesisNodeFailureFact) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisNodeFailureFact.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisNodeFailureFact proto.InternalMessageInfo + +func (m *GenesisNodeFailureFact) GetSupernodeAccount() string { + if m != nil { + return m.SupernodeAccount } - var l int - _ = l - l = m.Params.Size() - n += 1 + l + sovGenesis(uint64(l)) - if len(m.Evidence) > 0 { - for _, e := range m.Evidence { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } + return "" +} + +func (m *GenesisNodeFailureFact) GetEpochId() uint64 { + if m != nil { + return m.EpochId } - if m.NextEvidenceId != 0 { - n += 1 + sovGenesis(uint64(m.NextEvidenceId)) + return 0 +} + +func (m *GenesisNodeFailureFact) GetTicketId() string { + if m != nil { + return m.TicketId } - if len(m.NodeSuspicionStates) > 0 { - for _, e := range m.NodeSuspicionStates { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) + return "" +} + +func (m *GenesisNodeFailureFact) GetReporterAccount() string { + if m != nil { + return m.ReporterAccount + } + return "" +} + +func (m *GenesisNodeFailureFact) GetRecordJson() []byte { + if m != nil { + return m.RecordJson + } + return nil +} + +// GenesisReporterResultFact — st/rrs/ entry (JSON-encoded record). +// The st/rrs-tt/ secondary index is rebuilt by the existing setter. +type GenesisReporterResultFact struct { + ReporterAccount string `protobuf:"bytes,1,opt,name=reporter_account,json=reporterAccount,proto3" json:"reporter_account,omitempty"` + EpochId uint64 `protobuf:"varint,2,opt,name=epoch_id,json=epochId,proto3" json:"epoch_id,omitempty"` + TicketId string `protobuf:"bytes,3,opt,name=ticket_id,json=ticketId,proto3" json:"ticket_id,omitempty"` + TargetAccount string `protobuf:"bytes,4,opt,name=target_account,json=targetAccount,proto3" json:"target_account,omitempty"` + RecordJson []byte `protobuf:"bytes,5,opt,name=record_json,json=recordJson,proto3" json:"record_json,omitempty"` +} + +func (m *GenesisReporterResultFact) Reset() { *m = GenesisReporterResultFact{} } +func (m *GenesisReporterResultFact) String() string { return proto.CompactTextString(m) } +func (*GenesisReporterResultFact) ProtoMessage() {} +func (*GenesisReporterResultFact) Descriptor() ([]byte, []int) { + return fileDescriptor_a433cb4f206fdbad, []int{5} +} +func (m *GenesisReporterResultFact) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisReporterResultFact) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisReporterResultFact.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err } + return b[:n], nil } - if len(m.ReporterReliabilityStates) > 0 { - for _, e := range m.ReporterReliabilityStates { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) +} +func (m *GenesisReporterResultFact) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisReporterResultFact.Merge(m, src) +} +func (m *GenesisReporterResultFact) XXX_Size() int { + return m.Size() +} +func (m *GenesisReporterResultFact) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisReporterResultFact.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisReporterResultFact proto.InternalMessageInfo + +func (m *GenesisReporterResultFact) GetReporterAccount() string { + if m != nil { + return m.ReporterAccount + } + return "" +} + +func (m *GenesisReporterResultFact) GetEpochId() uint64 { + if m != nil { + return m.EpochId + } + return 0 +} + +func (m *GenesisReporterResultFact) GetTicketId() string { + if m != nil { + return m.TicketId + } + return "" +} + +func (m *GenesisReporterResultFact) GetTargetAccount() string { + if m != nil { + return m.TargetAccount + } + return "" +} + +func (m *GenesisReporterResultFact) GetRecordJson() []byte { + if m != nil { + return m.RecordJson + } + return nil +} + +// GenesisFailedHealMarker — st/fh/ marker. +type GenesisFailedHealMarker struct { + SupernodeAccount string `protobuf:"bytes,1,opt,name=supernode_account,json=supernodeAccount,proto3" json:"supernode_account,omitempty"` + EpochId uint64 `protobuf:"varint,2,opt,name=epoch_id,json=epochId,proto3" json:"epoch_id,omitempty"` + TicketId string `protobuf:"bytes,3,opt,name=ticket_id,json=ticketId,proto3" json:"ticket_id,omitempty"` +} + +func (m *GenesisFailedHealMarker) Reset() { *m = GenesisFailedHealMarker{} } +func (m *GenesisFailedHealMarker) String() string { return proto.CompactTextString(m) } +func (*GenesisFailedHealMarker) ProtoMessage() {} +func (*GenesisFailedHealMarker) Descriptor() ([]byte, []int) { + return fileDescriptor_a433cb4f206fdbad, []int{6} +} +func (m *GenesisFailedHealMarker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisFailedHealMarker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisFailedHealMarker.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err } + return b[:n], nil } - if len(m.TicketDeteriorationStates) > 0 { - for _, e := range m.TicketDeteriorationStates { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) +} +func (m *GenesisFailedHealMarker) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisFailedHealMarker.Merge(m, src) +} +func (m *GenesisFailedHealMarker) XXX_Size() int { + return m.Size() +} +func (m *GenesisFailedHealMarker) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisFailedHealMarker.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisFailedHealMarker proto.InternalMessageInfo + +func (m *GenesisFailedHealMarker) GetSupernodeAccount() string { + if m != nil { + return m.SupernodeAccount + } + return "" +} + +func (m *GenesisFailedHealMarker) GetEpochId() uint64 { + if m != nil { + return m.EpochId + } + return 0 +} + +func (m *GenesisFailedHealMarker) GetTicketId() string { + if m != nil { + return m.TicketId + } + return "" +} + +// GenesisReportIndex — ri/ index entry. +type GenesisReportIndex struct { + ReporterSupernodeAccount string `protobuf:"bytes,1,opt,name=reporter_supernode_account,json=reporterSupernodeAccount,proto3" json:"reporter_supernode_account,omitempty"` + EpochId uint64 `protobuf:"varint,2,opt,name=epoch_id,json=epochId,proto3" json:"epoch_id,omitempty"` +} + +func (m *GenesisReportIndex) Reset() { *m = GenesisReportIndex{} } +func (m *GenesisReportIndex) String() string { return proto.CompactTextString(m) } +func (*GenesisReportIndex) ProtoMessage() {} +func (*GenesisReportIndex) Descriptor() ([]byte, []int) { + return fileDescriptor_a433cb4f206fdbad, []int{7} +} +func (m *GenesisReportIndex) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisReportIndex) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisReportIndex.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err } + return b[:n], nil } - if len(m.HealOps) > 0 { - for _, e := range m.HealOps { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) +} +func (m *GenesisReportIndex) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisReportIndex.Merge(m, src) +} +func (m *GenesisReportIndex) XXX_Size() int { + return m.Size() +} +func (m *GenesisReportIndex) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisReportIndex.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisReportIndex proto.InternalMessageInfo + +func (m *GenesisReportIndex) GetReporterSupernodeAccount() string { + if m != nil { + return m.ReporterSupernodeAccount + } + return "" +} + +func (m *GenesisReportIndex) GetEpochId() uint64 { + if m != nil { + return m.EpochId + } + return 0 +} + +// GenesisHostReportIndex — hr/ index entry. +type GenesisHostReportIndex struct { + ReporterSupernodeAccount string `protobuf:"bytes,1,opt,name=reporter_supernode_account,json=reporterSupernodeAccount,proto3" json:"reporter_supernode_account,omitempty"` + EpochId uint64 `protobuf:"varint,2,opt,name=epoch_id,json=epochId,proto3" json:"epoch_id,omitempty"` +} + +func (m *GenesisHostReportIndex) Reset() { *m = GenesisHostReportIndex{} } +func (m *GenesisHostReportIndex) String() string { return proto.CompactTextString(m) } +func (*GenesisHostReportIndex) ProtoMessage() {} +func (*GenesisHostReportIndex) Descriptor() ([]byte, []int) { + return fileDescriptor_a433cb4f206fdbad, []int{8} +} +func (m *GenesisHostReportIndex) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisHostReportIndex) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisHostReportIndex.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err } + return b[:n], nil } - if m.NextHealOpId != 0 { - n += 1 + sovGenesis(uint64(m.NextHealOpId)) +} +func (m *GenesisHostReportIndex) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisHostReportIndex.Merge(m, src) +} +func (m *GenesisHostReportIndex) XXX_Size() int { + return m.Size() +} +func (m *GenesisHostReportIndex) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisHostReportIndex.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisHostReportIndex proto.InternalMessageInfo + +func (m *GenesisHostReportIndex) GetReporterSupernodeAccount() string { + if m != nil { + return m.ReporterSupernodeAccount } - if len(m.TicketArtifactCountStates) > 0 { - for _, e := range m.TicketArtifactCountStates { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) + return "" +} + +func (m *GenesisHostReportIndex) GetEpochId() uint64 { + if m != nil { + return m.EpochId + } + return 0 +} + +// GenesisStorageChallengeIndex — sc/ index entry. +type GenesisStorageChallengeIndex struct { + SupernodeAccount string `protobuf:"bytes,1,opt,name=supernode_account,json=supernodeAccount,proto3" json:"supernode_account,omitempty"` + EpochId uint64 `protobuf:"varint,2,opt,name=epoch_id,json=epochId,proto3" json:"epoch_id,omitempty"` + ReporterSupernodeAccount string `protobuf:"bytes,3,opt,name=reporter_supernode_account,json=reporterSupernodeAccount,proto3" json:"reporter_supernode_account,omitempty"` +} + +func (m *GenesisStorageChallengeIndex) Reset() { *m = GenesisStorageChallengeIndex{} } +func (m *GenesisStorageChallengeIndex) String() string { return proto.CompactTextString(m) } +func (*GenesisStorageChallengeIndex) ProtoMessage() {} +func (*GenesisStorageChallengeIndex) Descriptor() ([]byte, []int) { + return fileDescriptor_a433cb4f206fdbad, []int{9} +} +func (m *GenesisStorageChallengeIndex) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisStorageChallengeIndex) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisStorageChallengeIndex.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err } + return b[:n], nil } - if len(m.StorageTruthPostponements) > 0 { - for _, e := range m.StorageTruthPostponements { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) +} +func (m *GenesisStorageChallengeIndex) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisStorageChallengeIndex.Merge(m, src) +} +func (m *GenesisStorageChallengeIndex) XXX_Size() int { + return m.Size() +} +func (m *GenesisStorageChallengeIndex) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisStorageChallengeIndex.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisStorageChallengeIndex proto.InternalMessageInfo + +func (m *GenesisStorageChallengeIndex) GetSupernodeAccount() string { + if m != nil { + return m.SupernodeAccount + } + return "" +} + +func (m *GenesisStorageChallengeIndex) GetEpochId() uint64 { + if m != nil { + return m.EpochId + } + return 0 +} + +func (m *GenesisStorageChallengeIndex) GetReporterSupernodeAccount() string { + if m != nil { + return m.ReporterSupernodeAccount + } + return "" +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "lumera.audit.v1.GenesisState") + proto.RegisterType((*StorageTruthPostponement)(nil), "lumera.audit.v1.StorageTruthPostponement") + proto.RegisterType((*GenesisRecheckEvidence)(nil), "lumera.audit.v1.GenesisRecheckEvidence") + proto.RegisterType((*GenesisStorageProofTranscript)(nil), "lumera.audit.v1.GenesisStorageProofTranscript") + proto.RegisterType((*GenesisNodeFailureFact)(nil), "lumera.audit.v1.GenesisNodeFailureFact") + proto.RegisterType((*GenesisReporterResultFact)(nil), "lumera.audit.v1.GenesisReporterResultFact") + proto.RegisterType((*GenesisFailedHealMarker)(nil), "lumera.audit.v1.GenesisFailedHealMarker") + proto.RegisterType((*GenesisReportIndex)(nil), "lumera.audit.v1.GenesisReportIndex") + proto.RegisterType((*GenesisHostReportIndex)(nil), "lumera.audit.v1.GenesisHostReportIndex") + proto.RegisterType((*GenesisStorageChallengeIndex)(nil), "lumera.audit.v1.GenesisStorageChallengeIndex") +} + +func init() { proto.RegisterFile("lumera/audit/v1/genesis.proto", fileDescriptor_a433cb4f206fdbad) } + +var fileDescriptor_a433cb4f206fdbad = []byte{ + // 1047 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4d, 0x6f, 0x1b, 0x45, + 0x18, 0xce, 0xd6, 0x69, 0x62, 0x4f, 0xfc, 0x39, 0x26, 0x64, 0xf3, 0x51, 0x37, 0x32, 0xaa, 0xea, + 0x06, 0x61, 0x2b, 0xe5, 0x82, 0x80, 0x4b, 0x52, 0x48, 0x63, 0x24, 0x20, 0x72, 0x72, 0x40, 0xa0, + 0xb2, 0x9a, 0xee, 0x4e, 0xbc, 0x43, 0xec, 0x9d, 0x65, 0x66, 0x1c, 0x25, 0x1c, 0xf8, 0x0d, 0xfd, + 0x11, 0x1c, 0x38, 0xf2, 0x2b, 0x50, 0xb9, 0xf5, 0xc8, 0x09, 0xa1, 0xe4, 0xc0, 0xdf, 0x40, 0xf3, + 0xb1, 0xeb, 0xf5, 0xae, 0xd7, 0x14, 0x04, 0x5c, 0x5a, 0xe7, 0x7d, 0xe7, 0x79, 0x9e, 0xf7, 0x79, + 0x67, 0xde, 0xd7, 0x06, 0xf7, 0x46, 0x93, 0x31, 0x66, 0xa8, 0x87, 0x26, 0x1e, 0x11, 0xbd, 0xcb, + 0xfd, 0xde, 0x10, 0x07, 0x98, 0x13, 0xde, 0x0d, 0x19, 0x15, 0x14, 0xd6, 0x74, 0xba, 0xab, 0xd2, + 0xdd, 0xcb, 0xfd, 0xad, 0x06, 0x1a, 0x93, 0x80, 0xf6, 0xd4, 0xbf, 0xfa, 0xcc, 0xd6, 0x1b, 0x43, + 0x3a, 0xa4, 0xea, 0x63, 0x4f, 0x7e, 0x32, 0xd1, 0x9d, 0x34, 0x71, 0x88, 0x18, 0x1a, 0x1b, 0xde, + 0xad, 0x56, 0x3a, 0x8b, 0x2f, 0x89, 0x87, 0x03, 0x17, 0x9b, 0xfc, 0x76, 0x3a, 0xaf, 0x0b, 0x50, + 0xc9, 0xf6, 0x8b, 0x0a, 0x28, 0x3f, 0xd5, 0x65, 0x9e, 0x0a, 0x24, 0x30, 0x7c, 0x1f, 0xac, 0x68, + 0x76, 0xdb, 0xda, 0xb5, 0x3a, 0x6b, 0x8f, 0x37, 0xba, 0xa9, 0xb2, 0xbb, 0x27, 0x2a, 0x7d, 0x58, + 0x7a, 0xf9, 0xdb, 0xfd, 0xa5, 0x1f, 0xff, 0xf8, 0x69, 0xcf, 0x1a, 0x18, 0x04, 0xfc, 0x00, 0x14, + 0x23, 0x6d, 0xfb, 0xce, 0x6e, 0xa1, 0xb3, 0xf6, 0x78, 0x33, 0x83, 0xfe, 0xd8, 0x1c, 0x38, 0x5c, + 0x96, 0xf8, 0x41, 0x0c, 0x80, 0x1d, 0x50, 0x0f, 0xf0, 0x95, 0x70, 0xa2, 0x80, 0x43, 0x3c, 0xbb, + 0xb0, 0x6b, 0x75, 0x96, 0x07, 0x55, 0x19, 0x8f, 0x70, 0x7d, 0x0f, 0x3e, 0x03, 0xeb, 0x01, 0xf5, + 0xb0, 0xc3, 0x27, 0x3c, 0x24, 0x2e, 0xa1, 0x81, 0xc3, 0x65, 0xe9, 0xdc, 0x5e, 0x56, 0x9a, 0x6f, + 0x65, 0x34, 0x3f, 0xa3, 0x1e, 0x3e, 0x8d, 0x0e, 0x2b, 0x9b, 0x46, 0xbd, 0x19, 0x64, 0x32, 0x1c, + 0x52, 0xb0, 0xcd, 0x70, 0x48, 0x99, 0xc0, 0xcc, 0x61, 0x78, 0x44, 0xd0, 0x73, 0x32, 0x22, 0xe2, + 0x3a, 0x12, 0xb9, 0xab, 0x44, 0x1e, 0x65, 0x44, 0x06, 0x06, 0x33, 0x98, 0x42, 0x92, 0x52, 0x9b, + 0x2c, 0x27, 0xaf, 0x04, 0x05, 0x71, 0x2f, 0xb0, 0x70, 0x3c, 0x2c, 0x30, 0x23, 0x94, 0x21, 0x91, + 0x70, 0xb5, 0x92, 0x23, 0x78, 0xa6, 0x30, 0x1f, 0x25, 0x21, 0x33, 0x82, 0x22, 0x27, 0xcf, 0xe1, + 0x7b, 0xa0, 0xe8, 0x63, 0x34, 0x72, 0x68, 0xc8, 0xed, 0x55, 0xc5, 0x9e, 0xbd, 0xe5, 0x63, 0x8c, + 0x46, 0x9f, 0x87, 0x86, 0x6b, 0xd5, 0x57, 0x7f, 0x71, 0xf8, 0x00, 0xd4, 0xd4, 0x25, 0x19, 0xb8, + 0xbc, 0xa3, 0xa2, 0xba, 0xa3, 0xb2, 0x0c, 0x6b, 0x4c, 0xdf, 0x83, 0x21, 0xd8, 0x31, 0x8e, 0x10, + 0x13, 0xe4, 0x1c, 0xb9, 0xc2, 0x71, 0xe9, 0x24, 0x10, 0x91, 0xa5, 0xd2, 0x42, 0x4b, 0x07, 0x06, + 0xf3, 0x44, 0x42, 0xe6, 0x58, 0xca, 0xe6, 0x55, 0x0f, 0xb9, 0xa0, 0x0c, 0x0d, 0xb1, 0x23, 0xd8, + 0x44, 0xf8, 0x4e, 0x48, 0xb9, 0x08, 0x69, 0x80, 0xc7, 0x38, 0x10, 0xdc, 0x06, 0x39, 0x82, 0xa7, + 0x1a, 0x73, 0x26, 0x21, 0x27, 0x09, 0x44, 0x24, 0xc8, 0x73, 0xf2, 0x1c, 0x7e, 0x01, 0xea, 0x0c, + 0xbb, 0x3e, 0x76, 0x2f, 0xe2, 0x17, 0x6b, 0xaf, 0x29, 0x95, 0x87, 0x19, 0x15, 0x33, 0x60, 0x03, + 0x7d, 0x3e, 0x35, 0x01, 0x35, 0x36, 0x1b, 0x86, 0x21, 0x88, 0x64, 0x9d, 0x90, 0x51, 0x7a, 0xee, + 0x08, 0x86, 0x02, 0xee, 0x32, 0x12, 0x0a, 0x6e, 0x97, 0x95, 0x44, 0x37, 0x4f, 0xc2, 0xf8, 0x39, + 0x91, 0xb8, 0xb3, 0x18, 0x66, 0x94, 0x36, 0xf8, 0xdc, 0x2c, 0x87, 0x5f, 0x01, 0xa8, 0x06, 0xea, + 0x1c, 0x91, 0xd1, 0x84, 0xc9, 0xff, 0x5d, 0xc1, 0xed, 0xca, 0x62, 0x37, 0x72, 0xa8, 0x8e, 0x34, + 0xe0, 0x08, 0xb9, 0x91, 0x46, 0x3d, 0x98, 0x0d, 0x73, 0xe8, 0x81, 0xf5, 0xc4, 0x38, 0xf1, 0xc9, + 0x48, 0x18, 0xfe, 0xaa, 0xe2, 0xdf, 0xcb, 0xef, 0x56, 0x34, 0x2f, 0x12, 0x93, 0x90, 0x68, 0xb2, + 0x4c, 0x86, 0xc3, 0xaf, 0x41, 0x53, 0x56, 0x8f, 0x3d, 0xfd, 0x34, 0xc7, 0x88, 0x5d, 0x60, 0xc6, + 0xed, 0x9a, 0xd2, 0xe8, 0xe4, 0x69, 0x1c, 0x29, 0x88, 0x7c, 0xb6, 0x9f, 0x2a, 0x80, 0x51, 0x68, + 0x9c, 0xa7, 0xe2, 0x1c, 0x3e, 0x05, 0x15, 0x1c, 0x52, 0xd7, 0x77, 0xb4, 0x38, 0xb7, 0xeb, 0x8a, + 0x79, 0x27, 0xbb, 0xdf, 0xe4, 0x29, 0x5d, 0xbb, 0x61, 0x2b, 0xe3, 0x69, 0x88, 0xc3, 0x13, 0x50, + 0xd5, 0x14, 0x0e, 0x09, 0x3c, 0xe2, 0x62, 0x6e, 0x37, 0x72, 0xb6, 0xd6, 0x4c, 0x1f, 0xfa, 0x81, + 0x87, 0xaf, 0x0c, 0x61, 0x85, 0x45, 0x21, 0x89, 0x87, 0xcf, 0x40, 0xd3, 0xa7, 0x5c, 0x38, 0x29, + 0x5a, 0xb8, 0xf8, 0xfa, 0x8e, 0x29, 0x17, 0x59, 0xea, 0x86, 0x9f, 0x0c, 0x2b, 0x7a, 0x3a, 0x7d, + 0x8e, 0xae, 0x8f, 0x46, 0x23, 0x1c, 0x0c, 0x71, 0x2c, 0xd2, 0x54, 0x22, 0xef, 0xfc, 0xc5, 0x73, + 0x7c, 0x12, 0xe1, 0x92, 0x52, 0xd1, 0x6b, 0x4c, 0x26, 0x25, 0x67, 0xfb, 0x3b, 0x60, 0xe7, 0x8d, + 0x25, 0x7c, 0x1b, 0x34, 0xf8, 0x24, 0xc4, 0x4c, 0x3d, 0x57, 0xe4, 0xaa, 0xa5, 0xa2, 0xbe, 0xa8, + 0x4a, 0x83, 0x7a, 0x9c, 0x38, 0xd0, 0x71, 0xb8, 0x0f, 0xd6, 0xa3, 0x2d, 0xe0, 0x39, 0x48, 0x38, + 0xfa, 0x02, 0x89, 0x67, 0xdf, 0x51, 0x2b, 0x0b, 0xc6, 0xc9, 0x03, 0xa1, 0x6e, 0xad, 0xef, 0xb5, + 0xaf, 0xc1, 0x9b, 0xf3, 0x87, 0x15, 0x6e, 0x82, 0x62, 0x8c, 0xb7, 0x14, 0x7e, 0x15, 0x6b, 0x10, + 0xdc, 0x06, 0x25, 0xb3, 0xed, 0x0c, 0x77, 0x69, 0x50, 0xd4, 0x81, 0xbe, 0x07, 0x1f, 0x82, 0x9a, + 0xcb, 0x30, 0x12, 0x94, 0xc5, 0xf5, 0x16, 0xd4, 0x91, 0xaa, 0x09, 0x9b, 0x6a, 0xdb, 0x04, 0xdc, + 0x5b, 0x38, 0xc4, 0x92, 0x69, 0xba, 0x09, 0x1c, 0x1f, 0x71, 0xdf, 0x38, 0xaf, 0x4e, 0xc3, 0xc7, + 0x88, 0xfb, 0xf0, 0x3e, 0x58, 0x63, 0xd8, 0xa5, 0xcc, 0x73, 0xbe, 0xe1, 0x34, 0x50, 0x15, 0x95, + 0x07, 0x40, 0x87, 0x3e, 0xe1, 0x34, 0x68, 0xff, 0x62, 0xc5, 0x36, 0x53, 0x53, 0xfc, 0xf7, 0x1a, + 0x9c, 0xec, 0xc9, 0x9d, 0x05, 0x3d, 0x29, 0xa4, 0x7a, 0xf2, 0x48, 0xee, 0x4e, 0xb3, 0x12, 0x22, + 0x8d, 0x65, 0x75, 0xa6, 0x16, 0xc5, 0x23, 0x89, 0x94, 0x97, 0xbb, 0x19, 0x2f, 0x3f, 0x5b, 0x60, + 0x33, 0x77, 0x63, 0xcc, 0x55, 0xb2, 0xe6, 0x2b, 0xfd, 0x53, 0x33, 0x0f, 0x40, 0x55, 0x20, 0x36, + 0x94, 0xdf, 0x75, 0x33, 0x56, 0x2a, 0x3a, 0xfa, 0xda, 0x46, 0xbe, 0x07, 0x1b, 0x39, 0x5b, 0xe9, + 0x7f, 0xb9, 0x94, 0xf6, 0x18, 0xc0, 0xec, 0xc6, 0x81, 0x1f, 0x82, 0xad, 0xb8, 0x81, 0x79, 0x35, + 0xd8, 0xd1, 0x89, 0xd3, 0xd7, 0xaf, 0xa5, 0xfd, 0x6d, 0xfc, 0x04, 0x53, 0x9b, 0xe8, 0xbf, 0x93, + 0xfc, 0xc1, 0x02, 0x3b, 0x8b, 0x16, 0xd3, 0xbf, 0xd6, 0xe7, 0xc5, 0x0e, 0x0a, 0x8b, 0x1d, 0x1c, + 0xee, 0xbd, 0xbc, 0x69, 0x59, 0xaf, 0x6e, 0x5a, 0xd6, 0xef, 0x37, 0x2d, 0xeb, 0xc5, 0x6d, 0x6b, + 0xe9, 0xd5, 0x6d, 0x6b, 0xe9, 0xd7, 0xdb, 0xd6, 0xd2, 0x97, 0xf5, 0xab, 0xe9, 0x8f, 0x78, 0x71, + 0x1d, 0x62, 0xfe, 0x7c, 0x45, 0xfd, 0x8a, 0x7f, 0xf7, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, + 0x21, 0xa5, 0x52, 0x7b, 0x0c, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.StorageChallengeIndices) > 0 { + for iNdEx := len(m.StorageChallengeIndices) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.StorageChallengeIndices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x9a + } + } + if len(m.HostReportIndices) > 0 { + for iNdEx := len(m.HostReportIndices) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.HostReportIndices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x92 + } + } + if len(m.ReportIndices) > 0 { + for iNdEx := len(m.ReportIndices) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ReportIndices[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + } + } + if len(m.EpochReports) > 0 { + for iNdEx := len(m.EpochReports) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.EpochReports[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + } + if len(m.FailedHealMarkers) > 0 { + for iNdEx := len(m.FailedHealMarkers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FailedHealMarkers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x7a + } + } + if len(m.ReporterResultFacts) > 0 { + for iNdEx := len(m.ReporterResultFacts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ReporterResultFacts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x72 + } + } + if len(m.NodeFailureFacts) > 0 { + for iNdEx := len(m.NodeFailureFacts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.NodeFailureFacts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + } + } + if len(m.StorageProofTranscripts) > 0 { + for iNdEx := len(m.StorageProofTranscripts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.StorageProofTranscripts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } + } + if len(m.RecheckEvidence) > 0 { + for iNdEx := len(m.RecheckEvidence) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RecheckEvidence[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } + } + if len(m.StorageTruthPostponements) > 0 { + for iNdEx := len(m.StorageTruthPostponements) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.StorageTruthPostponements[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } + if len(m.TicketArtifactCountStates) > 0 { + for iNdEx := len(m.TicketArtifactCountStates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TicketArtifactCountStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } + if m.NextHealOpId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.NextHealOpId)) + i-- + dAtA[i] = 0x40 + } + if len(m.HealOps) > 0 { + for iNdEx := len(m.HealOps) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.HealOps[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if len(m.TicketDeteriorationStates) > 0 { + for iNdEx := len(m.TicketDeteriorationStates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TicketDeteriorationStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.ReporterReliabilityStates) > 0 { + for iNdEx := len(m.ReporterReliabilityStates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ReporterReliabilityStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.NodeSuspicionStates) > 0 { + for iNdEx := len(m.NodeSuspicionStates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.NodeSuspicionStates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if m.NextEvidenceId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.NextEvidenceId)) + i-- + dAtA[i] = 0x18 + } + if len(m.Evidence) > 0 { + for iNdEx := len(m.Evidence) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Evidence[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *StorageTruthPostponement) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StorageTruthPostponement) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StorageTruthPostponement) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PostponedAtEpochId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.PostponedAtEpochId)) + i-- + dAtA[i] = 0x10 + } + if len(m.SupernodeAccount) > 0 { + i -= len(m.SupernodeAccount) + copy(dAtA[i:], m.SupernodeAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.SupernodeAccount))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisRecheckEvidence) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisRecheckEvidence) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisRecheckEvidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CreatorAccount) > 0 { + i -= len(m.CreatorAccount) + copy(dAtA[i:], m.CreatorAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.CreatorAccount))) + i-- + dAtA[i] = 0x1a + } + if len(m.TicketId) > 0 { + i -= len(m.TicketId) + copy(dAtA[i:], m.TicketId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.TicketId))) + i-- + dAtA[i] = 0x12 + } + if m.EpochId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.EpochId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *GenesisStorageProofTranscript) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisStorageProofTranscript) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisStorageProofTranscript) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RecordJson) > 0 { + i -= len(m.RecordJson) + copy(dAtA[i:], m.RecordJson) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.RecordJson))) + i-- + dAtA[i] = 0x12 + } + if len(m.TranscriptHash) > 0 { + i -= len(m.TranscriptHash) + copy(dAtA[i:], m.TranscriptHash) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.TranscriptHash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisNodeFailureFact) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisNodeFailureFact) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisNodeFailureFact) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RecordJson) > 0 { + i -= len(m.RecordJson) + copy(dAtA[i:], m.RecordJson) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.RecordJson))) + i-- + dAtA[i] = 0x2a + } + if len(m.ReporterAccount) > 0 { + i -= len(m.ReporterAccount) + copy(dAtA[i:], m.ReporterAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ReporterAccount))) + i-- + dAtA[i] = 0x22 + } + if len(m.TicketId) > 0 { + i -= len(m.TicketId) + copy(dAtA[i:], m.TicketId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.TicketId))) + i-- + dAtA[i] = 0x1a + } + if m.EpochId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.EpochId)) + i-- + dAtA[i] = 0x10 + } + if len(m.SupernodeAccount) > 0 { + i -= len(m.SupernodeAccount) + copy(dAtA[i:], m.SupernodeAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.SupernodeAccount))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisReporterResultFact) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisReporterResultFact) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisReporterResultFact) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RecordJson) > 0 { + i -= len(m.RecordJson) + copy(dAtA[i:], m.RecordJson) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.RecordJson))) + i-- + dAtA[i] = 0x2a + } + if len(m.TargetAccount) > 0 { + i -= len(m.TargetAccount) + copy(dAtA[i:], m.TargetAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.TargetAccount))) + i-- + dAtA[i] = 0x22 + } + if len(m.TicketId) > 0 { + i -= len(m.TicketId) + copy(dAtA[i:], m.TicketId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.TicketId))) + i-- + dAtA[i] = 0x1a + } + if m.EpochId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.EpochId)) + i-- + dAtA[i] = 0x10 + } + if len(m.ReporterAccount) > 0 { + i -= len(m.ReporterAccount) + copy(dAtA[i:], m.ReporterAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ReporterAccount))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisFailedHealMarker) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisFailedHealMarker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisFailedHealMarker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TicketId) > 0 { + i -= len(m.TicketId) + copy(dAtA[i:], m.TicketId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.TicketId))) + i-- + dAtA[i] = 0x1a + } + if m.EpochId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.EpochId)) + i-- + dAtA[i] = 0x10 + } + if len(m.SupernodeAccount) > 0 { + i -= len(m.SupernodeAccount) + copy(dAtA[i:], m.SupernodeAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.SupernodeAccount))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisReportIndex) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisReportIndex) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisReportIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.EpochId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.EpochId)) + i-- + dAtA[i] = 0x10 + } + if len(m.ReporterSupernodeAccount) > 0 { + i -= len(m.ReporterSupernodeAccount) + copy(dAtA[i:], m.ReporterSupernodeAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ReporterSupernodeAccount))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisHostReportIndex) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisHostReportIndex) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisHostReportIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.EpochId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.EpochId)) + i-- + dAtA[i] = 0x10 + } + if len(m.ReporterSupernodeAccount) > 0 { + i -= len(m.ReporterSupernodeAccount) + copy(dAtA[i:], m.ReporterSupernodeAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ReporterSupernodeAccount))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisStorageChallengeIndex) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisStorageChallengeIndex) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisStorageChallengeIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ReporterSupernodeAccount) > 0 { + i -= len(m.ReporterSupernodeAccount) + copy(dAtA[i:], m.ReporterSupernodeAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ReporterSupernodeAccount))) + i-- + dAtA[i] = 0x1a + } + if m.EpochId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.EpochId)) + i-- + dAtA[i] = 0x10 + } + if len(m.SupernodeAccount) > 0 { + i -= len(m.SupernodeAccount) + copy(dAtA[i:], m.SupernodeAccount) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.SupernodeAccount))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.Evidence) > 0 { + for _, e := range m.Evidence { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if m.NextEvidenceId != 0 { + n += 1 + sovGenesis(uint64(m.NextEvidenceId)) + } + if len(m.NodeSuspicionStates) > 0 { + for _, e := range m.NodeSuspicionStates { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ReporterReliabilityStates) > 0 { + for _, e := range m.ReporterReliabilityStates { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.TicketDeteriorationStates) > 0 { + for _, e := range m.TicketDeteriorationStates { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.HealOps) > 0 { + for _, e := range m.HealOps { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if m.NextHealOpId != 0 { + n += 1 + sovGenesis(uint64(m.NextHealOpId)) + } + if len(m.TicketArtifactCountStates) > 0 { + for _, e := range m.TicketArtifactCountStates { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.StorageTruthPostponements) > 0 { + for _, e := range m.StorageTruthPostponements { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.RecheckEvidence) > 0 { + for _, e := range m.RecheckEvidence { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.StorageProofTranscripts) > 0 { + for _, e := range m.StorageProofTranscripts { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.NodeFailureFacts) > 0 { + for _, e := range m.NodeFailureFacts { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ReporterResultFacts) > 0 { + for _, e := range m.ReporterResultFacts { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.FailedHealMarkers) > 0 { + for _, e := range m.FailedHealMarkers { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.EpochReports) > 0 { + for _, e := range m.EpochReports { + l = e.Size() + n += 2 + l + sovGenesis(uint64(l)) + } + } + if len(m.ReportIndices) > 0 { + for _, e := range m.ReportIndices { + l = e.Size() + n += 2 + l + sovGenesis(uint64(l)) + } + } + if len(m.HostReportIndices) > 0 { + for _, e := range m.HostReportIndices { + l = e.Size() + n += 2 + l + sovGenesis(uint64(l)) + } + } + if len(m.StorageChallengeIndices) > 0 { + for _, e := range m.StorageChallengeIndices { + l = e.Size() + n += 2 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *StorageTruthPostponement) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SupernodeAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.PostponedAtEpochId != 0 { + n += 1 + sovGenesis(uint64(m.PostponedAtEpochId)) + } + return n +} + +func (m *GenesisRecheckEvidence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.EpochId != 0 { + n += 1 + sovGenesis(uint64(m.EpochId)) + } + l = len(m.TicketId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.CreatorAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *GenesisStorageProofTranscript) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TranscriptHash) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.RecordJson) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *GenesisNodeFailureFact) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SupernodeAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.EpochId != 0 { + n += 1 + sovGenesis(uint64(m.EpochId)) + } + l = len(m.TicketId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ReporterAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.RecordJson) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *GenesisReporterResultFact) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ReporterAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.EpochId != 0 { + n += 1 + sovGenesis(uint64(m.EpochId)) + } + l = len(m.TicketId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.TargetAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.RecordJson) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *GenesisFailedHealMarker) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SupernodeAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.EpochId != 0 { + n += 1 + sovGenesis(uint64(m.EpochId)) + } + l = len(m.TicketId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *GenesisReportIndex) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ReporterSupernodeAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.EpochId != 0 { + n += 1 + sovGenesis(uint64(m.EpochId)) + } + return n +} + +func (m *GenesisHostReportIndex) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ReporterSupernodeAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.EpochId != 0 { + n += 1 + sovGenesis(uint64(m.EpochId)) + } + return n +} + +func (m *GenesisStorageChallengeIndex) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SupernodeAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.EpochId != 0 { + n += 1 + sovGenesis(uint64(m.EpochId)) + } + l = len(m.ReporterSupernodeAccount) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Evidence = append(m.Evidence, Evidence{}) + if err := m.Evidence[len(m.Evidence)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NextEvidenceId", wireType) + } + m.NextEvidenceId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NextEvidenceId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NodeSuspicionStates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NodeSuspicionStates = append(m.NodeSuspicionStates, NodeSuspicionState{}) + if err := m.NodeSuspicionStates[len(m.NodeSuspicionStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReporterReliabilityStates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReporterReliabilityStates = append(m.ReporterReliabilityStates, ReporterReliabilityState{}) + if err := m.ReporterReliabilityStates[len(m.ReporterReliabilityStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TicketDeteriorationStates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TicketDeteriorationStates = append(m.TicketDeteriorationStates, TicketDeteriorationState{}) + if err := m.TicketDeteriorationStates[len(m.TicketDeteriorationStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HealOps", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HealOps = append(m.HealOps, HealOp{}) + if err := m.HealOps[len(m.HealOps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NextHealOpId", wireType) + } + m.NextHealOpId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NextHealOpId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TicketArtifactCountStates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TicketArtifactCountStates = append(m.TicketArtifactCountStates, TicketArtifactCountState{}) + if err := m.TicketArtifactCountStates[len(m.TicketArtifactCountStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageTruthPostponements", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StorageTruthPostponements = append(m.StorageTruthPostponements, StorageTruthPostponement{}) + if err := m.StorageTruthPostponements[len(m.StorageTruthPostponements)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RecheckEvidence", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RecheckEvidence = append(m.RecheckEvidence, GenesisRecheckEvidence{}) + if err := m.RecheckEvidence[len(m.RecheckEvidence)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageProofTranscripts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StorageProofTranscripts = append(m.StorageProofTranscripts, GenesisStorageProofTranscript{}) + if err := m.StorageProofTranscripts[len(m.StorageProofTranscripts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NodeFailureFacts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NodeFailureFacts = append(m.NodeFailureFacts, GenesisNodeFailureFact{}) + if err := m.NodeFailureFacts[len(m.NodeFailureFacts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReporterResultFacts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReporterResultFacts = append(m.ReporterResultFacts, GenesisReporterResultFact{}) + if err := m.ReporterResultFacts[len(m.ReporterResultFacts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FailedHealMarkers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FailedHealMarkers = append(m.FailedHealMarkers, GenesisFailedHealMarker{}) + if err := m.FailedHealMarkers[len(m.FailedHealMarkers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochReports", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EpochReports = append(m.EpochReports, EpochReport{}) + if err := m.EpochReports[len(m.EpochReports)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 17: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReportIndices", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReportIndices = append(m.ReportIndices, GenesisReportIndex{}) + if err := m.ReportIndices[len(m.ReportIndices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 18: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostReportIndices", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostReportIndices = append(m.HostReportIndices, GenesisHostReportIndex{}) + if err := m.HostReportIndices[len(m.HostReportIndices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 19: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageChallengeIndices", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StorageChallengeIndices = append(m.StorageChallengeIndices, GenesisStorageChallengeIndex{}) + if err := m.StorageChallengeIndices[len(m.StorageChallengeIndices)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StorageTruthPostponement) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StorageTruthPostponement: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StorageTruthPostponement: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SupernodeAccount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SupernodeAccount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PostponedAtEpochId", wireType) + } + m.PostponedAtEpochId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PostponedAtEpochId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisRecheckEvidence) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisRecheckEvidence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisRecheckEvidence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochId", wireType) + } + m.EpochId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EpochId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TicketId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TicketId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatorAccount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CreatorAccount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisStorageProofTranscript) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisStorageProofTranscript: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisStorageProofTranscript: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TranscriptHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TranscriptHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RecordJson", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RecordJson = append(m.RecordJson[:0], dAtA[iNdEx:postIndex]...) + if m.RecordJson == nil { + m.RecordJson = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisNodeFailureFact) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisNodeFailureFact: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisNodeFailureFact: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SupernodeAccount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SupernodeAccount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochId", wireType) + } + m.EpochId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EpochId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TicketId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TicketId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReporterAccount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReporterAccount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RecordJson", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RecordJson = append(m.RecordJson[:0], dAtA[iNdEx:postIndex]...) + if m.RecordJson == nil { + m.RecordJson = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy } } - return n -} -func (m *StorageTruthPostponement) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.SupernodeAccount) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - if m.PostponedAtEpochId != 0 { - n += 1 + sovGenesis(uint64(m.PostponedAtEpochId)) + if iNdEx > l { + return io.ErrUnexpectedEOF } - return n -} - -func sovGenesis(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozGenesis(x uint64) (n int) { - return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + return nil } -func (m *GenesisState) Unmarshal(dAtA []byte) error { +func (m *GenesisReporterResultFact) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -537,17 +3061,17 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + return fmt.Errorf("proto: GenesisReporterResultFact: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GenesisReporterResultFact: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ReporterAccount", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -557,30 +3081,48 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ReporterAccount = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochId", wireType) + } + m.EpochId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EpochId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TicketId", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -590,31 +3132,61 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.Evidence = append(m.Evidence, Evidence{}) - if err := m.Evidence[len(m.Evidence)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.TicketId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetAccount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF } + m.TargetAccount = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NextEvidenceId", wireType) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RecordJson", wireType) } - m.NextEvidenceId = 0 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -624,16 +3196,81 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.NextEvidenceId |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - case 4: + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RecordJson = append(m.RecordJson[:0], dAtA[iNdEx:postIndex]...) + if m.RecordJson == nil { + m.RecordJson = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisFailedHealMarker) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisFailedHealMarker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisFailedHealMarker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field NodeSuspicionStates", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SupernodeAccount", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -643,31 +3280,29 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.NodeSuspicionStates = append(m.NodeSuspicionStates, NodeSuspicionState{}) - if err := m.NodeSuspicionStates[len(m.NodeSuspicionStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.SupernodeAccount = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ReporterReliabilityStates", wireType) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochId", wireType) } - var msglen int + m.EpochId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -677,31 +3312,16 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + m.EpochId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ReporterReliabilityStates = append(m.ReporterReliabilityStates, ReporterReliabilityState{}) - if err := m.ReporterReliabilityStates[len(m.ReporterReliabilityStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TicketDeteriorationStates", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TicketId", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -711,31 +3331,79 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.TicketDeteriorationStates = append(m.TicketDeteriorationStates, TicketDeteriorationState{}) - if err := m.TicketDeteriorationStates[len(m.TicketDeteriorationStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.TicketId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { return err } - iNdEx = postIndex - case 7: + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisReportIndex) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisReportIndex: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisReportIndex: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HealOps", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ReporterSupernodeAccount", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -745,31 +3413,29 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.HealOps = append(m.HealOps, HealOp{}) - if err := m.HealOps[len(m.HealOps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ReporterSupernodeAccount = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 8: + case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NextHealOpId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EpochId", wireType) } - m.NextHealOpId = 0 + m.EpochId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -779,16 +3445,66 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.NextHealOpId |= uint64(b&0x7F) << shift + m.EpochId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - case 9: + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisHostReportIndex) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisHostReportIndex: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisHostReportIndex: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TicketArtifactCountStates", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ReporterSupernodeAccount", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -798,31 +3514,29 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.TicketArtifactCountStates = append(m.TicketArtifactCountStates, TicketArtifactCountState{}) - if err := m.TicketArtifactCountStates[len(m.TicketArtifactCountStates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ReporterSupernodeAccount = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StorageTruthPostponements", wireType) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochId", wireType) } - var msglen int + m.EpochId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -832,26 +3546,11 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + m.EpochId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.StorageTruthPostponements = append(m.StorageTruthPostponements, StorageTruthPostponement{}) - if err := m.StorageTruthPostponements[len(m.StorageTruthPostponements)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) @@ -873,7 +3572,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } return nil } -func (m *StorageTruthPostponement) Unmarshal(dAtA []byte) error { +func (m *GenesisStorageChallengeIndex) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -896,10 +3595,10 @@ func (m *StorageTruthPostponement) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: StorageTruthPostponement: wiretype end group for non-group") + return fmt.Errorf("proto: GenesisStorageChallengeIndex: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: StorageTruthPostponement: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GenesisStorageChallengeIndex: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -936,9 +3635,9 @@ func (m *StorageTruthPostponement) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PostponedAtEpochId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EpochId", wireType) } - m.PostponedAtEpochId = 0 + m.EpochId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -948,11 +3647,43 @@ func (m *StorageTruthPostponement) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.PostponedAtEpochId |= uint64(b&0x7F) << shift + m.EpochId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReporterSupernodeAccount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReporterSupernodeAccount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/audit/v1/types/genesis_validate.go b/x/audit/v1/types/genesis_validate.go index 84438dd4..6095ddc5 100644 --- a/x/audit/v1/types/genesis_validate.go +++ b/x/audit/v1/types/genesis_validate.go @@ -3,13 +3,17 @@ package types import "fmt" // ValidateScoreStatesGenesis hard-errors on score states that are malformed -// relative to the current epoch. Per 119-F8 / 119-F12. +// relative to the current epoch. Per 119-F8 / 119-F12 + NEW-A-12. func ValidateScoreStatesGenesis(g GenesisState, currentEpoch uint64) error { for _, s := range g.NodeSuspicionStates { if s.LastUpdatedEpoch > currentEpoch { return fmt.Errorf("node suspicion %q has LastUpdatedEpoch %d > current %d", s.SupernodeAccount, s.LastUpdatedEpoch, currentEpoch) } + if s.WindowStartEpoch > currentEpoch { + return fmt.Errorf("node suspicion %q has WindowStartEpoch %d > current %d", + s.SupernodeAccount, s.WindowStartEpoch, currentEpoch) + } if s.SuspicionScore < 0 { return fmt.Errorf("node suspicion %q negative score %d", s.SupernodeAccount, s.SuspicionScore) } @@ -19,6 +23,10 @@ func ValidateScoreStatesGenesis(g GenesisState, currentEpoch uint64) error { return fmt.Errorf("reporter reliability %q has LastUpdatedEpoch %d > current %d", s.ReporterSupernodeAccount, s.LastUpdatedEpoch, currentEpoch) } + if s.WindowStartEpoch > currentEpoch { + return fmt.Errorf("reporter reliability %q has WindowStartEpoch %d > current %d", + s.ReporterSupernodeAccount, s.WindowStartEpoch, currentEpoch) + } } for _, s := range g.TicketDeteriorationStates { if s.LastUpdatedEpoch > currentEpoch { diff --git a/x/audit/v1/types/genesis_validate_test.go b/x/audit/v1/types/genesis_validate_test.go new file mode 100644 index 00000000..25c47906 --- /dev/null +++ b/x/audit/v1/types/genesis_validate_test.go @@ -0,0 +1,55 @@ +package types_test + +import ( + "testing" + + "github.com/LumeraProtocol/lumera/x/audit/v1/types" + "github.com/stretchr/testify/require" +) + +func TestValidateScoreStatesGenesis_WindowStartEpochInFuture(t *testing.T) { + const currentEpoch uint64 = 10 + + t.Run("node suspicion future window rejected", func(t *testing.T) { + g := types.GenesisState{ + NodeSuspicionStates: []types.NodeSuspicionState{ + { + SupernodeAccount: "lumera1aaaa", + LastUpdatedEpoch: 5, + WindowStartEpoch: currentEpoch + 10, + }, + }, + } + err := types.ValidateScoreStatesGenesis(g, currentEpoch) + require.Error(t, err) + require.Contains(t, err.Error(), "WindowStartEpoch") + }) + + t.Run("reporter reliability future window rejected", func(t *testing.T) { + g := types.GenesisState{ + ReporterReliabilityStates: []types.ReporterReliabilityState{ + { + ReporterSupernodeAccount: "lumera1bbbb", + LastUpdatedEpoch: 5, + WindowStartEpoch: currentEpoch + 10, + }, + }, + } + err := types.ValidateScoreStatesGenesis(g, currentEpoch) + require.Error(t, err) + require.Contains(t, err.Error(), "WindowStartEpoch") + }) + + t.Run("non-future window accepted", func(t *testing.T) { + g := types.GenesisState{ + NodeSuspicionStates: []types.NodeSuspicionState{ + { + SupernodeAccount: "lumera1aaaa", + LastUpdatedEpoch: 5, + WindowStartEpoch: currentEpoch, + }, + }, + } + require.NoError(t, types.ValidateScoreStatesGenesis(g, currentEpoch)) + }) +} diff --git a/x/audit/v1/types/keys.go b/x/audit/v1/types/keys.go index 972acd39..e2a1af0f 100644 --- a/x/audit/v1/types/keys.go +++ b/x/audit/v1/types/keys.go @@ -79,6 +79,8 @@ var ( // Storage-truth postponement state: // - StorageTruthPostponementKey: "ap/st/" + supernode_account -> 8 bytes u64be(postponed_at_epoch_id) storageTruthPostponementPrefix = []byte("ap/st/") + // Per F121-F12 — sibling marker recording strong-postpone reason. + storageTruthPostponementStrongPrefix = []byte("ap/sts/") // Storage-truth state: // - NodeSuspicionStateKey: "st/ns/" + supernode_account @@ -453,6 +455,32 @@ func StorageTruthPostponementPrefix() []byte { return storageTruthPostponementPrefix } +// StorageTruthPostponementStrongKey marks a postponement record as strong-band +// (F121-F12). Presence of this key indicates the supernode was postponed under +// the strong-postpone band; recovery requires StorageTruthStrongRecoveryCleanPassCount +// rather than StorageTruthRecoveryCleanPassCount. +func StorageTruthPostponementStrongKey(supernodeAccount string) []byte { + key := make([]byte, 0, len(storageTruthPostponementStrongPrefix)+len(supernodeAccount)) + key = append(key, storageTruthPostponementStrongPrefix...) + key = append(key, supernodeAccount...) + return key +} + +// RecheckEvidencePrefix returns the root prefix for all recheck-evidence dedup keys. +func RecheckEvidencePrefix() []byte { + return recheckEvidencePrefix +} + +// NodeStorageTruthFailureRootPrefix returns the root prefix for all node-failure facts. +func NodeStorageTruthFailureRootPrefix() []byte { + return nodeStorageTruthFailurePrefix +} + +// StorageTruthFailedHealRootPrefix returns the root prefix for all failed-heal markers. +func StorageTruthFailedHealRootPrefix() []byte { + return storageTruthFailedHealPrefix +} + // RecheckEvidenceKey returns the dedup key for a recheck evidence submission. // Format: "st/rce/" + u64be(epoch_id) + "/" + ticket_id + 0x00 + creator_account func RecheckEvidenceKey(epochID uint64, ticketID string, creatorAccount string) []byte { @@ -523,6 +551,59 @@ func ReporterStorageTruthResultRootPrefix() []byte { return reporterStorageTruthResultPrefix } +// NodeStorageTruthFailureEpochScanRange returns [start, end) iterator bounds +// for scanning a supernode's failure facts within the inclusive epoch range +// [startEpoch, endEpoch]. Key shape unchanged — start/end built from the +// canonical prefix + u64be(epoch). Per CP-NEW-A-11 residue (bounded scan). +func NodeStorageTruthFailureEpochScanRange(supernodeAccount string, startEpoch, endEpoch uint64) ([]byte, []byte) { + base := NodeStorageTruthFailurePrefix(supernodeAccount) + start := make([]byte, 0, len(base)+8) + start = append(start, base...) + start = binary.BigEndian.AppendUint64(start, startEpoch) + end := make([]byte, 0, len(base)+8) + end = append(end, base...) + // end is exclusive: u64be(endEpoch+1). Wrap-safe: if endEpoch is MaxUint64, + // fall back to the unbounded prefix end. + if endEpoch == ^uint64(0) { + // No upper bound — emit the prefix-end sentinel. + return start, prefixEnd(base) + } + end = binary.BigEndian.AppendUint64(end, endEpoch+1) + return start, end +} + +// ReporterStorageTruthResultEpochScanRange returns [start, end) iterator +// bounds for scanning a reporter's result facts within the inclusive epoch +// range [startEpoch, endEpoch]. Per CP-NEW-A-11 residue. +func ReporterStorageTruthResultEpochScanRange(reporterAccount string, startEpoch, endEpoch uint64) ([]byte, []byte) { + base := ReporterStorageTruthResultPrefix(reporterAccount) + start := make([]byte, 0, len(base)+8) + start = append(start, base...) + start = binary.BigEndian.AppendUint64(start, startEpoch) + end := make([]byte, 0, len(base)+8) + end = append(end, base...) + if endEpoch == ^uint64(0) { + return start, prefixEnd(base) + } + end = binary.BigEndian.AppendUint64(end, endEpoch+1) + return start, end +} + +// prefixEnd computes the exclusive end key of a prefix range — i.e. the +// smallest byte string that is strictly greater than every key beginning +// with prefix. Returns nil when prefix is all 0xFF. +func prefixEnd(prefix []byte) []byte { + end := make([]byte, len(prefix)) + copy(end, prefix) + for i := len(end) - 1; i >= 0; i-- { + end[i]++ + if end[i] != 0 { + return end[:i+1] + } + } + return nil +} + func StorageTruthFailedHealKey(supernodeAccount string, epochID uint64, ticketID string) []byte { key := make([]byte, 0, len(storageTruthFailedHealPrefix)+len(supernodeAccount)+1+8+1+len(ticketID)) key = append(key, storageTruthFailedHealPrefix...) diff --git a/x/audit/v1/types/params.go b/x/audit/v1/types/params.go index 5c8f9079..aad2717a 100644 --- a/x/audit/v1/types/params.go +++ b/x/audit/v1/types/params.go @@ -60,6 +60,8 @@ var ( KeyStorageTruthReporterMinReportsForDivergence = []byte("StorageTruthReporterMinReportsForDivergence") KeyStorageTruthNodeSuspicionThresholdStrongPostpone = []byte("StorageTruthNodeSuspicionThresholdStrongPostpone") KeyStorageTruthRecoveryCleanPassCount = []byte("StorageTruthRecoveryCleanPassCount") + KeyStorageTruthStrongRecoveryCleanPassCount = []byte("StorageTruthStrongRecoveryCleanPassCount") + KeyStorageTruthHealVerifierCount = []byte("StorageTruthHealVerifierCount") KeyStorageTruthClassAFaultWindow = []byte("StorageTruthClassAFaultWindow") KeyStorageTruthClassBFaultWindow = []byte("StorageTruthClassBFaultWindow") KeyStorageTruthHealDeadlineEpochs = []byte("StorageTruthHealDeadlineEpochs") @@ -154,6 +156,8 @@ var ( DefaultStorageTruthReporterMinReportsForDivergence = uint32(5) DefaultStorageTruthNodeSuspicionThresholdStrongPostpone = int64(140) DefaultStorageTruthRecoveryCleanPassCount = uint32(3) + DefaultStorageTruthStrongRecoveryCleanPassCount = uint32(5) + DefaultStorageTruthHealVerifierCount = uint32(2) DefaultStorageTruthClassAFaultWindow = uint32(14) DefaultStorageTruthClassBFaultWindow = uint32(7) DefaultStorageTruthHealDeadlineEpochs = uint32(3) @@ -254,6 +258,8 @@ func NewParams( storageTruthOldClassAFaultWindow uint32, storageTruthContradictionWindowEpochs uint32, storageTruthReporterIneligibleDurationEpochs uint32, + storageTruthStrongRecoveryCleanPassCount uint32, + storageTruthHealVerifierCount uint32, ) Params { return Params{ EpochLengthBlocks: epochLengthBlocks, @@ -310,6 +316,8 @@ func NewParams( StorageTruthOldClassAFaultWindow: storageTruthOldClassAFaultWindow, StorageTruthContradictionWindowEpochs: storageTruthContradictionWindowEpochs, StorageTruthReporterIneligibleDurationEpochs: storageTruthReporterIneligibleDurationEpochs, + StorageTruthStrongRecoveryCleanPassCount: storageTruthStrongRecoveryCleanPassCount, + StorageTruthHealVerifierCount: storageTruthHealVerifierCount, } } @@ -364,6 +372,8 @@ func DefaultParams() Params { DefaultStorageTruthOldClassAFaultWindow, DefaultStorageTruthContradictionWindowEpochs, DefaultStorageTruthReporterIneligibleDurationEpochs, + DefaultStorageTruthStrongRecoveryCleanPassCount, + DefaultStorageTruthHealVerifierCount, ) } @@ -479,6 +489,12 @@ func (p Params) WithDefaults() Params { if p.StorageTruthRecoveryCleanPassCount == 0 { p.StorageTruthRecoveryCleanPassCount = DefaultStorageTruthRecoveryCleanPassCount } + if p.StorageTruthStrongRecoveryCleanPassCount == 0 { + p.StorageTruthStrongRecoveryCleanPassCount = DefaultStorageTruthStrongRecoveryCleanPassCount + } + if p.StorageTruthHealVerifierCount == 0 { + p.StorageTruthHealVerifierCount = DefaultStorageTruthHealVerifierCount + } if p.StorageTruthClassAFaultWindow == 0 { p.StorageTruthClassAFaultWindow = DefaultStorageTruthClassAFaultWindow } @@ -549,6 +565,8 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyStorageTruthReporterMinReportsForDivergence, &p.StorageTruthReporterMinReportsForDivergence, validateUint32), paramtypes.NewParamSetPair(KeyStorageTruthNodeSuspicionThresholdStrongPostpone, &p.StorageTruthNodeSuspicionThresholdStrongPostpone, validateInt64), paramtypes.NewParamSetPair(KeyStorageTruthRecoveryCleanPassCount, &p.StorageTruthRecoveryCleanPassCount, validateUint32), + paramtypes.NewParamSetPair(KeyStorageTruthStrongRecoveryCleanPassCount, &p.StorageTruthStrongRecoveryCleanPassCount, validateUint32), + paramtypes.NewParamSetPair(KeyStorageTruthHealVerifierCount, &p.StorageTruthHealVerifierCount, validateUint32), paramtypes.NewParamSetPair(KeyStorageTruthClassAFaultWindow, &p.StorageTruthClassAFaultWindow, validateUint32), paramtypes.NewParamSetPair(KeyStorageTruthClassBFaultWindow, &p.StorageTruthClassBFaultWindow, validateUint32), paramtypes.NewParamSetPair(KeyStorageTruthHealDeadlineEpochs, &p.StorageTruthHealDeadlineEpochs, validateUint32), @@ -740,6 +758,9 @@ func (p Params) Validate() error { if p.StorageTruthRecoveryCleanPassCount == 0 { return fmt.Errorf("storage_truth_recovery_clean_pass_count must be > 0") } + if p.StorageTruthHealVerifierCount == 0 { + return fmt.Errorf("storage_truth_heal_verifier_count must be > 0") + } if p.StorageTruthClassBFaultWindow == 0 { return fmt.Errorf("storage_truth_class_b_fault_window must be > 0") } diff --git a/x/audit/v1/types/params.pb.go b/x/audit/v1/types/params.pb.go index 49d63553..afd3a23e 100644 --- a/x/audit/v1/types/params.pb.go +++ b/x/audit/v1/types/params.pb.go @@ -147,6 +147,12 @@ type Params struct { StorageTruthContradictionWindowEpochs uint32 `protobuf:"varint,48,opt,name=storage_truth_contradiction_window_epochs,json=storageTruthContradictionWindowEpochs,proto3" json:"storage_truth_contradiction_window_epochs,omitempty"` // Reporter challenger ineligibility duration in epochs (default 7). StorageTruthReporterIneligibleDurationEpochs uint32 `protobuf:"varint,49,opt,name=storage_truth_reporter_ineligible_duration_epochs,json=storageTruthReporterIneligibleDurationEpochs,proto3" json:"storage_truth_reporter_ineligible_duration_epochs,omitempty"` + // Strong-band recovery clean-pass requirement (F121-F12, default 5). + StorageTruthStrongRecoveryCleanPassCount uint32 `protobuf:"varint,50,opt,name=storage_truth_strong_recovery_clean_pass_count,json=storageTruthStrongRecoveryCleanPassCount,proto3" json:"storage_truth_strong_recovery_clean_pass_count,omitempty"` + // Number of verifier supernodes assigned per heal-op (NEW-B-3, default 2). + // Verifiers cross-check the healer's recovery; making this a Param allows + // governance to tune redundancy if heal volume / failure rate shifts. + StorageTruthHealVerifierCount uint32 `protobuf:"varint,51,opt,name=storage_truth_heal_verifier_count,json=storageTruthHealVerifierCount,proto3" json:"storage_truth_heal_verifier_count,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -525,6 +531,20 @@ func (m *Params) GetStorageTruthReporterIneligibleDurationEpochs() uint32 { return 0 } +func (m *Params) GetStorageTruthStrongRecoveryCleanPassCount() uint32 { + if m != nil { + return m.StorageTruthStrongRecoveryCleanPassCount + } + return 0 +} + +func (m *Params) GetStorageTruthHealVerifierCount() uint32 { + if m != nil { + return m.StorageTruthHealVerifierCount + } + return 0 +} + func init() { proto.RegisterEnum("lumera.audit.v1.StorageTruthEnforcementMode", StorageTruthEnforcementMode_name, StorageTruthEnforcementMode_value) proto.RegisterType((*Params)(nil), "lumera.audit.v1.Params") @@ -533,106 +553,109 @@ func init() { func init() { proto.RegisterFile("lumera/audit/v1/params.proto", fileDescriptor_3788ca0fc7eb9d86) } var fileDescriptor_3788ca0fc7eb9d86 = []byte{ - // 1581 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x58, 0xdd, 0x72, 0x1b, 0xb7, - 0x15, 0x16, 0x23, 0xd7, 0x4d, 0xd0, 0x26, 0x96, 0xd6, 0x72, 0xbd, 0xb5, 0x62, 0x86, 0x96, 0x62, - 0x4b, 0x96, 0x15, 0x52, 0xb2, 0x9b, 0xa6, 0xed, 0xf4, 0x46, 0xe2, 0x4f, 0xa5, 0x56, 0x14, 0x19, - 0x92, 0x1a, 0xb7, 0x99, 0x76, 0x30, 0xe0, 0xee, 0x21, 0x89, 0x6a, 0x09, 0xac, 0x01, 0x2c, 0x25, - 0xe5, 0x29, 0xfa, 0x08, 0x9d, 0xe9, 0xcb, 0x74, 0x7a, 0x95, 0xcb, 0x5e, 0x76, 0xec, 0x9b, 0x3e, - 0x46, 0x07, 0xd8, 0x1f, 0xee, 0x2e, 0xc9, 0x92, 0x37, 0xb6, 0xc4, 0xf3, 0xfd, 0x00, 0xe7, 0xe0, - 0x1c, 0x40, 0x44, 0x9f, 0x7b, 0xc1, 0x18, 0x04, 0xa9, 0x90, 0xc0, 0xa5, 0xaa, 0x32, 0x39, 0xae, - 0xf8, 0x44, 0x90, 0xb1, 0x2c, 0xfb, 0x82, 0x2b, 0x6e, 0x3d, 0x08, 0xa3, 0x65, 0x13, 0x2d, 0x4f, - 0x8e, 0x9f, 0x6c, 0x92, 0x31, 0x65, 0xbc, 0x62, 0xfe, 0x0d, 0x31, 0x4f, 0xb6, 0x86, 0x7c, 0xc8, - 0xcd, 0x8f, 0x15, 0xfd, 0x53, 0xf8, 0xe9, 0xce, 0x3f, 0x4a, 0xe8, 0x7e, 0xdb, 0x48, 0x59, 0x65, - 0xf4, 0x10, 0x7c, 0xee, 0x8c, 0xb0, 0x07, 0x6c, 0xa8, 0x46, 0xb8, 0xef, 0x71, 0xe7, 0x5a, 0xda, - 0x85, 0x52, 0x61, 0xff, 0x5e, 0x67, 0xd3, 0x84, 0x2e, 0x4c, 0xe4, 0xd4, 0x04, 0xac, 0x03, 0x14, - 0x7e, 0x88, 0xbf, 0x07, 0xc1, 0xf1, 0x08, 0xe8, 0x70, 0xa4, 0xec, 0x8f, 0x0c, 0xfa, 0x81, 0x09, - 0x7c, 0x07, 0x82, 0x9f, 0x99, 0x8f, 0xb5, 0xb6, 0x0f, 0x20, 0xf0, 0xbb, 0x80, 0x8b, 0x60, 0x8c, - 0x05, 0xf8, 0x5c, 0x28, 0x69, 0xaf, 0x97, 0x0a, 0xfb, 0x9f, 0x76, 0x36, 0x75, 0xe8, 0x5b, 0x13, - 0xe9, 0x84, 0x01, 0xeb, 0xb7, 0x68, 0x7b, 0x4c, 0x19, 0xf6, 0x05, 0xef, 0x03, 0x56, 0x44, 0x0c, - 0x41, 0x49, 0xec, 0x83, 0xc0, 0x46, 0xd8, 0xbe, 0x67, 0x78, 0x8f, 0xc7, 0x94, 0xb5, 0x35, 0xa2, - 0x17, 0x02, 0xda, 0x20, 0xea, 0x3a, 0x6c, 0xd8, 0xe4, 0x76, 0x21, 0xfb, 0x47, 0x11, 0x9b, 0xdc, - 0xce, 0x65, 0x97, 0xd1, 0x43, 0x01, 0xef, 0x02, 0x2a, 0xc0, 0xc5, 0xdc, 0x07, 0x86, 0xc3, 0xb5, - 0xde, 0x2f, 0xad, 0xeb, 0xb5, 0xc6, 0xa1, 0x96, 0x0f, 0xac, 0x6d, 0xd6, 0x5a, 0x41, 0x5b, 0x7a, - 0xad, 0x8e, 0x1f, 0xe0, 0x81, 0x00, 0xd0, 0x46, 0x0e, 0x30, 0x65, 0xff, 0x38, 0xdc, 0xdc, 0x98, - 0xb2, 0xaa, 0x1f, 0x34, 0x04, 0x40, 0x3b, 0x0c, 0xc4, 0x84, 0x31, 0x8c, 0xb3, 0x84, 0x8f, 0x13, - 0x42, 0x13, 0xc6, 0x69, 0xc2, 0x31, 0x7a, 0xa4, 0x09, 0x2e, 0x95, 0xd7, 0x59, 0xc6, 0x27, 0x86, - 0x61, 0x8d, 0x29, 0xab, 0x51, 0x79, 0x9d, 0xa6, 0x54, 0x51, 0xd1, 0xe1, 0x4c, 0x82, 0x13, 0x28, - 0x3a, 0x81, 0x70, 0xe3, 0x12, 0x2b, 0x8e, 0x7d, 0x2e, 0x95, 0xcf, 0x19, 0xd8, 0xc8, 0x70, 0xb7, - 0x53, 0x28, 0xb3, 0x7d, 0xd9, 0xe3, 0xed, 0x08, 0x62, 0x7d, 0x8d, 0x1e, 0x5f, 0x03, 0xf8, 0xd8, - 0x23, 0x52, 0x85, 0x12, 0x18, 0x98, 0x12, 0x14, 0xa4, 0xfd, 0x13, 0x53, 0xe7, 0x2d, 0x1d, 0xbe, - 0x20, 0x52, 0x19, 0x6a, 0x3d, 0x8c, 0x59, 0x97, 0xe8, 0x4b, 0x53, 0x6c, 0x9d, 0xb7, 0xc4, 0x0f, - 0xab, 0x91, 0x00, 0x39, 0xe2, 0x9e, 0x9b, 0xac, 0xfe, 0xa7, 0x66, 0x05, 0x25, 0x8d, 0xd5, 0x99, - 0x8c, 0x6d, 0x7b, 0x31, 0x30, 0xde, 0xcb, 0x04, 0xfd, 0x9a, 0x38, 0x8a, 0x72, 0x86, 0x07, 0x94, - 0x11, 0x8f, 0x7e, 0x4f, 0xcc, 0x2f, 0x92, 0x0e, 0x19, 0x51, 0x81, 0x00, 0x3c, 0x20, 0xd4, 0xd3, - 0xff, 0xc3, 0x84, 0xba, 0xc0, 0x1c, 0x48, 0x17, 0xfb, 0x53, 0x63, 0xf2, 0x26, 0x14, 0x68, 0xa4, - 0xf8, 0xdd, 0x98, 0xde, 0x08, 0xd9, 0xf5, 0x98, 0x9c, 0x1c, 0x84, 0x00, 0xfd, 0x6a, 0x35, 0xdf, - 0xd9, 0x4c, 0xdb, 0x9f, 0xad, 0x6a, 0x5b, 0xcd, 0xe7, 0xdf, 0xba, 0x46, 0xbf, 0x98, 0x67, 0xcb, - 0xb8, 0xc2, 0x94, 0x61, 0xc5, 0xfd, 0xe3, 0xa3, 0xb9, 0x3b, 0x7d, 0x60, 0x2c, 0xbf, 0x9a, 0xb5, - 0xbc, 0xe4, 0xea, 0x9c, 0xf5, 0x34, 0x6f, 0x76, 0x8f, 0x7f, 0x45, 0x6f, 0x96, 0x9a, 0xcd, 0xd9, - 0xde, 0xc6, 0x72, 0xaf, 0xd9, 0x8d, 0x35, 0xd1, 0xee, 0x3c, 0x2f, 0x01, 0x0e, 0x9f, 0x80, 0xb8, - 0x8b, 0xb5, 0x37, 0xc3, 0x63, 0x31, 0xab, 0xdd, 0x89, 0x80, 0x91, 0x9c, 0x37, 0x3f, 0x4f, 0x89, - 0x9c, 0x1e, 0x01, 0x8a, 0x2b, 0xe2, 0xe1, 0x3e, 0x71, 0xa7, 0x19, 0xb3, 0x2d, 0xa3, 0x5f, 0x5e, - 0xac, 0xdf, 0x24, 0xb7, 0x3d, 0xcd, 0x3b, 0x25, 0x6e, 0x92, 0x30, 0xeb, 0x29, 0x42, 0xd2, 0xc1, - 0xc0, 0x48, 0xdf, 0x03, 0xd7, 0x7e, 0x58, 0x2a, 0xec, 0x7f, 0xdc, 0xf9, 0x44, 0x3a, 0xf5, 0xf0, - 0x03, 0xeb, 0x1b, 0x64, 0x4b, 0x07, 0x3b, 0x23, 0xe2, 0xe9, 0xe9, 0x09, 0x22, 0x5d, 0x98, 0x2d, - 0x63, 0xf8, 0x48, 0x3a, 0xd5, 0x69, 0x38, 0x29, 0xc0, 0xb7, 0xe8, 0x85, 0x54, 0x5c, 0x90, 0x21, - 0x60, 0x25, 0x02, 0x35, 0xd2, 0xeb, 0x07, 0xa6, 0x70, 0x3f, 0x70, 0xae, 0x41, 0x99, 0x4d, 0x44, - 0x83, 0xf8, 0x91, 0x69, 0xb9, 0x67, 0x11, 0xba, 0xa7, 0xc1, 0x1d, 0x83, 0x3d, 0x35, 0xd0, 0x26, - 0xb9, 0x8d, 0x06, 0xf3, 0x1f, 0xd0, 0x6e, 0x56, 0x52, 0x37, 0x5d, 0xac, 0x47, 0x59, 0xac, 0xf7, - 0x33, 0xa3, 0x57, 0x4c, 0xeb, 0xb5, 0x3c, 0x37, 0x12, 0xa3, 0x2c, 0x12, 0xeb, 0xe4, 0xd7, 0x97, - 0xec, 0x31, 0x9a, 0xac, 0xd8, 0xa5, 0x13, 0x2a, 0xb9, 0xb0, 0x1f, 0x9b, 0x6d, 0xee, 0xa4, 0xf5, - 0x92, 0x0d, 0x87, 0x33, 0xb6, 0x16, 0x22, 0xad, 0x3f, 0xa1, 0x83, 0x9c, 0x26, 0x1f, 0xfb, 0x3c, - 0x60, 0x2e, 0x16, 0x84, 0x0d, 0xa3, 0x43, 0x4d, 0x84, 0xa2, 0x03, 0xe2, 0x28, 0xdb, 0x36, 0xba, - 0xcf, 0x33, 0xba, 0x11, 0xbe, 0x63, 0xe0, 0x6d, 0x10, 0x27, 0x11, 0x78, 0x36, 0x9d, 0x59, 0x69, - 0x7d, 0xb7, 0xe1, 0xfe, 0x9d, 0x02, 0x69, 0xff, 0xdc, 0xc8, 0x3e, 0x5b, 0x28, 0x7b, 0x01, 0xec, - 0x54, 0x03, 0xad, 0x2b, 0xf4, 0x32, 0x2b, 0xa9, 0x6b, 0x22, 0xc1, 0x1b, 0xe0, 0x11, 0x10, 0x0f, - 0x73, 0x3f, 0x5d, 0xeb, 0x27, 0xb3, 0x49, 0x68, 0x92, 0xdb, 0x2e, 0x78, 0x83, 0x33, 0x20, 0x5e, - 0xcb, 0x9f, 0x16, 0xbe, 0x8a, 0x8a, 0x59, 0x59, 0x7d, 0x5d, 0x85, 0x47, 0x38, 0x6a, 0x84, 0xed, - 0x70, 0x42, 0xa7, 0xb5, 0xda, 0x31, 0x26, 0xea, 0x81, 0x3f, 0xa3, 0xc3, 0xac, 0x08, 0xe3, 0x2e, - 0x60, 0x19, 0x48, 0x9f, 0x3a, 0x5a, 0xc9, 0x05, 0x87, 0xdc, 0xa5, 0x96, 0xf7, 0x79, 0xa9, 0xb0, - 0xbf, 0xde, 0x79, 0x91, 0x96, 0xbc, 0xe4, 0x2e, 0x74, 0x63, 0x42, 0x4d, 0xe3, 0x93, 0x25, 0x8e, - 0xd0, 0xeb, 0xfc, 0xd9, 0xd4, 0x33, 0x1d, 0x04, 0x16, 0xe0, 0x51, 0xd2, 0xa7, 0x1e, 0x55, 0x77, - 0x33, 0x1e, 0x4f, 0x8d, 0xc7, 0x61, 0xf6, 0x9c, 0x86, 0xbc, 0xce, 0x94, 0xb6, 0xc4, 0x49, 0x51, - 0x73, 0x5c, 0x5d, 0x50, 0x20, 0x28, 0x17, 0x61, 0x5e, 0xf2, 0x4e, 0xc5, 0x59, 0xa7, 0x9e, 0xe1, - 0xd5, 0xd2, 0xb4, 0xac, 0xd3, 0x5f, 0x96, 0x64, 0x6c, 0x7a, 0x4d, 0xdd, 0x10, 0xe5, 0x8c, 0xec, - 0x2f, 0x8c, 0xc7, 0xde, 0xc2, 0x8c, 0x25, 0xb7, 0xd5, 0x5b, 0x0d, 0xb7, 0x00, 0x1d, 0xad, 0x28, - 0x9f, 0x94, 0xdb, 0x2e, 0x19, 0x8b, 0x57, 0xcb, 0x2d, 0x92, 0xea, 0x5b, 0x0e, 0xaa, 0xac, 0x6a, - 0x13, 0xdf, 0xf7, 0xcf, 0x8c, 0xcb, 0xc1, 0x0a, 0x2e, 0xf1, 0xf5, 0xef, 0xa3, 0x5f, 0xae, 0x50, - 0x7e, 0x8f, 0xdf, 0xe8, 0xb0, 0x54, 0x53, 0x53, 0x7b, 0xc7, 0x78, 0x1d, 0x2d, 0x39, 0x02, 0x17, - 0xfc, 0xa6, 0xa7, 0x89, 0x89, 0xb3, 0x25, 0xd1, 0x37, 0x2b, 0x38, 0x52, 0x06, 0x1e, 0x1d, 0xd2, - 0xbe, 0x97, 0x7a, 0x54, 0xd8, 0xbb, 0xc6, 0xf2, 0xf5, 0x12, 0xcb, 0xf3, 0x84, 0x3a, 0x35, 0x1d, - 0xa2, 0xe3, 0x15, 0xce, 0x9e, 0xe9, 0xf5, 0xa9, 0xdd, 0x97, 0x2b, 0x1d, 0x3d, 0xdd, 0xf3, 0x53, - 0xa3, 0x77, 0xf9, 0x8e, 0x07, 0x36, 0xe0, 0xc2, 0x81, 0xb1, 0x9e, 0xf7, 0x63, 0xee, 0x82, 0xfd, - 0xbc, 0x54, 0xd8, 0xff, 0xec, 0xf5, 0x61, 0x39, 0xf7, 0x9c, 0x2f, 0x77, 0x53, 0x36, 0xf5, 0x29, - 0xa9, 0xc9, 0x5d, 0xc8, 0xce, 0x87, 0x5c, 0xd0, 0xe2, 0xe8, 0xeb, 0x95, 0x3a, 0x78, 0x28, 0x88, - 0x0b, 0x6e, 0x6a, 0x7f, 0x2f, 0x56, 0xaa, 0x60, 0x2d, 0x22, 0x4e, 0xf7, 0xd8, 0x43, 0x7b, 0xb9, - 0xa9, 0x46, 0x94, 0x02, 0xc1, 0x30, 0x48, 0x87, 0x78, 0x61, 0x2a, 0x6f, 0x28, 0x73, 0xf9, 0x8d, - 0xbd, 0x67, 0xc6, 0xdb, 0x6e, 0x66, 0xbc, 0x85, 0xe0, 0x7a, 0x82, 0x7d, 0x6b, 0xa0, 0xb3, 0x97, - 0x90, 0x4b, 0x27, 0x20, 0x86, 0xfa, 0x66, 0x8e, 0xd4, 0xe2, 0x99, 0xb9, 0x3f, 0x3b, 0x7f, 0x6b, - 0x09, 0x36, 0x54, 0x8b, 0x46, 0xe7, 0x20, 0x5f, 0xf6, 0x24, 0x35, 0xfa, 0x8e, 0x8c, 0xfe, 0x42, - 0xc1, 0x03, 0x2e, 0x52, 0x66, 0xf6, 0x4b, 0x23, 0xff, 0x6a, 0x5e, 0x5a, 0x9a, 0x94, 0x45, 0x7f, - 0xbd, 0x34, 0xb8, 0x98, 0x7a, 0xce, 0x76, 0xd1, 0xc2, 0x56, 0x95, 0x4a, 0x70, 0x36, 0x9c, 0x76, - 0xec, 0xc1, 0x6c, 0x0d, 0xe6, 0x77, 0x6c, 0xd7, 0x10, 0x93, 0xbe, 0xed, 0xe6, 0x6b, 0x90, 0x3c, - 0x89, 0x1c, 0x0f, 0x08, 0xc3, 0x3e, 0x91, 0x12, 0x3b, 0x3c, 0x60, 0xca, 0x7e, 0x35, 0x9b, 0xae, - 0xf8, 0x15, 0x54, 0xd5, 0xd8, 0x36, 0x91, 0xb2, 0xaa, 0x91, 0xd6, 0x39, 0xda, 0xc9, 0x5d, 0xac, - 0x9e, 0x96, 0x21, 0x78, 0x40, 0x02, 0x4f, 0xc5, 0x35, 0x3d, 0x34, 0x7a, 0x4f, 0x33, 0x97, 0xaa, - 0xc6, 0x9d, 0x34, 0x34, 0x2a, 0xaa, 0xe6, 0x02, 0xa9, 0x7e, 0x56, 0xea, 0xab, 0x05, 0x52, 0xa7, - 0x69, 0xa9, 0xdf, 0xe7, 0xa5, 0x4c, 0x9b, 0xba, 0x40, 0x5c, 0x8f, 0xb2, 0xe4, 0xb5, 0x5a, 0x36, - 0x52, 0x99, 0x97, 0x8e, 0xee, 0xcc, 0x5a, 0x04, 0x8b, 0x0e, 0x44, 0x3b, 0x7f, 0xc8, 0x74, 0x4d, - 0xe6, 0xee, 0xb2, 0x12, 0xbe, 0x50, 0x73, 0x2f, 0xa7, 0xd9, 0x8d, 0xfe, 0x31, 0xff, 0x72, 0x70, - 0x38, 0x53, 0x82, 0xb8, 0xd4, 0x49, 0xf5, 0x41, 0xbc, 0xc8, 0xa3, 0x79, 0xcf, 0x9c, 0x14, 0x3c, - 0x73, 0x78, 0x87, 0x0b, 0x0f, 0x6f, 0x6a, 0x38, 0xba, 0x81, 0xc8, 0xbc, 0x27, 0x8e, 0x8d, 0xc3, - 0xdc, 0x8b, 0x79, 0x3a, 0x17, 0x6b, 0x11, 0x29, 0x34, 0xfa, 0xcd, 0xbd, 0xff, 0xfe, 0xfd, 0x8b, - 0xc2, 0xc1, 0xbf, 0x0a, 0x68, 0xfb, 0xff, 0xcc, 0x20, 0xab, 0x8c, 0x0e, 0xba, 0xbd, 0x56, 0xe7, - 0xe4, 0x77, 0x75, 0xdc, 0xeb, 0x5c, 0xf5, 0xce, 0x70, 0xfd, 0xb2, 0xd1, 0xea, 0x54, 0xeb, 0xcd, - 0xfa, 0x65, 0x0f, 0x37, 0x5b, 0xb5, 0x3a, 0xbe, 0xba, 0xec, 0xb6, 0xeb, 0xd5, 0xf3, 0xc6, 0x79, - 0xbd, 0xb6, 0xb1, 0x66, 0xbd, 0x44, 0xcf, 0x97, 0xe0, 0xbb, 0x67, 0x27, 0xb5, 0xd6, 0xdb, 0x8d, - 0x82, 0xb5, 0x87, 0x76, 0x97, 0x41, 0x5b, 0x8d, 0xde, 0xc6, 0x47, 0x2b, 0x00, 0x1b, 0x57, 0x17, - 0x17, 0x1b, 0xeb, 0xa7, 0x07, 0xff, 0x7c, 0x5f, 0x2c, 0xfc, 0xf0, 0xbe, 0x58, 0xf8, 0xcf, 0xfb, - 0x62, 0xe1, 0x6f, 0x1f, 0x8a, 0x6b, 0x3f, 0x7c, 0x28, 0xae, 0xfd, 0xfb, 0x43, 0x71, 0xed, 0xbb, - 0x8d, 0xdb, 0xe9, 0xf7, 0x2b, 0xea, 0xce, 0x07, 0xd9, 0xbf, 0x6f, 0xbe, 0x25, 0x79, 0xf3, 0xbf, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xec, 0x3b, 0xb1, 0x68, 0x7f, 0x11, 0x00, 0x00, + // 1620 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x58, 0x5b, 0x77, 0x1b, 0x39, + 0x1d, 0xaf, 0xb7, 0xa5, 0xec, 0x0a, 0x76, 0x9b, 0x4e, 0x5b, 0x3a, 0xb4, 0x5b, 0xaf, 0xd3, 0x6c, + 0xdb, 0x34, 0xed, 0xda, 0xb9, 0xb0, 0x2c, 0x70, 0x78, 0x49, 0x7c, 0x21, 0x81, 0x38, 0xf6, 0xda, + 0x0e, 0x85, 0x3d, 0x70, 0x84, 0x3c, 0xf3, 0xb7, 0x2d, 0x32, 0x96, 0xa6, 0x92, 0xc6, 0x49, 0xf6, + 0x53, 0xf0, 0x11, 0xf8, 0x38, 0x1c, 0x5e, 0xe8, 0x23, 0x8f, 0x9c, 0xf6, 0x85, 0x8f, 0xc1, 0x91, + 0xe6, 0xe2, 0xb9, 0xd8, 0xd8, 0x2f, 0x6d, 0xe2, 0xff, 0xef, 0x22, 0xe9, 0x7f, 0x91, 0x62, 0xf4, + 0xb9, 0x17, 0x4c, 0x41, 0x90, 0x1a, 0x09, 0x5c, 0xaa, 0x6a, 0xb3, 0xbd, 0x9a, 0x4f, 0x04, 0x99, + 0xca, 0xaa, 0x2f, 0xb8, 0xe2, 0xd6, 0x9d, 0x30, 0x5a, 0x35, 0xd1, 0xea, 0x6c, 0xef, 0xd1, 0x5d, + 0x32, 0xa5, 0x8c, 0xd7, 0xcc, 0xbf, 0x21, 0xe6, 0xd1, 0xfd, 0x31, 0x1f, 0x73, 0xf3, 0x63, 0x4d, + 0xff, 0x14, 0x7e, 0xfa, 0xf4, 0x5f, 0x9b, 0xe8, 0x76, 0xd7, 0x48, 0x59, 0x55, 0x74, 0x0f, 0x7c, + 0xee, 0x4c, 0xb0, 0x07, 0x6c, 0xac, 0x26, 0x78, 0xe8, 0x71, 0xe7, 0x42, 0xda, 0xa5, 0x4a, 0x69, + 0xfb, 0x56, 0xef, 0xae, 0x09, 0x9d, 0x9a, 0xc8, 0x91, 0x09, 0x58, 0x3b, 0x28, 0xfc, 0x10, 0x7f, + 0x0f, 0x82, 0xe3, 0x09, 0xd0, 0xf1, 0x44, 0xd9, 0x1f, 0x19, 0xf4, 0x1d, 0x13, 0xf8, 0x0e, 0x04, + 0x3f, 0x36, 0x1f, 0x6b, 0x6d, 0x1f, 0x40, 0xe0, 0xb7, 0x01, 0x17, 0xc1, 0x14, 0x0b, 0xf0, 0xb9, + 0x50, 0xd2, 0xbe, 0x59, 0x29, 0x6d, 0x7f, 0xda, 0xbb, 0xab, 0x43, 0xdf, 0x9a, 0x48, 0x2f, 0x0c, + 0x58, 0xbf, 0x46, 0x8f, 0xa7, 0x94, 0x61, 0x5f, 0xf0, 0x21, 0x60, 0x45, 0xc4, 0x18, 0x94, 0xc4, + 0x3e, 0x08, 0x6c, 0x84, 0xed, 0x5b, 0x86, 0xf7, 0x70, 0x4a, 0x59, 0x57, 0x23, 0x06, 0x21, 0xa0, + 0x0b, 0xa2, 0xa9, 0xc3, 0x86, 0x4d, 0xae, 0x96, 0xb2, 0x7f, 0x10, 0xb1, 0xc9, 0xd5, 0x42, 0x76, + 0x15, 0xdd, 0x13, 0xf0, 0x36, 0xa0, 0x02, 0x5c, 0xcc, 0x7d, 0x60, 0x38, 0x5c, 0xeb, 0xed, 0xca, + 0x4d, 0xbd, 0xd6, 0x38, 0xd4, 0xf1, 0x81, 0x75, 0xcd, 0x5a, 0x6b, 0xe8, 0xbe, 0x5e, 0xab, 0xe3, + 0x07, 0x78, 0x24, 0x00, 0xb4, 0x91, 0x03, 0x4c, 0xd9, 0x3f, 0x0c, 0x37, 0x37, 0xa5, 0xac, 0xee, + 0x07, 0x2d, 0x01, 0xd0, 0x0d, 0x03, 0x31, 0x61, 0x0a, 0xd3, 0x2c, 0xe1, 0xe3, 0x84, 0xd0, 0x86, + 0x69, 0x9a, 0xb0, 0x87, 0x1e, 0x68, 0x82, 0x4b, 0xe5, 0x45, 0x96, 0xf1, 0x89, 0x61, 0x58, 0x53, + 0xca, 0x1a, 0x54, 0x5e, 0xa4, 0x29, 0x75, 0x54, 0x76, 0x38, 0x93, 0xe0, 0x04, 0x8a, 0xce, 0x20, + 0xdc, 0xb8, 0xc4, 0x8a, 0x63, 0x9f, 0x4b, 0xe5, 0x73, 0x06, 0x36, 0x32, 0xdc, 0xc7, 0x29, 0x94, + 0xd9, 0xbe, 0x1c, 0xf0, 0x6e, 0x04, 0xb1, 0xbe, 0x46, 0x0f, 0x2f, 0x00, 0x7c, 0xec, 0x11, 0xa9, + 0x42, 0x09, 0x0c, 0x4c, 0x09, 0x0a, 0xd2, 0xfe, 0x91, 0xc9, 0xf3, 0x7d, 0x1d, 0x3e, 0x25, 0x52, + 0x19, 0x6a, 0x33, 0x8c, 0x59, 0x67, 0xe8, 0x4b, 0x93, 0x6c, 0x7d, 0x6e, 0x89, 0x1f, 0x56, 0x13, + 0x01, 0x72, 0xc2, 0x3d, 0x37, 0x59, 0xfd, 0x8f, 0xcd, 0x0a, 0x2a, 0x1a, 0xab, 0x4f, 0x32, 0xb6, + 0x1d, 0xc4, 0xc0, 0x78, 0x2f, 0x33, 0xf4, 0x4b, 0xe2, 0x28, 0xca, 0x19, 0x1e, 0x51, 0x46, 0x3c, + 0xfa, 0x3d, 0x31, 0xbf, 0x48, 0x3a, 0x66, 0x44, 0x05, 0x02, 0xf0, 0x88, 0x50, 0x4f, 0xff, 0x0f, + 0x33, 0xea, 0x02, 0x73, 0x20, 0x9d, 0xec, 0x4f, 0x8d, 0xc9, 0x41, 0x28, 0xd0, 0x4a, 0xf1, 0xfb, + 0x31, 0xbd, 0x15, 0xb2, 0x9b, 0x31, 0x39, 0x29, 0x84, 0x00, 0xfd, 0x62, 0x3d, 0xdf, 0xe2, 0x49, + 0xdb, 0x9f, 0xad, 0x6b, 0x5b, 0xcf, 0x9f, 0xbf, 0x75, 0x81, 0x7e, 0xb6, 0xc8, 0x96, 0x71, 0x85, + 0x29, 0xc3, 0x8a, 0xfb, 0x7b, 0xbb, 0x0b, 0x77, 0x7a, 0xc7, 0x58, 0x7e, 0x55, 0xb4, 0x3c, 0xe3, + 0xea, 0x84, 0x0d, 0x34, 0xaf, 0xb8, 0xc7, 0xbf, 0xa2, 0x83, 0x95, 0x66, 0x0b, 0xb6, 0xb7, 0xb1, + 0xda, 0xab, 0xb8, 0xb1, 0x36, 0xda, 0x5a, 0xe4, 0x25, 0xc0, 0xe1, 0x33, 0x10, 0xd7, 0xb1, 0xf6, + 0xdd, 0xb0, 0x2c, 0x8a, 0xda, 0xbd, 0x08, 0x18, 0xc9, 0x79, 0x8b, 0xcf, 0x29, 0x91, 0xd3, 0x23, + 0x40, 0x71, 0x45, 0x3c, 0x3c, 0x24, 0xee, 0xfc, 0xc4, 0x6c, 0xcb, 0xe8, 0x57, 0x97, 0xeb, 0xb7, + 0xc9, 0xd5, 0x40, 0xf3, 0x8e, 0x88, 0x9b, 0x1c, 0x98, 0xf5, 0x04, 0x21, 0xe9, 0x60, 0x60, 0x64, + 0xe8, 0x81, 0x6b, 0xdf, 0xab, 0x94, 0xb6, 0x3f, 0xee, 0x7d, 0x22, 0x9d, 0x66, 0xf8, 0x81, 0xf5, + 0x0d, 0xb2, 0xa5, 0x83, 0x9d, 0x09, 0xf1, 0xf4, 0xf4, 0x04, 0x91, 0x4e, 0xcc, 0x7d, 0x63, 0xf8, + 0x40, 0x3a, 0xf5, 0x79, 0x38, 0x49, 0xc0, 0xb7, 0xe8, 0xb9, 0x54, 0x5c, 0x90, 0x31, 0x60, 0x25, + 0x02, 0x35, 0xd1, 0xeb, 0x07, 0xa6, 0xf0, 0x30, 0x70, 0x2e, 0x40, 0x99, 0x4d, 0x44, 0x83, 0xf8, + 0x81, 0x69, 0xb9, 0xcd, 0x08, 0x3d, 0xd0, 0xe0, 0x9e, 0xc1, 0x1e, 0x19, 0x68, 0x9b, 0x5c, 0x45, + 0x83, 0xf9, 0x77, 0x68, 0x2b, 0x2b, 0xa9, 0x9b, 0x2e, 0xd6, 0xa3, 0x2c, 0xd6, 0xfb, 0x89, 0xd1, + 0x2b, 0xa7, 0xf5, 0x3a, 0x9e, 0x1b, 0x89, 0x51, 0x16, 0x89, 0xf5, 0xf2, 0xeb, 0x4b, 0xf6, 0x18, + 0x4d, 0x56, 0xec, 0xd2, 0x19, 0x95, 0x5c, 0xd8, 0x0f, 0xcd, 0x36, 0x9f, 0xa6, 0xf5, 0x92, 0x0d, + 0x87, 0x33, 0xb6, 0x11, 0x22, 0xad, 0x3f, 0xa2, 0x9d, 0x9c, 0x26, 0x9f, 0xfa, 0x3c, 0x60, 0x2e, + 0x16, 0x84, 0x8d, 0xa3, 0xa2, 0x26, 0x42, 0xd1, 0x11, 0x71, 0x94, 0x6d, 0x1b, 0xdd, 0x67, 0x19, + 0xdd, 0x08, 0xdf, 0x33, 0xf0, 0x2e, 0x88, 0xc3, 0x08, 0x5c, 0x3c, 0xce, 0xac, 0xb4, 0xbe, 0xdb, + 0xf0, 0xf0, 0x5a, 0x81, 0xb4, 0x7f, 0x6a, 0x64, 0x37, 0x97, 0xca, 0x9e, 0x02, 0x3b, 0xd2, 0x40, + 0xeb, 0x1c, 0xbd, 0xcc, 0x4a, 0xea, 0x9c, 0x48, 0xf0, 0x46, 0x78, 0x02, 0xc4, 0xc3, 0xdc, 0x4f, + 0xe7, 0xfa, 0x51, 0xf1, 0x10, 0xda, 0xe4, 0xaa, 0x0f, 0xde, 0xe8, 0x18, 0x88, 0xd7, 0xf1, 0xe7, + 0x89, 0xaf, 0xa3, 0x72, 0x56, 0x56, 0x5f, 0x57, 0x61, 0x09, 0x47, 0x8d, 0xf0, 0x38, 0x9c, 0xd0, + 0x69, 0xad, 0x6e, 0x8c, 0x89, 0x7a, 0xe0, 0x4f, 0xe8, 0x75, 0x56, 0x84, 0x71, 0x17, 0xb0, 0x0c, + 0xa4, 0x4f, 0x1d, 0xad, 0xe4, 0x82, 0x43, 0xae, 0x53, 0xcb, 0xfb, 0xbc, 0x52, 0xda, 0xbe, 0xd9, + 0x7b, 0x9e, 0x96, 0x3c, 0xe3, 0x2e, 0xf4, 0x63, 0x42, 0x43, 0xe3, 0x93, 0x25, 0x4e, 0xd0, 0x7e, + 0xbe, 0x36, 0xf5, 0x4c, 0x07, 0x81, 0x05, 0x78, 0x94, 0x0c, 0xa9, 0x47, 0xd5, 0x75, 0xc1, 0xe3, + 0x89, 0xf1, 0x78, 0x9d, 0xad, 0xd3, 0x90, 0xd7, 0x9b, 0xd3, 0x56, 0x38, 0x29, 0x6a, 0xca, 0xd5, + 0x05, 0x05, 0x82, 0x72, 0x11, 0x9e, 0x4b, 0xde, 0xa9, 0x5c, 0x74, 0x1a, 0x18, 0x5e, 0x23, 0x4d, + 0xcb, 0x3a, 0xfd, 0x79, 0xc5, 0x89, 0xcd, 0xaf, 0xa9, 0x4b, 0xa2, 0x9c, 0x89, 0xfd, 0x85, 0xf1, + 0x78, 0xb1, 0xf4, 0xc4, 0x92, 0xdb, 0xea, 0x8d, 0x86, 0x5b, 0x80, 0x76, 0xd7, 0x94, 0x4f, 0xd2, + 0x6d, 0x57, 0x8c, 0xc5, 0xab, 0xd5, 0x16, 0x49, 0xf6, 0x2d, 0x07, 0xd5, 0xd6, 0xb5, 0x89, 0xef, + 0xfb, 0x4d, 0xe3, 0xb2, 0xb3, 0x86, 0x4b, 0x7c, 0xfd, 0xfb, 0xe8, 0xe7, 0x6b, 0xa4, 0xdf, 0xe3, + 0x97, 0x3a, 0x2c, 0xd5, 0xdc, 0xd4, 0x7e, 0x6a, 0xbc, 0x76, 0x57, 0x94, 0xc0, 0x29, 0xbf, 0x1c, + 0x68, 0x62, 0xe2, 0x6c, 0x49, 0xf4, 0xcd, 0x1a, 0x8e, 0x94, 0x81, 0x47, 0xc7, 0x74, 0xe8, 0xa5, + 0x1e, 0x15, 0xf6, 0x96, 0xb1, 0xdc, 0x5f, 0x61, 0x79, 0x92, 0x50, 0xe7, 0xa6, 0x63, 0xb4, 0xb7, + 0x46, 0xed, 0x99, 0x5e, 0x9f, 0xdb, 0x7d, 0xb9, 0x56, 0xe9, 0xe9, 0x9e, 0x9f, 0x1b, 0xbd, 0xcd, + 0x77, 0x3c, 0xb0, 0x11, 0x17, 0x0e, 0x4c, 0xf5, 0xbc, 0x9f, 0x72, 0x17, 0xec, 0x67, 0x95, 0xd2, + 0xf6, 0x67, 0xfb, 0xaf, 0xab, 0xb9, 0xe7, 0x7c, 0xb5, 0x9f, 0xb2, 0x69, 0xce, 0x49, 0x6d, 0xee, + 0x42, 0x76, 0x3e, 0xe4, 0x82, 0x16, 0x47, 0x5f, 0xaf, 0xd5, 0xc1, 0x63, 0x41, 0x5c, 0x70, 0x53, + 0xfb, 0x7b, 0xbe, 0x56, 0x06, 0x1b, 0x11, 0x71, 0xbe, 0xc7, 0x01, 0x7a, 0x91, 0x9b, 0x6a, 0x44, + 0x29, 0x10, 0x0c, 0x83, 0x74, 0x88, 0x17, 0x1e, 0xe5, 0x25, 0x65, 0x2e, 0xbf, 0xb4, 0x5f, 0x98, + 0xf1, 0xb6, 0x95, 0x19, 0x6f, 0x21, 0xb8, 0x99, 0x60, 0xdf, 0x18, 0x68, 0xf1, 0x12, 0x72, 0xe9, + 0x0c, 0xc4, 0x58, 0xdf, 0xcc, 0x91, 0x5a, 0x3c, 0x33, 0xb7, 0x8b, 0xf3, 0xb7, 0x91, 0x60, 0x43, + 0xb5, 0x68, 0x74, 0x8e, 0xf2, 0x69, 0x4f, 0x8e, 0x46, 0xdf, 0x91, 0xd1, 0x5f, 0x28, 0x78, 0xc4, + 0x45, 0xca, 0xcc, 0x7e, 0x69, 0xe4, 0x5f, 0x2d, 0x3a, 0x96, 0x36, 0x65, 0xd1, 0x5f, 0x2f, 0x2d, + 0x2e, 0xe6, 0x9e, 0xc5, 0x2e, 0x5a, 0xda, 0xaa, 0x52, 0x09, 0xce, 0xc6, 0xf3, 0x8e, 0xdd, 0x29, + 0xe6, 0x60, 0x71, 0xc7, 0xf6, 0x0d, 0x31, 0xe9, 0xdb, 0x7e, 0x3e, 0x07, 0xc9, 0x93, 0xc8, 0xf1, + 0x80, 0x30, 0xec, 0x13, 0x29, 0xb1, 0xc3, 0x03, 0xa6, 0xec, 0x57, 0xc5, 0xe3, 0x8a, 0x5f, 0x41, + 0x75, 0x8d, 0xed, 0x12, 0x29, 0xeb, 0x1a, 0x69, 0x9d, 0xa0, 0xa7, 0xb9, 0x8b, 0xd5, 0xd3, 0x32, + 0x04, 0x8f, 0x48, 0xe0, 0xa9, 0x38, 0xa7, 0xaf, 0x8d, 0xde, 0x93, 0xcc, 0xa5, 0xaa, 0x71, 0x87, + 0x2d, 0x8d, 0x8a, 0xb2, 0xb9, 0x44, 0x6a, 0x98, 0x95, 0xfa, 0x6a, 0x89, 0xd4, 0x51, 0x5a, 0xea, + 0xb7, 0x79, 0x29, 0xd3, 0xa6, 0x2e, 0x10, 0xd7, 0xa3, 0x2c, 0x79, 0xad, 0x56, 0x8d, 0x54, 0xe6, + 0xa5, 0xa3, 0x3b, 0xb3, 0x11, 0xc1, 0xa2, 0x82, 0xe8, 0xe6, 0x8b, 0x4c, 0xe7, 0x64, 0xe1, 0x2e, + 0x6b, 0xe1, 0x0b, 0x35, 0xf7, 0x72, 0x2a, 0x6e, 0xf4, 0x0f, 0xf9, 0x97, 0x83, 0xc3, 0x99, 0x12, + 0xc4, 0xa5, 0x4e, 0xaa, 0x0f, 0xe2, 0x45, 0xee, 0x2e, 0x7a, 0xe6, 0xa4, 0xe0, 0x99, 0xe2, 0x1d, + 0x2f, 0x2d, 0xde, 0xd4, 0x70, 0x74, 0x03, 0x91, 0x79, 0x4f, 0xec, 0x19, 0x87, 0x85, 0x17, 0xf3, + 0x7c, 0x2e, 0x36, 0x22, 0x52, 0x64, 0xf4, 0x17, 0x54, 0xcd, 0x1a, 0x45, 0x45, 0xba, 0xbc, 0xa4, + 0xf6, 0x8d, 0xcb, 0x76, 0xda, 0x25, 0xac, 0xcf, 0x25, 0x85, 0x75, 0x8c, 0x36, 0x17, 0xa4, 0x70, + 0x06, 0x82, 0x8e, 0x28, 0x88, 0x48, 0xf4, 0xa0, 0x58, 0x0c, 0x3a, 0x83, 0xbf, 0x8f, 0x50, 0x46, + 0xe9, 0x57, 0xb7, 0xfe, 0xfb, 0xf7, 0x2f, 0x4a, 0x3b, 0xff, 0x2c, 0xa1, 0xc7, 0xff, 0x67, 0x5e, + 0x5a, 0x55, 0xb4, 0xd3, 0x1f, 0x74, 0x7a, 0x87, 0xbf, 0x69, 0xe2, 0x41, 0xef, 0x7c, 0x70, 0x8c, + 0x9b, 0x67, 0xad, 0x4e, 0xaf, 0xde, 0x6c, 0x37, 0xcf, 0x06, 0xb8, 0xdd, 0x69, 0x34, 0xf1, 0xf9, + 0x59, 0xbf, 0xdb, 0xac, 0x9f, 0xb4, 0x4e, 0x9a, 0x8d, 0x8d, 0x1b, 0xd6, 0x4b, 0xf4, 0x6c, 0x05, + 0xbe, 0x7f, 0x7c, 0xd8, 0xe8, 0xbc, 0xd9, 0x28, 0x59, 0x2f, 0xd0, 0xd6, 0x2a, 0x68, 0xa7, 0x35, + 0xd8, 0xf8, 0x68, 0x0d, 0x60, 0xeb, 0xfc, 0xf4, 0x74, 0xe3, 0xe6, 0xd1, 0xce, 0x3f, 0xde, 0x97, + 0x4b, 0xef, 0xde, 0x97, 0x4b, 0xff, 0x79, 0x5f, 0x2e, 0xfd, 0xed, 0x43, 0xf9, 0xc6, 0xbb, 0x0f, + 0xe5, 0x1b, 0xff, 0xfe, 0x50, 0xbe, 0xf1, 0xdd, 0xc6, 0xd5, 0xfc, 0xbb, 0x20, 0x75, 0xed, 0x83, + 0x1c, 0xde, 0x36, 0xdf, 0xe8, 0x1c, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xf8, 0xb5, 0x55, + 0x2b, 0x12, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -806,6 +829,12 @@ func (this *Params) Equal(that interface{}) bool { if this.StorageTruthReporterIneligibleDurationEpochs != that1.StorageTruthReporterIneligibleDurationEpochs { return false } + if this.StorageTruthStrongRecoveryCleanPassCount != that1.StorageTruthStrongRecoveryCleanPassCount { + return false + } + if this.StorageTruthHealVerifierCount != that1.StorageTruthHealVerifierCount { + return false + } return true } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -828,6 +857,20 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.StorageTruthHealVerifierCount != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.StorageTruthHealVerifierCount)) + i-- + dAtA[i] = 0x3 + i-- + dAtA[i] = 0x98 + } + if m.StorageTruthStrongRecoveryCleanPassCount != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.StorageTruthStrongRecoveryCleanPassCount)) + i-- + dAtA[i] = 0x3 + i-- + dAtA[i] = 0x90 + } if m.StorageTruthReporterIneligibleDurationEpochs != 0 { i = encodeVarintParams(dAtA, i, uint64(m.StorageTruthReporterIneligibleDurationEpochs)) i-- @@ -1330,6 +1373,12 @@ func (m *Params) Size() (n int) { if m.StorageTruthReporterIneligibleDurationEpochs != 0 { n += 2 + sovParams(uint64(m.StorageTruthReporterIneligibleDurationEpochs)) } + if m.StorageTruthStrongRecoveryCleanPassCount != 0 { + n += 2 + sovParams(uint64(m.StorageTruthStrongRecoveryCleanPassCount)) + } + if m.StorageTruthHealVerifierCount != 0 { + n += 2 + sovParams(uint64(m.StorageTruthHealVerifierCount)) + } return n } @@ -2357,6 +2406,44 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 50: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageTruthStrongRecoveryCleanPassCount", wireType) + } + m.StorageTruthStrongRecoveryCleanPassCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StorageTruthStrongRecoveryCleanPassCount |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 51: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageTruthHealVerifierCount", wireType) + } + m.StorageTruthHealVerifierCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StorageTruthHealVerifierCount |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:])