Skip to content

Migrated sanction module to collections for state storage.#2570

Open
nagarajdivine wants to merge 10 commits into
mainfrom
feat/sanction-module-collections
Open

Migrated sanction module to collections for state storage.#2570
nagarajdivine wants to merge 10 commits into
mainfrom
feat/sanction-module-collections

Conversation

@nagarajdivine

@nagarajdivine nagarajdivine commented Dec 11, 2025

Copy link
Copy Markdown
Contributor

Description


Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

  • Targeted PR against correct branch (see CONTRIBUTING.md).
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Wrote unit and integration tests
  • Updated relevant documentation (docs/) or specification (x/<module>/spec/).
  • Added relevant godoc comments.
  • Added relevant changelog entries under .changelog/unreleased (see Adding Changes).
  • Re-reviewed Files changed in the Github PR explorer.
  • Review Codecov Report in the comment section below once CI passes.

Summary by CodeRabbit

  • Refactor

    • Module storage migrated to a collections-backed, context-driven model; keeper initialization and access patterns updated.
  • New Features

    • Improved queries: address-filtered temporary-entry retrieval with correct pagination totals and next-key behavior.
    • Added changelog entry documenting the storage migration.
  • Bug Fixes

    • Added explicit error handling in genesis and proposal-cleanup flows.
  • Tests

    • Added extensive backward-compatibility and iteration tests to validate old data and key layouts.

@nagarajdivine nagarajdivine requested a review from a team as a code owner December 11, 2025 15:46
@coderabbitai

coderabbitai Bot commented Dec 11, 2025

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Migrates x/sanction from direct KVStore access to cosmossdk.io/collections: adds collection-backed maps and key codecs, changes Keeper to accept a StoreService and context-based APIs, updates queries/tests, adds prefix/key codecs, improves error handling, and includes backward-compatibility tests for old KV layouts.

Changes

Cohort / File(s) Summary
Changelog & App Init
/.changelog/unreleased/features/2498-sanction-module-collections.md, app/app.go
Adds changelog entry; initialize SanctionKeeper using runtime KVStoreService instead of a raw store key.
Key Codecs & Prefixes
x/sanction/codec.go, x/sanction/keeper/keys.go
Adds AccAddressKey, TemporaryKeyCodec, ProposalIndexKeyCodec with binary/JSON/non-terminal/text methods; replaces byte-slice prefixes with collections.Prefix.
Keeper Core & Schema
x/sanction/keeper/keeper.go
Reworks Keeper to use StoreService and a collections.Schema; introduces Map stores (ParameterStore, SanctionedAddressesStore, TemporaryEntriesStore, ProposalIndex); many methods now context-based and return errors.
GRPC Queries & Pagination
x/sanction/keeper/grpc_query.go
Replaces Paginate with collection-aware pagination; adds address-filtered path (temporaryEntriesForAddress) with prefix iteration, proper NextKey/Total and reverse/forward pagination handling.
Export & Test Helpers
x/sanction/keeper/export_test.go, x/sanction/keeper/suite_test.go
Replaces StoreKey() with KVStore(ctx) / StoreService.OpenKVStore(ctx) in tests; updates test helpers to accept sdk.Context; adds runtime assertions and iterator error checks.
Genesis & Gov Hooks
x/sanction/keeper/genesis.go, x/sanction/keeper/gov_hooks.go
Adds error handling for collection iterations and deletions; panics with formatted messages on failures.
Keeper Tests & Back-compat
x/sanction/keeper/keeper_test.go, x/sanction/keeper/genesis_test.go
Updates tests to use context-based Keeper API; adds backward-compatibility tests validating old KV key layouts, reading legacy data, and iteration behavior.
Exported Test API Changes
x/sanction/keeper/export_test.go
Replaces store-based helper signatures to accept ctx sdk.Context and adds KVStore(ctx) accessor on Keeper for test usage.
Misc & Simulation
x/sanction/simulation/genesis.go
Adds nolint:gosec comments on RandomTempEntries; no behavioral change.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client as gRPC Client
  participant GRPC as sanction gRPC
  participant Keeper as sanction Keeper
  participant StoreSvc as runtime.KVStoreService
  participant DB as underlying KV DB

  Client->>GRPC: ListTemporaryEntries(req)
  GRPC->>Keeper: TemporaryEntries(ctx, req)
  alt address filter provided
    Keeper->>Keeper: temporaryEntriesForAddress(ctx, addr, pagination)
    Keeper->>StoreSvc: OpenKVStore(ctx)
    StoreSvc->>DB: open store
    Keeper->>Keeper: walk TemporaryEntries collection with prefix
    Keeper-->>Keeper: collect, apply offset/limit, compute NextKey/Total
  else unfiltered
    Keeper->>Keeper: CollectionPaginate(k.TemporaryEntriesStore, pagination)
    Keeper->>StoreSvc: OpenKVStore(ctx)
    StoreSvc->>DB: open store
    Keeper->>Keeper: collection pagination returns page + total/nextKey
  end
  Keeper-->>GRPC: build response with Entries + Pagination
  GRPC-->>Client: return paginated result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • iramiller
  • dcshock
  • SpicyLemon

Poem

🐇
I hop through keys and stitch bytes neat,
swapped slices for maps — collections meet.
Tests remember old trails as I bound,
Keeper opens stores, new order found.
Carrot cheers for code well-ground! 🥕

🚥 Pre-merge checks | ✅ 5 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (13 files):

⚔️ app/app.go (content)
⚔️ x/metadata/types/query.go (content)
⚔️ x/sanction/codec.go (content)
⚔️ x/sanction/keeper/export_test.go (content)
⚔️ x/sanction/keeper/genesis.go (content)
⚔️ x/sanction/keeper/genesis_test.go (content)
⚔️ x/sanction/keeper/gov_hooks.go (content)
⚔️ x/sanction/keeper/grpc_query.go (content)
⚔️ x/sanction/keeper/keeper.go (content)
⚔️ x/sanction/keeper/keeper_test.go (content)
⚔️ x/sanction/keeper/keys.go (content)
⚔️ x/sanction/keeper/suite_test.go (content)
⚔️ x/sanction/simulation/genesis.go (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: migrating the sanction module to use collections for state storage, which is the primary objective of the PR.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #2498: migrates x/sanction module to use collections, updates state storage interactions, and avoids requiring a state migration.
Out of Scope Changes check ✅ Passed All changes are directly related to the collections migration objective: codec implementations, keeper refactoring, store service integration, query pagination updates, and supporting test updates are all within scope.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/sanction-module-collections

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
x/trigger/simulation/genesis.go (1)

179-185: Int cast is safe after the math.MaxInt guard

The explicit triggerID > uint64(math.MaxInt) panic ensures the subsequent triggerIDInt := int(triggerID) is safe on all supported architectures. From a correctness standpoint, removing the //nolint:gosec G115 is fine.

If gosec still complains about G115 despite the guard, consider adding a brief comment explaining that the prior range check guarantees safety, or reintroducing a narrowly scoped nolint with that explanation.

x/sanction/keeper/export_test.go (1)

47-50: Comment is stale - says "StoreKey" but method is now "KVStore".

The comment on line 47 still references "storekey" but the method has been renamed to KVStore.

-// StoreKey, for unit tests, exposes this keeper's storekey.
+// KVStore, for unit tests, returns a KVStore from the keeper's StoreService.
 func (k Keeper) KVStore(ctx sdk.Context) store.KVStore {
 	return k.StoreService.OpenKVStore(ctx)
 }
x/sanction/keeper/keeper.go (3)

99-100: Typo: Comment has line break in the middle of "Proposal".

There's an accidental line break splitting "Proposal" across two lines.

-		// Proposa
-		// l index: (uint64, AccAddress) -> []byte with custom codec
+		// Proposal index: (uint64, AccAddress) -> []byte with custom codec
 		// Collections adds 0x03 prefix, codec handles [propID][len][addr]

266-297: Consider using prefix range for DeleteGovPropTempEntries.

Similar to getLatestTempEntry, this method walks the entire ProposalIndex to find entries for a specific govPropID. Since the ProposalIndex key is (govPropID, addr), you could use a prefix range based on govPropID to only iterate relevant entries.

However, this is less critical than getLatestTempEntry since deletion happens less frequently than reads.


300-342: Consider using prefix range for DeleteAddrTempEntries.

This method walks the entire TemporaryEntriesStore for each address. Since the key is (addr, govPropID), you could use a prefix range based on addr to only iterate relevant entries. This is especially important when deleting entries for multiple addresses.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5dc9932 and 346654e.

📒 Files selected for processing (22)
  • .changelog/unreleased/features/2498-sanction-module-collections.md (1 hunks)
  • app/app.go (1 hunks)
  • internal/protocompat/protocompat.go (1 hunks)
  • x/attribute/client/cli/tx.go (1 hunks)
  • x/exchange/client/cli/flags.go (2 hunks)
  • x/ledger/client/cli/tx.go (4 hunks)
  • x/ledger/keeper/genesis.go (3 hunks)
  • x/marker/client/cli/tx.go (2 hunks)
  • x/marker/types/si.go (1 hunks)
  • x/name/client/cli/tx.go (1 hunks)
  • x/sanction/codec.go (2 hunks)
  • x/sanction/keeper/export_test.go (3 hunks)
  • x/sanction/keeper/genesis.go (2 hunks)
  • x/sanction/keeper/genesis_test.go (1 hunks)
  • x/sanction/keeper/gov_hooks.go (1 hunks)
  • x/sanction/keeper/grpc_query.go (4 hunks)
  • x/sanction/keeper/keeper.go (7 hunks)
  • x/sanction/keeper/keeper_test.go (25 hunks)
  • x/sanction/keeper/keys.go (2 hunks)
  • x/sanction/keeper/suite_test.go (3 hunks)
  • x/sanction/simulation/genesis.go (1 hunks)
  • x/trigger/simulation/genesis.go (1 hunks)
🧰 Additional context used
🧠 Learnings (35)
📓 Common learnings
Learnt from: nullpointer0x00
Repo: provenance-io/provenance PR: 0
File: :0-0
Timestamp: 2024-06-10T19:25:28.209Z
Learning: A GitHub issue was created to track the migration of parameters for the metadata, marker, name, and msgFees modules as indicated by the TODO comments in the codebase. The issue is linked to PR #1932 and can be found at https://github.com/provenance-io/provenance/issues/1935.
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/asset/simulation/decoder.go:8-14
Timestamp: 2025-08-15T20:19:31.726Z
Learning: The asset module in Provenance doesn't use collections-based storage like ledger/registry modules. Instead, it delegates storage to the NFT module, so a collections-based store decoder isn't applicable here. The module should use its own types.StoreKey rather than exchange.StoreKey in RegisterStoreDecoder.
📚 Learning: 2025-12-10T23:09:58.272Z
Learnt from: iramiller
Repo: provenance-io/provenance PR: 2568
File: .changelog/unreleased/features/2568-add-provlabs-wasm-contract-to-upgrade.md:0-0
Timestamp: 2025-12-10T23:09:58.272Z
Learning: In the provenance-io/provenance repo, ProvLabs is the parent entity and Nuva is the client. In formal contexts (changelogs, documentation, and log messages), reference ProvLabs as the entity providing support for the code contribution, and avoid using Nuva in these contexts.

Applied to files:

  • .changelog/unreleased/features/2498-sanction-module-collections.md
📚 Learning: 2025-08-15T20:59:09.909Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/expected_keeper.go:11-19
Timestamp: 2025-08-15T20:59:09.909Z
Learning: The BankKeeper interface methods in Cosmos SDK v0.50.x and Provenance use `context.Context` as the context parameter type, not `sdk.Context`. This applies to methods like SendCoins, HasBalance, GetBalance, SpendableCoin, HasSupply, etc. The expected keeper interfaces should consistently use `context.Context` to match the actual Cosmos SDK bank keeper signatures.

Applied to files:

  • x/sanction/keeper/genesis_test.go
  • app/app.go
  • x/sanction/keeper/keys.go
  • x/sanction/keeper/keeper_test.go
  • x/sanction/keeper/export_test.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:59:09.909Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/expected_keeper.go:11-19
Timestamp: 2025-08-15T20:59:09.909Z
Learning: In Cosmos SDK v0.50.x, the bank keeper interface methods use `context.Context` rather than `sdk.Context`. The BankKeeper interface should use `context.Context` for methods like SendCoins, HasBalance, GetBalance, etc.

Applied to files:

  • x/sanction/keeper/genesis_test.go
  • app/app.go
  • x/sanction/keeper/keeper_test.go
  • x/sanction/keeper/export_test.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-10T23:13:56.722Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2176
File: x/ibchooks/types/params.go:22-26
Timestamp: 2024-10-10T23:13:56.722Z
Learning: In the file `x/ibchooks/types/params.go`, maintain the existing behavior in the `Validate` method without modifying the error messages, even if they may lack additional context.

Applied to files:

  • x/sanction/keeper/genesis_test.go
  • x/attribute/client/cli/tx.go
  • x/sanction/keeper/keeper_test.go
  • x/sanction/keeper/gov_hooks.go
📚 Learning: 2024-10-02T01:58:51.519Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/expected_keepers.go:39-49
Timestamp: 2024-10-02T01:58:51.519Z
Learning: - In v0.50.x of the SDK, they have started the transition to using `context.Context` instead of `sdk.Context`, and `sdk.Context` satisfies `context.Context`.

Applied to files:

  • x/sanction/keeper/genesis_test.go
  • x/sanction/keeper/export_test.go
📚 Learning: 2024-10-02T02:51:17.452Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/bank_test.go:81-91
Timestamp: 2024-10-02T02:51:17.452Z
Learning: In test helper functions like `setBalances` in `x/metadata/keeper/bank_test.go`, it's acceptable to handle zero or negative amounts without raising an error, as it suits the test's purposes.

Applied to files:

  • x/sanction/keeper/genesis_test.go
  • x/sanction/keeper/keeper_test.go
📚 Learning: 2025-08-15T22:52:24.461Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/keeper.go:74-173
Timestamp: 2025-08-15T22:52:24.461Z
Learning: In the ledger keeper NewKeeper function in x/ledger/keeper/keeper.go, SpicyLemon prefers to allow bankKeeper and registryKeeper dependencies to be nil rather than adding validation that would panic on nil values. The design intentionally supports nil keepers for flexibility.

Applied to files:

  • x/sanction/keeper/genesis_test.go
  • app/app.go
  • x/ledger/keeper/genesis.go
  • x/sanction/keeper/keeper_test.go
  • x/sanction/keeper/export_test.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2024-06-10T19:25:28.209Z
Learnt from: Taztingo
Repo: provenance-io/provenance PR: 0
File: :0-0
Timestamp: 2024-06-10T19:25:28.209Z
Learning: The user has updated the governance parameter structure in `cmd/provenanced/cmd/init.go` to `govGenState.Params.MinDeposit` and added a TODO to verify this change as it relates to a different task.

Applied to files:

  • x/sanction/keeper/genesis_test.go
  • x/attribute/client/cli/tx.go
  • x/sanction/simulation/genesis.go
  • x/sanction/keeper/keeper_test.go
  • x/sanction/keeper/gov_hooks.go
  • x/marker/client/cli/tx.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-08T18:12:51.936Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 1868
File: x/exchange/keeper/payments.go:24-34
Timestamp: 2024-10-08T18:12:51.936Z
Learning: The `parsePaymentStoreValue` function in `x/exchange/keeper/payments.go` returns `nil, nil` when the input byte slice is empty, as a design decision to simplify handling for the caller. This behavior is based on the rationale provided by a user, emphasizing ease of use over explicit error signaling for empty inputs.

Applied to files:

  • x/sanction/keeper/genesis_test.go
  • x/sanction/keeper/keeper_test.go
📚 Learning: 2024-10-02T18:03:10.008Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/types/signer_utils_test.go:478-493
Timestamp: 2024-10-02T18:03:10.008Z
Learning: In Go tests, modifying byte slices directly using arithmetic operations like addition and subtraction is acceptable, even if it causes overflow, as overflow on `uint8` just wraps around. Avoid flagging such usage, and avoid suggesting bitwise operations which can be harder to read and understand.

Applied to files:

  • x/attribute/client/cli/tx.go
  • x/exchange/client/cli/flags.go
  • x/marker/types/si.go
📚 Learning: 2024-10-02T01:43:01.360Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/marker/types/send_restrictions.go:11-11
Timestamp: 2024-10-02T01:43:01.360Z
Learning: In `x/marker/types/send_restrictions.go`, the `transferAgentKey` is only used for storing data in ephemeral contexts, so changing its value does not impact backward compatibility.

Applied to files:

  • x/attribute/client/cli/tx.go
  • app/app.go
  • x/ledger/keeper/genesis.go
  • x/sanction/keeper/keys.go
  • x/sanction/keeper/keeper_test.go
  • x/ledger/client/cli/tx.go
  • x/sanction/keeper/export_test.go
  • x/marker/client/cli/tx.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-21T17:12:02.352Z
Learnt from: iramiller
Repo: provenance-io/provenance PR: 2194
File: cmd/provenanced/cmd/root.go:225-225
Timestamp: 2024-10-21T17:12:02.352Z
Learning: When adding flags in `cmd/provenanced/cmd/root.go`, use `flags.AddTxFlagsToCmd(cmd)` for each command to add the appropriate flags, instead of individually adding flags to the root command.

Applied to files:

  • x/exchange/client/cli/flags.go
📚 Learning: 2025-08-15T19:49:19.255Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/genesis.go:273-283
Timestamp: 2025-08-15T19:49:19.255Z
Learning: SpicyLemon prefers using strconv.ParseInt with explicit bit size parameter (e.g., strconv.ParseInt(str, 10, 32)) over strconv.Atoi followed by manual bounds checking when converting to specific integer types like int32, as it's more idiomatic and automatically enforces bounds.

Applied to files:

  • x/exchange/client/cli/flags.go
📚 Learning: 2024-10-24T19:50:09.457Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2198
File: app/app_test.go:448-528
Timestamp: 2024-10-24T19:50:09.457Z
Learning: In `app/app_test.go`, when testing that the encoder is correctly wired to handle a governance `Proposal` with a `ParameterChangeProposal`, it's sufficient to have a basic test case without adding additional test cases, since the types and encoders are defined and maintained in external libraries outside our control.

Applied to files:

  • x/sanction/simulation/genesis.go
  • x/sanction/keeper/keeper_test.go
📚 Learning: 2025-08-15T20:59:51.949Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/keys.go:3-12
Timestamp: 2025-08-15T20:59:51.949Z
Learning: In Cosmos SDK, key prefixes only need to be unique within a given module's store, not across the entire application. Each module operates within its own isolated key-value store namespace, so the same byte prefixes can be safely reused across different modules without causing collisions.

Applied to files:

  • x/sanction/keeper/keys.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:34:01.110Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/asset/types/codec.go:9-10
Timestamp: 2025-08-15T20:34:01.110Z
Learning: In Go Cosmos SDK projects, sdk.Msg interface embeds proto.Message interface, making it valid to copy elements from []sdk.Msg to []proto.Message even though the slice types are different. The pattern of declaring AllRequestMsgs as []sdk.Msg for type assertions while copying to []proto.Message for RegisterImplementations is a common and correct pattern.

Applied to files:

  • x/sanction/keeper/keys.go
  • internal/protocompat/protocompat.go
  • x/sanction/codec.go
  • x/sanction/keeper/grpc_query.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-08T18:12:51.936Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/mocks_test.go:425-427
Timestamp: 2024-10-08T18:12:51.936Z
Learning: In this codebase, when using `sdk.AccAddress` as map keys, casting to `string` is preferred over calling `.String()` for performance reasons.

Applied to files:

  • x/sanction/keeper/keys.go
  • x/sanction/codec.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:39:34.095Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/asset/types/util.go:68-102
Timestamp: 2025-08-15T20:39:34.095Z
Learning: In the Provenance codebase, functions with "Must" prefix (like MustGetMarkerAddress) can panic and should only be used when you know they won't panic. Instead, use the twin function that returns an error (like GetMarkerAddress) and handle the error properly.

Applied to files:

  • x/sanction/keeper/genesis.go
📚 Learning: 2024-10-02T02:29:56.018Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/types/signer_utils.go:138-143
Timestamp: 2024-10-02T02:29:56.018Z
Learning: In this codebase, methods like `GetAcc()` and `GetSignerAcc()` are intended to return `nil` if the address is invalid, and address validation is performed elsewhere. These methods should return a single value without an error.

Applied to files:

  • x/sanction/keeper/genesis.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:57:04.455Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/entries_test.go:26-31
Timestamp: 2025-08-15T20:57:04.455Z
Learning: SpicyLemon prefers string-based error assertions in tests using empty string to indicate "no error expected" and non-empty string for expected error messages. Use assertions.AssertErrorValue instead of errors.Is() comparisons because errors.Is() with s.Require().True() provides poor failure messages that only say "Should be true" without showing expected vs actual error content.

Applied to files:

  • x/sanction/keeper/suite_test.go
📚 Learning: 2024-06-10T19:25:28.209Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 1993
File: x/marker/client/cli/cli_test.go:1090-1090
Timestamp: 2024-06-10T19:25:28.209Z
Learning: SpicyLemon prefers allowing tests to fail naturally if the setup is incorrect rather than explicitly checking and handling such errors within the test functions. They also recommend using `s.Require().NotNil(...)` instead of `s.T().Fatal(...)` for assertions in test functions.

Applied to files:

  • x/sanction/keeper/suite_test.go
  • x/sanction/keeper/keeper_test.go
📚 Learning: 2024-10-02T03:37:18.486Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/msg_server_test.go:1225-1228
Timestamp: 2024-10-02T03:37:18.486Z
Learning: When test cases are run using `s.T().Run` instead of `s.Run`, use `require` with `t` instead of `s.Require()`, to ensure that assertions apply to the correct test instance.

Applied to files:

  • x/sanction/keeper/suite_test.go
  • x/sanction/keeper/keeper_test.go
📚 Learning: 2024-10-08T18:12:51.935Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/account_data_test.go:11-11
Timestamp: 2024-10-08T18:12:51.935Z
Learning: Do not raise issues about the `keeper` package still being in use after import removal in test files when there are no unresolved references.

Applied to files:

  • x/sanction/keeper/keeper_test.go
📚 Learning: 2024-10-10T23:08:15.256Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2175
File: .golangci.yml:87-87
Timestamp: 2024-10-10T23:08:15.256Z
Learning: The `depguard` definitions in `.golangci.yml` are prefixes (unless they end with `$`), so the entry `- cosmossdk.io/client/v2` covers imports from `cosmossdk.io/client/v2` and its subpackages like `autocli`. Changing imports from `cosmossdk.io/client/v2/autocli` to `cosmossdk.io/client/v2` in `app/app.go` would result in unresolved references because the required code resides in the `autocli` package.

Applied to files:

  • x/sanction/keeper/keeper_test.go
  • x/sanction/keeper/grpc_query.go
📚 Learning: 2024-10-08T18:12:51.936Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/migrations_v4_test.go:253-479
Timestamp: 2024-10-08T18:12:51.936Z
Learning: In Go tests within this project, it's acceptable to have similar helper functions like `newUUID`, `newScopeID`, `newSpecID`, and `newScope` defined within each test. Tests may tailor these functions to specific needs rather than sharing them, to avoid breaking other tests when changes are made and to keep them non-public.

Applied to files:

  • x/sanction/keeper/keeper_test.go
📚 Learning: 2024-06-10T19:25:28.209Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 0
File: :0-0
Timestamp: 2024-06-10T19:25:28.209Z
Learning: The `GetLockedCoins` function in `x/hold/keeper/locked_coins.go` must conform to the `banktypes.GetLockedCoinsFn` type, which does not allow returning an error. In cases where `k.GetHoldCoins` encounters an error, using `panic` is considered appropriate due to the severity of such errors.

Applied to files:

  • x/sanction/keeper/keeper_test.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-02T17:24:43.269Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/mocks_test.go:579-589
Timestamp: 2024-10-02T17:24:43.269Z
Learning: When mocking methods like `MintCoins` and `BurnCoins` in tests, using slices to store error strings and consuming them sequentially is the preferred approach, as it offers precise control and simplicity without unnecessary complexity.

Applied to files:

  • x/sanction/keeper/keeper_test.go
📚 Learning: 2024-10-02T03:42:47.070Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/query_server_test.go:940-945
Timestamp: 2024-10-02T03:42:47.070Z
Learning: In the `TestScopeQuery` function, the conditional checks following the equality assertion are designed to help identify differences when `tc.expResp` and `actResp` are not equal and both are not `nil`. If they are equal, or either is `nil`, the failure message from the equality assertion suffices, and further checks are not needed.

Applied to files:

  • x/sanction/keeper/keeper_test.go
📚 Learning: 2024-10-08T18:12:51.936Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/types/signer_utils_test.go:1837-1889
Timestamp: 2024-10-08T18:12:51.936Z
Learning: In Go tests where test cases are defined within a test case slice and iterated with `t.Run`, instances defined in the test case struct are not shared between subtests, ensuring test independence.

Applied to files:

  • x/sanction/keeper/keeper_test.go
📚 Learning: 2024-10-04T16:17:48.021Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2167
File: scripts/protocgen.sh:13-14
Timestamp: 2024-10-04T16:17:48.021Z
Learning: In `scripts/protocgen.sh`, the regex pattern `'option go_package.*provenance'` is sufficient for selecting the necessary proto files and does not need modification.

Applied to files:

  • internal/protocompat/protocompat.go
📚 Learning: 2025-09-19T19:57:02.914Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/entries.go:62-71
Timestamp: 2025-09-19T19:57:02.914Z
Learning: In Cosmos SDK v0.50.x, sdk.Context satisfies the context.Context interface and can be passed directly to methods expecting context.Context without wrapping via sdk.WrapSDKContext().

Applied to files:

  • x/sanction/keeper/export_test.go
📚 Learning: 2024-10-08T18:12:51.936Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/types/signer_utils.go:306-308
Timestamp: 2024-10-08T18:12:51.936Z
Learning: When using `sdk.AccAddress` as map keys in `AuthzCache`, casting to `string(addr)` is acceptable and preferred over `addr.String()` due to performance considerations and the keys being used internally.

Applied to files:

  • x/sanction/codec.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:34:01.110Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/asset/types/codec.go:9-10
Timestamp: 2025-08-15T20:34:01.110Z
Learning: The pattern of declaring AllRequestMsgs as []sdk.Msg and then copying to []proto.Message for RegisterImplementations is a standard, correct pattern used throughout the Provenance codebase. This works because sdk.Msg interface embeds proto.Message interface, making the copy operation valid. This pattern appears consistently across 15+ modules and compiles without errors.

Applied to files:

  • x/sanction/codec.go
📚 Learning: 2024-10-02T02:06:21.664Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/migrations_v4.go:57-80
Timestamp: 2024-10-02T02:06:21.664Z
Learning: The `V3WriteNewScope` method in `x/metadata/keeper/migrations_v4.go` must exist until after the migration has been executed and will be deleted as part of the `viridian` cleanup.

Applied to files:

  • x/sanction/keeper/keeper.go
🧬 Code graph analysis (8)
x/sanction/keeper/genesis_test.go (2)
x/sanction/keeper/keeper.go (1)
  • Keeper (19-50)
x/sanction/keeper/keys.go (1)
  • ParamNameImmediateUnsanctionMinDeposit (35-35)
app/app.go (2)
x/sanction/keeper/keeper.go (1)
  • NewKeeper (52-124)
x/sanction/keys.go (1)
  • StoreKey (8-8)
x/sanction/simulation/genesis.go (1)
x/sanction/sanction.pb.go (4)
  • TEMP_STATUS_SANCTIONED (37-37)
  • TemporaryEntry (124-131)
  • TemporaryEntry (135-135)
  • TemporaryEntry (136-138)
x/sanction/keeper/suite_test.go (1)
x/sanction/keeper/keeper.go (1)
  • Keeper (19-50)
x/sanction/keeper/keeper_test.go (6)
x/sanction/keeper/keeper.go (1)
  • Keeper (19-50)
x/sanction/keeper/keys.go (7)
  • ParamNameImmediateSanctionMinDeposit (34-34)
  • ParamNameImmediateUnsanctionMinDeposit (35-35)
  • CreateSanctionedAddrKey (85-87)
  • CreateTemporaryKey (111-118)
  • CreateProposalTempIndexKey (185-187)
  • SanctionB (129-129)
  • UnsanctionB (131-131)
x/sanction/codec.go (3)
  • AccAddressKey (26-26)
  • TemporaryKeyCodec (93-93)
  • ProposalIndexKeyCodec (190-190)
app/app.go (1)
  • App (243-324)
x/sanction/sanction.pb.go (1)
  • TEMP_STATUS_SANCTIONED (37-37)
x/ibchooks/ibc_middleware_test.go (1)
  • Status (41-45)
x/sanction/keeper/export_test.go (1)
x/sanction/keeper/keeper.go (1)
  • Keeper (19-50)
x/sanction/codec.go (1)
internal/provutils/pair.go (1)
  • Pair (6-9)
x/marker/types/si.go (1)
x/marker/types/si.pb.go (2)
  • SIPrefix (25-25)
  • SIPrefix (124-126)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: test-race (00)
  • GitHub Check: tests (01)
  • GitHub Check: test-race (03)
  • GitHub Check: tests (03)
  • GitHub Check: tests (04)
  • GitHub Check: test-race (01)
  • GitHub Check: tests (00)
  • GitHub Check: test-race (04)
  • GitHub Check: test-race (02)
  • GitHub Check: tests (02)
  • GitHub Check: build-linux
  • GitHub Check: Build Linux
  • GitHub Check: Build OSX
  • GitHub Check: golangci-lint
  • GitHub Check: Analyze (go)
  • GitHub Check: ghcr-publish
  • GitHub Check: heighliner-docker
  • GitHub Check: docker
🔇 Additional comments (39)
x/sanction/simulation/genesis.go (1)

47-47: LGTM! Appropriate lint suppression for simulation code.

The nolint:gosec directives are correctly applied with clear justification. Since Int63n returns positive values and the offsets ensure the results stay well within both int64 and uint64 ranges, the casts are safe. The comments accurately explain that this is intentional simulation randomness.

Also applies to: 53-53

internal/protocompat/protocompat.go (1)

8-8: LGTM!

Removing the lint directive is appropriate—the import is legitimate and widely used in the codebase for proto compatibility handling.

x/marker/types/si.go (1)

127-134: LGTM!

The bounds check on lines 127-129 ensures exp is within int32 range before the conversion on line 130, making the nolint directive unnecessary.

x/marker/client/cli/tx.go (2)

1468-1482: LGTM!

The strconv.ParseUint(args[5], 10, 32) on line 1468 already constrains the value to fit within uint32, making the conversion on line 1482 safe without a lint directive.


1521-1535: LGTM!

Similar to the earlier conversion, strconv.ParseUint(args[5], 10, 32) on line 1521 ensures the value fits within uint32, making the conversion on line 1535 safe.

x/attribute/client/cli/tx.go (1)

342-347: LGTM!

The strconv.ParseUint(args[0], 10, 32) on line 342 constrains the value to uint32 range, making the conversion on line 346 safe.

x/ledger/client/cli/tx.go (4)

64-77: LGTM!

The strconv.ParseInt(args[3], 10, 32) ensures the value fits within int32 range, making the conversion safe.


315-325: LGTM!

The strconv.ParseInt(args[1], 10, 32) on line 315 ensures safe conversion to int32.


355-365: LGTM!

The strconv.ParseInt(args[1], 10, 32) on line 355 ensures safe conversion to int32.


395-405: LGTM!

The strconv.ParseInt(args[1], 10, 32) on line 395 ensures safe conversion to int32.

x/sanction/keeper/gov_hooks.go (1)

100-102: Improved error handling with better context.

The change adds proper error checking for DeleteGovPropTempEntries and panics with a descriptive error message that includes the proposal ID. This is consistent with the error handling pattern used elsewhere in the function (lines 87-88) and provides better debugging information if the operation fails.

x/exchange/client/cli/flags.go (2)

336-340: LGTM!

The strconv.ParseUint(args[0], 10, 32) on line 336 constrains the value to uint32 range, making the conversion on line 340 safe.


588-595: LGTM!

The strconv.ParseUint(amountStr, 10, 32) on line 588 ensures the value fits within uint32 range, making the conversion on line 595 safe.

x/ledger/keeper/genesis.go (3)

181-186: LGTM!

The strconv.ParseInt(l.Key.P2, 10, 32) on line 181 ensures the value fits within int32 range before the conversion on line 186.


197-202: LGTM!

The strconv.ParseInt(l.Key.P2, 10, 32) on line 197 ensures safe conversion to int32 on line 202.


213-218: LGTM!

The strconv.ParseInt(l.Key.P2, 10, 32) on line 213 ensures safe conversion to int32 on line 218.

x/name/client/cli/tx.go (1)

275-277: LGTM! Safe uint32 conversions.

The removal of nolint:gosec comments is appropriate here. The strconv.ParseUint calls with bitSize: 32 ensure the values are within uint32 range before conversion, making these casts safe.

x/sanction/codec.go (3)

25-89: LGTM! Well-implemented AccAddressKey codec.

The codec correctly implements length-prefixed encoding for sdk.AccAddress:

  • Buffer size validation in Encode/Decode
  • Proper length-prefix handling (1 byte for length)
  • JSON marshaling via Bech32 strings
  • Non-terminal methods properly delegate to terminal variants

91-186: LGTM! TemporaryKeyCodec properly handles composite keys.

The codec correctly implements encoding for Pair[sdk.AccAddress, uint64]:

  • Proper buffer validation before reads/writes
  • BigEndian encoding for proposal ID ensures correct ordering
  • JSON representation is clear with named fields
  • EncodePrefix helper enables efficient prefix queries by address

188-276: LGTM! ProposalIndexKeyCodec correctly inverts key order.

The codec correctly implements encoding for Pair[uint64, sdk.AccAddress] with proposal ID first:

  • Proposal ID as leading component enables efficient queries by proposal
  • Proper buffer validation throughout
  • JSON representation matches binary ordering
  • Consistent implementation style with other codecs
.changelog/unreleased/features/2498-sanction-module-collections.md (1)

1-1: LGTM! Clear and concise changelog entry.

The entry accurately describes the migration and properly references the related issue.

app/app.go (1)

729-731: LGTM! Correct KVStoreService initialization.

The change properly wraps the store key with runtime.NewKVStoreService to match the updated NewKeeper signature that expects a store.KVStoreService instead of a raw *storetypes.KVStoreKey. This aligns with the collection-based storage migration.

x/sanction/keeper/genesis_test.go (1)

535-535: LGTM! Updated to context-based DeleteParam API.

The change from passing store to s.SdkCtx aligns with the migration to context-based keeper APIs, where methods now accept sdk.Context instead of direct store references.

x/sanction/keeper/genesis.go (2)

68-73: LGTM! Proper error handling for collection-based iteration.

The addition of error handling for IterateSanctionedAddresses is appropriate. Panicking on iteration errors in genesis export is acceptable since these are critical operations that should not fail silently.


81-94: LGTM! Consistent error handling pattern.

The error handling mirrors the pattern in GetAllSanctionedAddresses, maintaining consistency across genesis export functions. Panicking on iteration errors is appropriate in this context.

x/sanction/keeper/suite_test.go (3)

7-7: LGTM! Proper setup validation.

The import addition supports the new store types, and the StoreService nil-check ensures the keeper is properly initialized before tests execute. Good defensive programming.

Also applies to: 64-64


73-75: LGTM! Updated to StoreService-based access.

The change from s.SdkCtx.KVStore(s.Keeper.StoreKey()) to s.Keeper.StoreService.OpenKVStore(s.SdkCtx) correctly reflects the migration to the StoreService pattern. The return type update to store.KVStore matches the new implementation.


81-82: LGTM! Proper error handling for Iterator.

The addition of error capture and assertion for store.Iterator is correct. This ensures the test fails early if iteration cannot be started, preventing misleading test results.

x/sanction/keeper/keys.go (1)

6-6: LGTM! Prefix migration to collections types.

The change from []byte to collections.Prefix aligns with the collection-based storage migration while preserving the prefix values (0, 1, 2, 3) for backward compatibility. The collections.Prefix type integrates seamlessly with the existing key construction functions.

Also applies to: 27-30

x/sanction/keeper/grpc_query.go (2)

236-252: LGTM - prefixEndBytes correctly handles prefix range termination.

The implementation correctly increments bytes from the end to find the exclusive end of the prefix range, handling byte overflow (wrapping to 0) by continuing to the next byte. Returning nil for all-0xFF prefix is correct as it means "iterate to the end."


44-65: LGTM - Collection-based pagination for sanctioned addresses.

The migration to CollectionPaginate is correctly implemented, initializing the response with an empty slice and properly handling the results and pagination response.

x/sanction/keeper/keeper_test.go (4)

870-884: Test setup uses direct store access while testing context-based API.

The test correctly sets up data using the old KVStore pattern (lines 879-883) to verify backward compatibility, which is intentional based on the test name and purpose. The test then correctly uses the context-based GetLatestTempEntry(s.SdkCtx, ...) to verify the new API can read old data.


2389-2431: Good backward compatibility test for key layouts.

These tests verify that the new Collections codecs produce identical keys to the old KVStore approach, which is crucial for ensuring no state migration is required. The test correctly compares:

  • Sanctioned address keys
  • Temporary entry keys
  • Proposal index keys

2434-2469: Good backward compatibility test for reading old data.

This test writes data using the old KVStore pattern and verifies that Collections-based accessors can read it correctly. This is essential for the migration requirement of "no state migration needed."


2498-2558: Comprehensive complex scenario test.

This test validates a realistic chain state scenario with mixed permanent and temporary sanctions, verifying that IsSanctionedAddr, GetAllSanctionedAddresses, and GetAllTemporaryEntries work correctly with data written using the old pattern.

x/sanction/keeper/export_test.go (1)

73-90: LGTM - Test helpers properly updated to context-based API.

The test helper methods (GetLatestTempEntry, GetParam, SetParam, DeleteParam) are correctly updated to accept sdk.Context and delegate to the corresponding private context-based methods.

x/sanction/keeper/keeper.go (3)

419-438: Behavior change: SetParams(nil) now sets defaults instead of deleting.

The previous behavior (per the comment on line 418) was that nil params would delete the params so defaults are used. The new behavior explicitly sets the default values in the store.

This is semantically different:

  • Before: Params not in store → GetParams returns defaults
  • Now: Params in store with default values → GetParams returns those values

While functionally equivalent for now, this could cause issues if default values change in the future (stored values would remain, not reflect new defaults).

Please verify this behavior change is intentional and aligns with the module's requirements.


52-124: LGTM - NewKeeper properly initializes collections-based storage.

The keeper initialization correctly:

  • Creates a SchemaBuilder
  • Initializes all collection Maps with appropriate prefixes and codecs
  • Builds and assigns the schema
  • Appends the send restriction to the bank keeper

344-379: All callers of these iteration methods handle errors, but via panic—consider more graceful error handling.

The two methods that have production callers—IterateSanctionedAddresses and IterateTemporaryEntries—are both called in x/sanction/keeper/genesis.go (lines 68 and 81), and both properly check the error return with if err := method(...); err != nil { panic(...) }. However, converting returned errors to panics in export genesis functions undermines the purpose of returning errors rather than using must-style functions. Consider handling errors more gracefully in genesis operations. Additionally, IterateProposalIndexEntries has no production callers and its error return is unused in test code; verify whether this method is needed or should be removed.

Comment thread x/sanction/keeper/grpc_query.go
Comment thread x/sanction/keeper/keeper.go
@nagarajdivine nagarajdivine force-pushed the feat/sanction-module-collections branch from 346654e to 1c4db62 Compare December 11, 2025 16:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
x/sanction/keeper/grpc_query.go (1)

164-191: Total count is still incorrect when using key-based pagination.

The issue raised in the previous review remains unresolved. When startPropID is set (key-based pagination), the code increments total for skipped entries (lines 168-171, 175-178) and again for entries that pass the filter (lines 182-184). The total should represent all entries for the address, counted once per entry, before applying the pagination filter.

Apply this fix to count all entries once before filtering:

 	for ; iter.Valid(); iter.Next() {
 		kv, err := iter.KeyValue()
 		if err != nil {
 			return nil, status.Error(codes.Internal, err.Error())
 		}
 
 		pid := kv.Key.K2()
+
+		// Count all entries for this address regardless of pagination
+		if countTotal {
+			total++
+		}
 
 		// :white_check_mark: FIX: Handle both forward and reverse key pagination
 		if startPropID != nil {
 			if !reverse && pid < *startPropID {
 				// Forward mode: skip entries before startPropID
-				if countTotal {
-					total++
-				}
 				continue
 			}
 			if reverse && pid > *startPropID {
 				// Reverse mode: skip entries after startPropID
-				if countTotal {
-					total++
-				}
 				continue
 			}
 		}
 
-		if countTotal {
-			total++
-		}
-
 		items = append(items, &sanction.TemporaryEntry{
x/sanction/keeper/keeper.go (1)

232-263: Performance issue: getLatestTempEntry still walks the entire store.

The issue raised in the previous review remains unresolved. This method walks all temporary entries in the store (O(n) across all addresses) and is called from IsSanctionedAddr, a critical hot path invoked on every transaction. Use prefix-based iteration with reverse ordering to scan only entries for the specific address.

Apply this fix to use prefix-based reverse iteration:

 func (k Keeper) getLatestTempEntry(ctx sdk.Context, addr sdk.AccAddress) []byte {
 	if len(addr) == 0 {
 		return nil
 	}
-
-	var latestValue []byte
-	var latestPropID uint64
-	found := false
-
-	// Walk all temporary entries and find the one for this address with highest propID
-	err := k.TemporaryEntriesStore.Walk(ctx, nil,
-		func(key collections.Pair[sdk.AccAddress, uint64], value []byte) (stop bool, err error) {
-			// Only consider entries for this address
-			if !key.K1().Equals(addr) {
-				return false, nil
-			}
-
-			propID := key.K2()
-			if !found || propID > latestPropID {
-				latestPropID = propID
-				latestValue = value
-				found = true
-			}
-			return false, nil
-		})
-
-	if err != nil {
-		return nil
-	}
-
-	return latestValue
+
+	// Use prefix-based iteration with reverse order to get the latest (highest propID) entry first
+	prefixBytes := make([]byte, 1+len(addr))
+	prefixBytes[0] = byte(len(addr))
+	copy(prefixBytes[1:], addr)
+
+	prefixEnd := prefixEndBytes(prefixBytes)
+
+	iter, err := k.TemporaryEntriesStore.IterateRaw(ctx, prefixBytes, prefixEnd, collections.OrderDescending)
+	if err != nil {
+		return nil
+	}
+	defer iter.Close()
+
+	if iter.Valid() {
+		kv, err := iter.KeyValue()
+		if err != nil {
+			return nil
+		}
+		return kv.Value
+	}
+
+	return nil
 }

Note: You'll need to add a prefixEndBytes helper (similar to the one in grpc_query.go) to this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 346654e and 1c4db62.

📒 Files selected for processing (5)
  • x/sanction/keeper/genesis.go (2 hunks)
  • x/sanction/keeper/gov_hooks.go (1 hunks)
  • x/sanction/keeper/grpc_query.go (4 hunks)
  • x/sanction/keeper/keeper.go (7 hunks)
  • x/sanction/simulation/genesis.go (1 hunks)
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: nullpointer0x00
Repo: provenance-io/provenance PR: 0
File: :0-0
Timestamp: 2024-06-10T19:25:28.209Z
Learning: A GitHub issue was created to track the migration of parameters for the metadata, marker, name, and msgFees modules as indicated by the TODO comments in the codebase. The issue is linked to PR #1932 and can be found at https://github.com/provenance-io/provenance/issues/1935.
📚 Learning: 2024-06-10T19:25:28.209Z
Learnt from: Taztingo
Repo: provenance-io/provenance PR: 0
File: :0-0
Timestamp: 2024-06-10T19:25:28.209Z
Learning: The user has updated the governance parameter structure in `cmd/provenanced/cmd/init.go` to `govGenState.Params.MinDeposit` and added a TODO to verify this change as it relates to a different task.

Applied to files:

  • x/sanction/keeper/gov_hooks.go
  • x/sanction/keeper/keeper.go
  • x/sanction/simulation/genesis.go
📚 Learning: 2024-10-10T23:08:15.256Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2175
File: .golangci.yml:87-87
Timestamp: 2024-10-10T23:08:15.256Z
Learning: The `depguard` definitions in `.golangci.yml` are prefixes (unless they end with `$`), so the entry `- cosmossdk.io/client/v2` covers imports from `cosmossdk.io/client/v2` and its subpackages like `autocli`. Changing imports from `cosmossdk.io/client/v2/autocli` to `cosmossdk.io/client/v2` in `app/app.go` would result in unresolved references because the required code resides in the `autocli` package.

Applied to files:

  • x/sanction/keeper/grpc_query.go
📚 Learning: 2025-08-15T20:34:01.110Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/asset/types/codec.go:9-10
Timestamp: 2025-08-15T20:34:01.110Z
Learning: In Go Cosmos SDK projects, sdk.Msg interface embeds proto.Message interface, making it valid to copy elements from []sdk.Msg to []proto.Message even though the slice types are different. The pattern of declaring AllRequestMsgs as []sdk.Msg for type assertions while copying to []proto.Message for RegisterImplementations is a common and correct pattern.

Applied to files:

  • x/sanction/keeper/grpc_query.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:39:34.095Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/asset/types/util.go:68-102
Timestamp: 2025-08-15T20:39:34.095Z
Learning: In the Provenance codebase, functions with "Must" prefix (like MustGetMarkerAddress) can panic and should only be used when you know they won't panic. Instead, use the twin function that returns an error (like GetMarkerAddress) and handle the error properly.

Applied to files:

  • x/sanction/keeper/genesis.go
📚 Learning: 2024-10-02T02:29:56.018Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/types/signer_utils.go:138-143
Timestamp: 2024-10-02T02:29:56.018Z
Learning: In this codebase, methods like `GetAcc()` and `GetSignerAcc()` are intended to return `nil` if the address is invalid, and address validation is performed elsewhere. These methods should return a single value without an error.

Applied to files:

  • x/sanction/keeper/genesis.go
  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:59:09.909Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/expected_keeper.go:11-19
Timestamp: 2025-08-15T20:59:09.909Z
Learning: The BankKeeper interface methods in Cosmos SDK v0.50.x and Provenance use `context.Context` as the context parameter type, not `sdk.Context`. This applies to methods like SendCoins, HasBalance, GetBalance, SpendableCoin, HasSupply, etc. The expected keeper interfaces should consistently use `context.Context` to match the actual Cosmos SDK bank keeper signatures.

Applied to files:

  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T22:52:24.461Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/keeper.go:74-173
Timestamp: 2025-08-15T22:52:24.461Z
Learning: In the ledger keeper NewKeeper function in x/ledger/keeper/keeper.go, SpicyLemon prefers to allow bankKeeper and registryKeeper dependencies to be nil rather than adding validation that would panic on nil values. The design intentionally supports nil keepers for flexibility.

Applied to files:

  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:59:09.909Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/expected_keeper.go:11-19
Timestamp: 2025-08-15T20:59:09.909Z
Learning: In Cosmos SDK v0.50.x, the bank keeper interface methods use `context.Context` rather than `sdk.Context`. The BankKeeper interface should use `context.Context` for methods like SendCoins, HasBalance, GetBalance, etc.

Applied to files:

  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-02T01:43:01.360Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/marker/types/send_restrictions.go:11-11
Timestamp: 2024-10-02T01:43:01.360Z
Learning: In `x/marker/types/send_restrictions.go`, the `transferAgentKey` is only used for storing data in ephemeral contexts, so changing its value does not impact backward compatibility.

Applied to files:

  • x/sanction/keeper/keeper.go
📚 Learning: 2025-08-15T20:59:51.949Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/keys.go:3-12
Timestamp: 2025-08-15T20:59:51.949Z
Learning: In Cosmos SDK, key prefixes only need to be unique within a given module's store, not across the entire application. Each module operates within its own isolated key-value store namespace, so the same byte prefixes can be safely reused across different modules without causing collisions.

Applied to files:

  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-08T18:12:51.936Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/types/signer_utils.go:306-308
Timestamp: 2024-10-08T18:12:51.936Z
Learning: When using `sdk.AccAddress` as map keys in `AuthzCache`, casting to `string(addr)` is acceptable and preferred over `addr.String()` due to performance considerations and the keys being used internally.

Applied to files:

  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-02T16:55:10.172Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/mocks_test.go:425-427
Timestamp: 2024-10-02T16:55:10.172Z
Learning: In this codebase, when using `sdk.AccAddress` as map keys, casting to `string` is preferred over calling `.String()` for performance reasons.

Applied to files:

  • x/sanction/keeper/keeper.go
📚 Learning: 2024-06-10T19:25:28.209Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 0
File: :0-0
Timestamp: 2024-06-10T19:25:28.209Z
Learning: The `GetLockedCoins` function in `x/hold/keeper/locked_coins.go` must conform to the `banktypes.GetLockedCoinsFn` type, which does not allow returning an error. In cases where `k.GetHoldCoins` encounters an error, using `panic` is considered appropriate due to the severity of such errors.

Applied to files:

  • x/sanction/keeper/keeper.go
📚 Learning: 2024-10-24T19:50:09.457Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2198
File: app/app_test.go:448-528
Timestamp: 2024-10-24T19:50:09.457Z
Learning: In `app/app_test.go`, when testing that the encoder is correctly wired to handle a governance `Proposal` with a `ParameterChangeProposal`, it's sufficient to have a basic test case without adding additional test cases, since the types and encoders are defined and maintained in external libraries outside our control.

Applied to files:

  • x/sanction/simulation/genesis.go
📚 Learning: 2024-10-10T23:19:54.565Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2176
File: app/upgrades_test.go:610-610
Timestamp: 2024-10-10T23:19:54.565Z
Learning: In `app/upgrades_test.go`, we prefer to keep TODO comments (like `TODO[viridian]`) to handle code deletions manually, and do not want to implement automated processes for code removal, especially for unit tests.

Applied to files:

  • x/sanction/simulation/genesis.go
🧬 Code graph analysis (2)
x/sanction/keeper/grpc_query.go (5)
x/sanction/query.pb.go (6)
  • QuerySanctionedAddressesResponse (171-176)
  • QuerySanctionedAddressesResponse (180-180)
  • QuerySanctionedAddressesResponse (181-183)
  • QueryTemporaryEntriesResponse (281-285)
  • QueryTemporaryEntriesResponse (289-289)
  • QueryTemporaryEntriesResponse (290-292)
internal/provutils/pair.go (1)
  • Pair (6-9)
x/sanction/sanction.pb.go (3)
  • TemporaryEntry (124-131)
  • TemporaryEntry (135-135)
  • TemporaryEntry (136-138)
x/sanction/keeper/keys.go (1)
  • ToTempStatus (145-155)
x/sanction/keeper/keeper.go (1)
  • Keeper (19-50)
x/sanction/keeper/genesis.go (2)
x/sanction/keeper/keeper.go (1)
  • Keeper (19-50)
x/sanction/sanction.pb.go (3)
  • TemporaryEntry (124-131)
  • TemporaryEntry (135-135)
  • TemporaryEntry (136-138)
🪛 GitHub Actions: Lint
x/sanction/simulation/genesis.go

[error] 47-47: golangci-lint run: directive //nolint:gosec // G115: Int63n used for simulation randomness; casting to uint64 is safe and intentional. is unused for linter "gosec" (nolintlint)

🪛 GitHub Check: golangci-lint
x/sanction/simulation/genesis.go

[failure] 53-53:
directive //nolint:gosec // G115: Int63n used for simulation randomness; casting to uint64 is safe and intentional. is unused for linter "gosec" (nolintlint)


[failure] 47-47:
directive //nolint:gosec // G115: Int63n used for simulation randomness; casting to uint64 is safe and intentional. is unused for linter "gosec" (nolintlint)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: tests (04)
  • GitHub Check: test-race (02)
  • GitHub Check: tests (02)
  • GitHub Check: tests (00)
  • GitHub Check: tests (01)
  • GitHub Check: tests (03)
  • GitHub Check: test-race (01)
  • GitHub Check: test-race (00)
  • GitHub Check: test-race (03)
  • GitHub Check: test-race (04)
  • GitHub Check: build-linux
  • GitHub Check: Build OSX
  • GitHub Check: ghcr-publish
  • GitHub Check: docker
  • GitHub Check: heighliner-docker
  • GitHub Check: Analyze (go)
🔇 Additional comments (15)
x/sanction/keeper/gov_hooks.go (1)

100-102: LGTM! Proper error handling for collections-based deletion.

The error handling for DeleteGovPropTempEntries is appropriate. Panicking with a descriptive error message in a governance hook context ensures critical failures don't go unnoticed.

x/sanction/keeper/genesis.go (2)

68-73: LGTM! Proper error handling for collections-based iteration.

The error handling for IterateSanctionedAddresses is appropriate. Panicking with a descriptive error message during genesis export ensures critical failures are caught.


81-94: LGTM! Proper error handling for collections-based iteration.

The error handling for IterateTemporaryEntries is appropriate. Panicking with a descriptive error message during genesis export ensures critical failures are caught.

x/sanction/keeper/grpc_query.go (5)

44-66: LGTM! Clean migration to collection-based pagination.

The refactoring to use query.CollectionPaginate over k.SanctionedAddressesStore is clean and properly handles errors. The response construction correctly initializes the Addresses slice to avoid nil values.


83-109: LGTM! Well-structured conditional query handling.

The conditional logic cleanly separates address-filtered queries (delegated to temporaryEntriesForAddress) from unfiltered queries (using standard CollectionPaginate). The unfiltered path properly constructs the response with error handling.


112-163: LGTM! Proper pagination setup and prefix construction.

The pagination parameter parsing and prefix construction correctly match the TemporaryKeyCodec format. The handling of pagination.Key as an 8-byte uint64 for key-based pagination is appropriate.


193-226: LGTM! Correct post-processing and response construction.

The reverse ordering, offset/limit slicing, and NextKey calculation are correctly implemented. The response properly constructs the pagination metadata (aside from the total counting issue flagged separately).


236-252: LGTM! Standard prefix range helper.

The prefixEndBytes helper correctly computes the end boundary for prefix-based iteration by incrementing bytes from right to left.

x/sanction/keeper/keeper.go (7)

52-124: LGTM! Well-structured collections migration in NewKeeper.

The refactoring to use store.KVStoreService and collections-based storage is well-implemented. The schema builder pattern with custom key codecs ensures backward compatibility. The panic on schema build failure is appropriate for constructor-level errors.


132-150: LGTM! Proper collections-based sanctioned address check.

The logic correctly checks temporary entries first, then permanent sanctions using SanctionedAddressesStore.Has. The error handling appropriately returns false on errors (aside from the performance concern in getLatestTempEntry flagged separately).


154-175: LGTM! Proper error handling in SanctionAddresses.

The collections-based updates are properly wrapped with error handling and descriptive error messages. The error propagation pattern is consistent throughout.


177-195: LGTM! Consistent error handling in UnsanctionAddresses.

The collections-based removals properly handle errors with descriptive messages. The pattern mirrors SanctionAddresses appropriately.


207-229: LGTM! Proper collections-based temporary entry addition.

The function correctly updates both TemporaryEntriesStore and ProposalIndex with proper error handling. The use of collections.Join for composite keys is appropriate.


266-342: LGTM! Proper collections-based deletion with error handling.

Both deletion methods correctly use the collect-then-delete pattern to avoid iterator invalidation. The error handling and propagation are appropriate with descriptive error messages.


346-458: LGTM! Collections-based iteration and parameter methods.

The iteration methods correctly use Walk with appropriate error returns. The parameter methods properly interact with ParameterStore using collection-based gets and sets with error handling. The GetParams method appropriately handles missing parameters by falling back to defaults.

Comment thread x/sanction/simulation/genesis.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1c4db62 and a30c6d5.

📒 Files selected for processing (1)
  • x/sanction/simulation/genesis.go (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: nullpointer0x00
Repo: provenance-io/provenance PR: 0
File: :0-0
Timestamp: 2024-06-10T19:25:28.209Z
Learning: A GitHub issue was created to track the migration of parameters for the metadata, marker, name, and msgFees modules as indicated by the TODO comments in the codebase. The issue is linked to PR #1932 and can be found at https://github.com/provenance-io/provenance/issues/1935.
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/migrations_v4.go:57-80
Timestamp: 2024-10-02T02:06:21.664Z
Learning: The `V3WriteNewScope` method in `x/metadata/keeper/migrations_v4.go` must exist until after the migration has been executed and will be deleted as part of the `viridian` cleanup.
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/keeper/migrations_v4.go:57-80
Timestamp: 2024-10-08T18:12:51.935Z
Learning: The `V3WriteNewScope` method in `x/metadata/keeper/migrations_v4.go` must exist until after the migration has been executed and will be deleted as part of the `viridian` cleanup.
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2422
File: x/ledger/keeper/expected_keeper.go:11-19
Timestamp: 2025-08-15T20:59:09.909Z
Learning: The BankKeeper interface methods in Cosmos SDK v0.50.x and Provenance use `context.Context` as the context parameter type, not `sdk.Context`. This applies to methods like SendCoins, HasBalance, GetBalance, SpendableCoin, HasSupply, etc. The expected keeper interfaces should consistently use `context.Context` to match the actual Cosmos SDK bank keeper signatures.
📚 Learning: 2024-10-10T23:19:54.565Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2176
File: app/upgrades_test.go:610-610
Timestamp: 2024-10-10T23:19:54.565Z
Learning: In `app/upgrades_test.go`, we prefer to keep TODO comments (like `TODO[viridian]`) to handle code deletions manually, and do not want to implement automated processes for code removal, especially for unit tests.

Applied to files:

  • x/sanction/simulation/genesis.go
📚 Learning: 2024-10-02T03:23:58.504Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/types/scope_test.go:1355-1364
Timestamp: 2024-10-02T03:23:58.504Z
Learning: In `scope_test.go`, numeric literals are intentionally used for the `Role` field in tests instead of named constants. This approach keeps the lines shorter and reduces false positives when searching for usages of specific party types, as the tests do not depend on the actual names of the roles.

Applied to files:

  • x/sanction/simulation/genesis.go
📚 Learning: 2024-10-02T18:03:10.008Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2140
File: x/metadata/types/signer_utils_test.go:478-493
Timestamp: 2024-10-02T18:03:10.008Z
Learning: In Go tests, modifying byte slices directly using arithmetic operations like addition and subtraction is acceptable, even if it causes overflow, as overflow on `uint8` just wraps around. Avoid flagging such usage, and avoid suggesting bitwise operations which can be harder to read and understand.

Applied to files:

  • x/sanction/simulation/genesis.go
📚 Learning: 2024-10-10T23:18:06.683Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2176
File: app/upgrades.go:221-227
Timestamp: 2024-10-10T23:18:06.683Z
Learning: In the Go codebase, assigning functions to the blank identifier `_` is an acceptable practice to prevent linter warnings about unused functions. This approach is preferred over using `nolint` directives because it avoids linter complaints about unused `nolint` directives when the functions become used again.

Applied to files:

  • x/sanction/simulation/genesis.go
📚 Learning: 2024-06-10T19:25:28.209Z
Learnt from: Taztingo
Repo: provenance-io/provenance PR: 0
File: :0-0
Timestamp: 2024-06-10T19:25:28.209Z
Learning: The user has updated the governance parameter structure in `cmd/provenanced/cmd/init.go` to `govGenState.Params.MinDeposit` and added a TODO to verify this change as it relates to a different task.

Applied to files:

  • x/sanction/simulation/genesis.go
📚 Learning: 2024-10-24T19:50:09.457Z
Learnt from: SpicyLemon
Repo: provenance-io/provenance PR: 2198
File: app/app_test.go:448-528
Timestamp: 2024-10-24T19:50:09.457Z
Learning: In `app/app_test.go`, when testing that the encoder is correctly wired to handle a governance `Proposal` with a `ParameterChangeProposal`, it's sufficient to have a basic test case without adding additional test cases, since the types and encoders are defined and maintained in external libraries outside our control.

Applied to files:

  • x/sanction/simulation/genesis.go
🪛 GitHub Actions: Lint
x/sanction/simulation/genesis.go

[error] 42-42: golangci-lint: directive //nolint:gosec is unused for linter "gosec" (nolintlint)

🪛 GitHub Check: golangci-lint
x/sanction/simulation/genesis.go

[failure] 42-42:
directive //nolint:gosec is unused for linter "gosec" (nolintlint)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: tests (02)
  • GitHub Check: test-race (01)
  • GitHub Check: test-race (03)
  • GitHub Check: test-race (00)
  • GitHub Check: tests (03)
  • GitHub Check: test-race (04)
  • GitHub Check: test-race (02)
  • GitHub Check: tests (00)
  • GitHub Check: tests (04)
  • GitHub Check: tests (01)
  • GitHub Check: build-linux
  • GitHub Check: ghcr-publish
  • GitHub Check: docker
  • GitHub Check: heighliner-docker
  • GitHub Check: Build OSX
  • GitHub Check: Build Linux
  • GitHub Check: Analyze (go)

Comment thread x/sanction/simulation/genesis.go Outdated
@nagarajdivine nagarajdivine force-pushed the feat/sanction-module-collections branch from 1707318 to 6f2d100 Compare December 18, 2025 15:52
@nagarajdivine nagarajdivine force-pushed the feat/sanction-module-collections branch from 6f2d100 to 9c0785b Compare February 12, 2026 19:31

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
x/sanction/keeper/suite_test.go (2)

96-98: ⚠️ Potential issue | 🟡 Minor

store.Delete(key) error is silently ignored.

store.KVStore.Delete (from cosmossdk.io/core/store) returns an error. Ignoring it means ClearState may silently fail to delete entries, causing stale state to leak between tests.

Proposed fix
 	for _, key := range keysToDelete {
-		store.Delete(key)
+		s.Require().NoError(store.Delete(key), "store.Delete")
 	}

181-186: ⚠️ Potential issue | 🟡 Minor

ReqOKDelPropTemp doesn't check the error returned by DeleteGovPropTempEntries.

Per gov_hooks.go (line 100), DeleteGovPropTempEntries now returns an error. This test helper only checks for panics but ignores the returned error. Consider using RequireNotPanicsNoError instead.

Proposed fix
 func (s *BaseTestSuite) ReqOKDelPropTemp(id uint64) {
-	s.Require().NotPanics(func() {
-		s.Keeper.DeleteGovPropTempEntries(s.SdkCtx, id)
-	}, "DeleteGovPropTempEntries(%d)", id)
+	s.T().Helper()
+	s.RequireNotPanicsNoError(func() error {
+		return s.Keeper.DeleteGovPropTempEntries(s.SdkCtx, id)
+	}, "DeleteGovPropTempEntries(%d)", id)
 }
x/sanction/keeper/keeper_test.go (1)

878-884: ⚠️ Potential issue | 🟡 Minor

store.Set(...) errors are silently discarded.

s.GetStore() now returns cosmossdk.io/core/store.KVStore, whose Set method returns an error. The ignored errors here could cause the test setup to silently fail, leading to misleading test results.

Proposed fix
 	for _, id := range []uint64{18, 19, 55, 100000} {
 		for _, addr := range []sdk.AccAddress{randAddr1, randAddr2, randAddr3, randAddr4} {
 			val += 1
-			store.Set(keeper.CreateTemporaryKey(addr, id), []byte{val})
-			store.Set(keeper.CreateProposalTempIndexKey(id, addr), []byte{val})
+			s.Require().NoError(store.Set(keeper.CreateTemporaryKey(addr, id), []byte{val}), "store.Set temp key")
+			s.Require().NoError(store.Set(keeper.CreateProposalTempIndexKey(id, addr), []byte{val}), "store.Set index key")
 		}
 	}
🤖 Fix all issues with AI agents
In `@x/sanction/keeper/export_test.go`:
- Around line 47-50: Update the stale doc comment to reflect the current
function name: change the comment above Keeper.KVStore from "StoreKey, for unit
tests, exposes this keeper's storekey." to something like "KVStore, for unit
tests, exposes this keeper's KV store." or similar; ensure the comment
references KVStore and describes that it returns the keeper's KV store by
calling k.StoreService.OpenKVStore(ctx).

In `@x/sanction/keeper/keeper.go`:
- Around line 419-425: The comment for Keeper.SetParams is inaccurate: when
params is nil the function writes default values into the store (using
sanction.Params with DefaultImmediateSanctionMinDeposit and
DefaultImmediateUnsanctionMinDeposit) rather than deleting stored params to rely
on implicit defaults. Update the docstring/comment for SetParams (and any
related public docs) to state that passing nil will persist default Params into
the store (initializing those fields) instead of removing entries, and mention
the exact defaults written (DefaultImmediateSanctionMinDeposit,
DefaultImmediateUnsanctionMinDeposit) so callers know the stored state after
calling SetParams(nil).
- Around line 144-149: In IsSanctionedAddr, don't silently swallow errors from
k.SanctionedAddressesStore.Has; instead log the error (using the keeper's
logger, e.g., k.Logger or equivalent) and return a conservative result (treat
the address as sanctioned) so an underlying store error cannot allow a
sanctioned address to transact; specifically, update the error branch after
k.SanctionedAddressesStore.Has(ctx, addr) to emit a clear error log including
the err and then return true (or propagate the error if the function signature
is changed to return an error).
- Around line 99-100: Fix the broken comment by joining the split word so it
reads a single coherent line like "// Proposal index: (uint64, AccAddress) ->
[]byte with custom codec" (replace the two lines "// Proposa" and "// l index"
with the single corrected comment) near the keeper struct or the related mapping
in keeper.go so the comment correctly documents the Proposal index.
- Around line 313-320: The current code uses TemporaryEntriesStore.Walk to scan
all entries and filters by key.K1().Equals(addr), causing O(n) work per address;
instead iterate only the entries for that address by using a prefix/range-based
iteration on TemporaryEntriesStore (e.g., WalkPrefix or an iterator created with
the address prefix) to enumerate keys for the given addr, appending to tempKeys
and indexKeys (use collections.Join(key.K2(), addr) as before) and remove the
per-entry equality check; update the block around TemporaryEntriesStore.Walk,
collections.Pair handling, and any code that builds tempKeys/indexKeys to use
the scoped prefix iterator so complexity becomes proportional to the number of
entries for that address rather than the whole store.
🧹 Nitpick comments (6)
x/sanction/codec.go (1)

39-53: Decoded address aliases the input buffer — consider copying.

In Decode, the returned sdk.AccAddress is a sub-slice of the input buffer (line 51). If the caller ever reuses or mutates that buffer, the address will silently change. The same pattern repeats in TemporaryKeyCodec.Decode (line 123) and ProposalIndexKeyCodec.Decode (line 221).

This is typically safe within the collections framework but is a subtle footgun for any other caller.

🛡️ Defensive copy
-	addr := sdk.AccAddress(buffer[1 : 1+addrLen])
+	addr := make(sdk.AccAddress, addrLen)
+	copy(addr, buffer[1:1+addrLen])

Apply similarly in TemporaryKeyCodec.Decode and ProposalIndexKeyCodec.Decode.

x/sanction/keeper/grpc_query.go (2)

146-151: All matching entries are loaded into memory before pagination.

temporaryEntriesForAddress iterates over all temporary entries for the address, collecting them into items, then applies offset/limit in memory. For addresses with many entries, this could be memory-intensive. In practice, the number of temporary entries per address is expected to be small, but it's worth noting.


234-252: Replace prefixEndBytes with storetypes.PrefixEndBytes from the Cosmos SDK.

The function duplicates storetypes.PrefixEndBytes from cosmossdk.io/store/types, which is already used throughout the codebase. Add the import and replace the function call at line 144 with the SDK utility.

x/sanction/keeper/keeper.go (3)

357-366: Performance: IterateTemporaryEntries should use prefix range when addr is provided.

When a specific addr is passed, the Walk still scans all temporary entries. Use a prefix range to scope iteration:

♻️ Suggested approach
 func (k Keeper) IterateTemporaryEntries(ctx sdk.Context, addr sdk.AccAddress, cb func(addr sdk.AccAddress, govPropID uint64, isSanction bool) (stop bool)) error {
-	return k.TemporaryEntriesStore.Walk(ctx, nil, func(key collections.Pair[sdk.AccAddress, uint64], value []byte) (stop bool, err error) {
-		if len(addr) > 0 && !key.K1().Equals(addr) {
-			return false, nil
-		}
-
-		isSanction := IsSanctionBz(value)
-		return cb(key.K1(), key.K2(), isSanction), nil
-	})
+	var rng *collections.PairRange[sdk.AccAddress, uint64]
+	if len(addr) > 0 {
+		rng = collections.NewPrefixedPairRange[sdk.AccAddress, uint64](addr)
+	}
+	return k.TemporaryEntriesStore.Walk(ctx, rng, func(key collections.Pair[sdk.AccAddress, uint64], value []byte) (stop bool, err error) {
+		isSanction := IsSanctionBz(value)
+		return cb(key.K1(), key.K2(), isSanction), nil
+	})
 }

371-379: Performance: IterateProposalIndexEntries should use prefix range when govPropID is provided.

Same pattern — use NewPrefixedPairRange on govPropID instead of scanning everything.

♻️ Suggested approach
 func (k Keeper) IterateProposalIndexEntries(ctx sdk.Context, govPropID *uint64, cb func(govPropID uint64, addr sdk.AccAddress) (stop bool)) error {
-	return k.ProposalIndex.Walk(ctx, nil, func(key collections.Pair[uint64, sdk.AccAddress], _ []byte) (stop bool, err error) {
-		if govPropID != nil && key.K1() != *govPropID {
-			return false, nil
-		}
-
-		return cb(key.K1(), key.K2()), nil
-	})
+	var rng *collections.PairRange[uint64, sdk.AccAddress]
+	if govPropID != nil {
+		rng = collections.NewPrefixedPairRange[uint64, sdk.AccAddress](*govPropID)
+	}
+	return k.ProposalIndex.Walk(ctx, rng, func(key collections.Pair[uint64, sdk.AccAddress], _ []byte) (stop bool, err error) {
+		return cb(key.K1(), key.K2()), nil
+	})
 }

270-278: Use NewPrefixedPairRange to scope ProposalIndex walk by govPropID.

Since ProposalIndex is keyed by (govPropID, address), use a prefix range on govPropID to avoid scanning all entries. This pattern is already used elsewhere in the same module.

♻️ Suggested approach
-	err := k.ProposalIndex.Walk(ctx, nil,
-		func(key collections.Pair[uint64, sdk.AccAddress], _ []byte) (stop bool, err error) {
-			if key.K1() == govPropID {
-				addr := key.K2()
-				toRemove = append(toRemove, collections.Join(addr, govPropID))
-				indexToRemove = append(indexToRemove, key)
-			}
-			return false, nil
-		})
+	rng := collections.NewPrefixedPairRange[uint64, sdk.AccAddress](govPropID)
+	err := k.ProposalIndex.Walk(ctx, rng,
+		func(key collections.Pair[uint64, sdk.AccAddress], _ []byte) (stop bool, err error) {
+			addr := key.K2()
+			toRemove = append(toRemove, collections.Join(addr, govPropID))
+			indexToRemove = append(indexToRemove, key)
+			return false, nil
+		})

Comment thread x/sanction/keeper/export_test.go Outdated
Comment thread x/sanction/keeper/keeper.go Outdated
Comment thread x/sanction/keeper/keeper.go
Comment thread x/sanction/keeper/keeper.go
Comment thread x/sanction/keeper/keeper.go
@nagarajdivine nagarajdivine force-pushed the feat/sanction-module-collections branch from 9c0785b to c75e82e Compare February 12, 2026 20:58
@nagarajdivine nagarajdivine force-pushed the feat/sanction-module-collections branch from c75e82e to b44d66d Compare February 19, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Switch to collections in the sanction module.

1 participant