Skip to content

Conversation

@rick-a-lane-ii
Copy link

@rick-a-lane-ii rick-a-lane-ii commented Oct 15, 2025

Description

Refactors the behavior of deployments and deployment groups when accounts are overdrawn.

Author Checklist

  • included the correct type prefix in the PR title
  • added ! to the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • included comments for documenting Go code
  • updated the relevant documentation or specification
  • reviewed "Files changed" and left comments if necessary
  • confirmed all CI checks have passed

@coderabbitai
Copy link

coderabbitai bot commented Oct 15, 2025

Walkthrough

Adds DeploymentKeeper.OnPauseGroup and MarketKeeper.OnGroupPaused hooks; changes OnEscrowAccountClosed to decide per-group target state (GroupPaused vs GroupClosed) and call pausable/closable validations and corresponding hooks; centralizes group resource closing into closeMarketResourcesForGroup; adds parameterized tests for escrow-account-closure outcomes.

Changes

Cohort / File(s) Summary
Hook Interface Extensions
x/market/hooks/external.go
Added OnPauseGroup(ctx sdk.Context, group dtypes.Group) error to DeploymentKeeper and OnGroupPaused(ctx sdk.Context, id dv1.GroupID) error to MarketKeeper.
Hooks Logic
x/market/hooks/hooks.go
Reworked OnEscrowAccountClosed to derive per-group target state: StateOverdrawnGroupPaused (validate pausable, call OnPauseGroup, notify market via OnGroupPaused and close market resources with InsufficientFunds reason); otherwise → GroupClosed (validate closable, call OnCloseGroup, notify via OnGroupClosed, and close resources with Owner reason). CloseDeployment moved into the non-overdrawn (close) branch.
Keeper Implementation
x/market/keeper/keeper.go
Added OnGroupPaused(ctx, id) to IKeeper/Keeper; introduced closeMarketResourcesForGroup(ctx, id, reason) error to centralize closing orders/bids/leases with a configurable LeaseClosedReason; OnGroupClosed delegates to this helper with LeaseClosedReasonOwner; OnGroupPaused uses it with LeaseClosedReasonInsufficientFunds.
Tests
x/market/hooks/hooks_test.go
New parameterized test TestEscrowAccountClose covering overdrawn escrow → groups paused and other states → groups closed; seeds deployments/groups, invokes OnEscrowAccountClosed, and asserts resulting deployment/group states and interactions.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant EscrowHook as Escrow Hook
    participant Hooks as Market Hooks
    participant DeployK as DeploymentKeeper
    participant MarketK as MarketKeeper
    participant MarketIK as Market IKeeper

    EscrowHook->>Hooks: OnEscrowAccountClosed(escrowAcct)
    alt escrow state = StateOverdrawn
        Hooks->>Hooks: target = GroupPaused
        loop per group
            Hooks->>DeployK: ValidatePausable(group)
            DeployK-->>Hooks: ok / err
            Hooks->>DeployK: OnPauseGroup(group)
            DeployK-->>Hooks: ok / err
            Hooks->>MarketK: OnGroupPaused(groupID)
            MarketK-->>Hooks: ok / err
            Hooks->>MarketIK: closeMarketResourcesForGroup(groupID, InsufficientFunds)
            MarketIK-->>Hooks: ok / err
        end
    else escrow state != StateOverdrawn
        Hooks->>Hooks: target = GroupClosed
        loop per group
            Hooks->>DeployK: ValidateClosable(group)
            DeployK-->>Hooks: ok / err
            Hooks->>DeployK: OnCloseGroup(group, target)
            DeployK-->>Hooks: ok / err
            Hooks->>MarketIK: OnGroupClosed(groupID) -> closeMarketResourcesForGroup(groupID, Owner)
            MarketIK-->>Hooks: ok / err
        end
        Hooks->>Hooks: CloseDeployment(...)  %% invoked in close branch
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Review ordering and error handling in x/market/hooks/hooks.go when iterating groups and invoking Validate*/On* hooks.
  • Verify interface signatures in x/market/hooks/external.go match all callers.
  • Inspect closeMarketResourcesForGroup in x/market/keeper/keeper.go to confirm LeaseClosedReason is applied correctly and that orders/bids/leases are closed consistently.
  • Validate tests in x/market/hooks/hooks_test.go for correct seeding, mocks, and assertions covering both paused and closed flows.

Poem

🐰 I nudged a group to sleep when coins ran thin,
Or closed the gate when funding stayed within.
Leases folded neat, orders tucked in rows,
A hoppity patch where tidy logic grows.
Hop on—hooks called, and the meadow knows.

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "refactor: pause deployments when overdrawn" directly aligns with the main objective of the changeset. The changes implement a state-driven deployment handling mechanism where deployment groups are now paused when accounts are overdrawn (StateOverdrawn → GroupPaused) instead of being unconditionally closed. The title accurately captures this behavioral shift, uses the appropriate "refactor" type prefix, and is specific and concise enough for a reviewer scanning the history to understand the primary change without ambiguity.
Description Check ✅ Passed The pull request description "Refactors the behavior of deployments and deployment groups when accounts are overdrawn" is directly related to the changeset. The raw summary shows the changes implement exactly what the description indicates: modifications to escrow account closure behavior that now conditionally pause groups (when StateOverdrawn) versus closing them, new hook methods to support pausing, and tests validating this state-driven behavior. The description accurately captures the core purpose and intent of the refactoring without being vague or off-topic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@github-actions
Copy link

Marked as stale; will be closed in five days.
Cut bait or go fishing!

@rick-a-lane-ii
Copy link
Author

Rebased against the latest main. Minor rework to associated types/imports.
The tests need further rework before committing, and the logic needs tested again in general.
In progress.

@github-actions github-actions bot removed the stale label Nov 1, 2025
@rick-a-lane-ii
Copy link
Author

Added testing. It might be more optimal to change the deployment creation to mocks here, but leaving as-is for now.

@rick-a-lane-ii rick-a-lane-ii marked this pull request as ready for review November 3, 2025 02:38
@rick-a-lane-ii rick-a-lane-ii requested a review from a team as a code owner November 3, 2025 02:38
@rick-a-lane-ii
Copy link
Author

A few notes:

  • A more detailed design review should occur to ensure this is the desired behavior under all circumstances flowing through this particular hook.
  • #Deployment/Deployment Groups Close When Funds Exhaust support#368 cannot be fully closed by this, as it requires several more specific changes (i.e. the balance changes alone would require several more days of effort). I spent more time working on the other items required by the issue, but that would still need much more testing (local, unit, integration, etc.) and it's probably better to have smaller PRs and smaller commits.

Copy link

@coderabbitai coderabbitai bot left a comment

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 (1)
x/market/hooks/hooks_test.go (1)

125-125: Static analysis false positive (integer overflow).

The gosec warning about integer overflow from int to uint32 is a false positive here, since groupCount is 3 and i+1 will never exceed uint32 range. However, if you prefer to silence the linter, you can make the loop variable explicitly typed:

-	for i := range groups {
+	for i := 0; i < groupCount; i++ {
 		groups[i] = testutil.DeploymentGroup(t, did, uint32(i+1))
 	}

This is optional and doesn't affect correctness.

Based on static analysis hints.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26cf5ae and e0713db.

📒 Files selected for processing (3)
  • x/market/hooks/external.go (1 hunks)
  • x/market/hooks/hooks.go (1 hunks)
  • x/market/hooks/hooks_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
x/market/hooks/hooks_test.go (3)
testutil/state/suite.go (1)
  • SetupTestSuite (63-65)
x/market/hooks/external.go (2)
  • DeploymentKeeper (12-18)
  • MarketKeeper (20-28)
x/market/hooks/hooks.go (1)
  • New (23-28)
🪛 golangci-lint (2.5.0)
x/market/hooks/hooks_test.go

[high] 125-125: G115: integer overflow conversion int -> uint32

(gosec)

x/market/hooks/hooks.go

[error] 52-52: Error return value of h.dkeeper.CloseDeployment is not checked

(errcheck)


[error] 60-60: Error return value of h.mkeeper.OnGroupClosed is not checked

(errcheck)


[error] 65-65: Error return value of h.mkeeper.OnGroupClosed is not checked

(errcheck)

🔇 Additional comments (2)
x/market/hooks/external.go (1)

17-17: LGTM! Clean interface extension.

The new OnPauseGroup hook follows the same pattern as existing lifecycle hooks and provides the necessary API for pausing groups when escrow accounts become overdrawn.

x/market/hooks/hooks_test.go (1)

52-106: LGTM! Comprehensive test coverage.

The test effectively validates both scenarios:

  • Overdrawn accounts result in active deployments with paused groups
  • Accounts in good standing result in closed deployments with closed groups

The test structure is clear and assertions appropriately verify the expected state transitions.

@rick-a-lane-ii rick-a-lane-ii force-pushed the rick/support-issue-368 branch 2 times, most recently from 8be2416 to 713928a Compare November 3, 2025 05:19
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
x/market/hooks/hooks_test.go (2)

125-125: Optional: Rewrite conversion to silence static analysis.

The current conversion is safe (i ranges 0-2), but rewriting as uint32(i)+1 is more idiomatic and avoids the gosec warning.

Apply this diff:

-		groups[i] = testutil.DeploymentGroup(t, did, uint32(i+1))
+		groups[i] = testutil.DeploymentGroup(t, did, uint32(i)+1)

79-104: Consider adding tests for validation failure paths.

The current tests assume all groups pass ValidatePausable and ValidateClosable. Consider adding test cases where some groups fail validation to ensure the hook handles these edge cases gracefully (though this may be deferred to a follow-up PR given the preference for small, incremental changes).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8be2416 and 713928a.

📒 Files selected for processing (4)
  • x/market/hooks/external.go (1 hunks)
  • x/market/hooks/hooks.go (1 hunks)
  • x/market/hooks/hooks_test.go (1 hunks)
  • x/market/keeper/keeper.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
x/market/keeper/keeper.go (1)
x/escrow/keeper/keeper.go (1)
  • Keeper (30-50)
x/market/hooks/hooks_test.go (3)
testutil/state/suite.go (1)
  • SetupTestSuite (63-65)
x/market/hooks/external.go (2)
  • DeploymentKeeper (12-18)
  • MarketKeeper (20-29)
x/market/hooks/hooks.go (1)
  • New (23-28)
x/market/hooks/external.go (1)
x/deployment/query/types.go (1)
  • Group (71-71)
🪛 golangci-lint (2.5.0)
x/market/hooks/hooks_test.go

[high] 125-125: G115: integer overflow conversion int -> uint32

(gosec)

🔇 Additional comments (7)
x/market/hooks/external.go (1)

17-17: LGTM! Clean interface additions.

The new OnPauseGroup and OnGroupPaused hooks follow the established pattern and naming convention, providing a clear separation between pause and close semantics.

Also applies to: 25-25

x/market/hooks/hooks.go (2)

45-53: LGTM! Clear state mapping logic.

The switch statement correctly maps escrow states to group lifecycle states: overdrawn accounts pause groups while other states trigger full closure. The conditional deployment closure (line 52) ensures deployments remain active when groups are only paused.


55-68: LGTM! State-driven group lifecycle handling.

The refactored loop correctly separates pause and close semantics:

  • Paused groups: validated via ValidatePausable, then OnPauseGroup + OnGroupPaused
  • Closed groups: validated via ValidateClosable, then OnCloseGroup + OnGroupClosed

This addresses the previous concern about calling OnGroupClosed for paused groups—the appropriate hooks are now invoked for each state.

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

32-32: LGTM! Interface extension for pause semantics.

The OnGroupPaused method completes the pause/close separation at the keeper interface level.


350-363: Excellent refactoring that addresses previous review concerns.

The separation of OnGroupClosed and OnGroupPaused with distinct LeaseClosedReason values addresses the semantic inconsistency flagged in earlier reviews:

  • Paused groups → LeaseClosedReasonInsufficientFunds
  • Closed groups → LeaseClosedReasonOwner

The documentation (lines 358-361) clearly explains the current behavior and acknowledges future extensibility considerations.


366-415: LGTM! Clean consolidation of resource-closing logic.

The closeMarketResourcesForGroup helper effectively centralizes order/bid/lease closure with a parameterized reason (line 374), enabling both OnGroupClosed and OnGroupPaused to share the same workflow while maintaining correct semantic tracking.

x/market/hooks/hooks_test.go (1)

52-106: LGTM! Comprehensive test coverage for the main scenarios.

The parameterized test clearly validates both overdrawn and good-standing account closures, asserting the correct deployment and group states for each case. The test structure is clean and readable.

@rick-a-lane-ii rick-a-lane-ii force-pushed the rick/support-issue-368 branch 2 times, most recently from 9390941 to 0963adc Compare November 3, 2025 05:55
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
x/market/hooks/hooks_test.go (1)

187-187: Optional: Make the safe integer conversion explicit.

The conversion uint32(i)+1 is flagged by static analysis because i has type int. In practice, this is safe since groupCount=3 means i ∈ {0,1,2}, but making the range explicit would silence the warning.

Apply this diff to make the conversion explicit:

-	for i := range groups {
-		groups[i] = testutil.DeploymentGroup(t, did, uint32(i)+1)
+	for i := 0; i < groupCount; i++ {
+		groups[i] = testutil.DeploymentGroup(t, did, uint32(i+1))
 		groups[i].State = ti.groupState
 	}

This keeps the index within known bounds and makes the safe conversion clear to both static analyzers and code reviewers.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9390941 and 7ff090b.

📒 Files selected for processing (4)
  • x/market/hooks/external.go (1 hunks)
  • x/market/hooks/hooks.go (1 hunks)
  • x/market/hooks/hooks_test.go (1 hunks)
  • x/market/keeper/keeper.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
x/market/hooks/external.go (1)
x/deployment/query/types.go (1)
  • Group (71-71)
x/market/keeper/keeper.go (1)
x/escrow/keeper/keeper.go (1)
  • Keeper (30-50)
x/market/hooks/hooks_test.go (3)
x/market/keeper/keeper.go (2)
  • Keeper (49-56)
  • IKeeper (18-46)
testutil/state/suite.go (1)
  • SetupTestSuite (63-65)
x/market/hooks/external.go (2)
  • DeploymentKeeper (12-18)
  • MarketKeeper (20-29)
🪛 golangci-lint (2.5.0)
x/market/hooks/hooks_test.go

[high] 187-187: G115: integer overflow conversion int -> uint32

(gosec)

🔇 Additional comments (7)
x/market/hooks/external.go (1)

17-17: LGTM: Well-designed interface additions for pause lifecycle.

The new OnPauseGroup and OnGroupPaused methods cleanly extend the existing lifecycle hooks to support pausing groups separately from closing them. The method signatures are consistent with the existing OnCloseGroup and OnGroupClosed patterns, ensuring a coherent interface design.

Also applies to: 25-25

x/market/hooks/hooks.go (2)

45-53: LGTM: Correct state-driven deployment handling.

The logic correctly distinguishes between overdrawn accounts (which should pause the deployment) and other closure scenarios (which should close the deployment). The separation ensures that deployments remain recoverable when accounts are merely overdrawn rather than permanently closed.


55-68: LGTM: Well-structured per-group state transitions.

The refactored group processing correctly:

  • Validates group state before transitions (pausable vs. closable)
  • Routes to appropriate hooks based on target state
  • Maintains separation between pause and close semantics

This addresses the semantic inconsistency flagged in earlier reviews by invoking OnGroupPaused for paused groups and OnGroupClosed only for closed groups.

x/market/hooks/hooks_test.go (1)

58-168: LGTM: Comprehensive parameterized test coverage.

The test suite thoroughly validates the escrow account closure behavior across multiple scenarios:

  • Overdrawn vs. closed accounts
  • Active vs. closed deployments
  • Invalid account states

The table-driven approach makes it easy to verify all state combinations and ensures the pause vs. close logic works correctly in different contexts.

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

32-32: LGTM: Interface addition completes the pause lifecycle.

The OnGroupPaused method properly extends the IKeeper interface to handle paused groups, complementing the existing OnGroupClosed method.


350-363: LGTM: Clean separation of close and pause semantics.

The refactoring correctly:

  • Delegates to a shared helper that eliminates duplication
  • Uses LeaseClosedReasonOwner for group closures (deployment owner initiated)
  • Uses LeaseClosedReasonInsufficientFunds for group pauses (account overdrawn)

The inline comments and TODO appropriately document the current hardcoded approach and flag potential future enhancements if multiple pause reasons are needed. This is a pragmatic solution that addresses the semantic inconsistency raised in earlier reviews.


365-415: LGTM: Well-refactored resource cleanup with proper parameterization.

The closeMarketResourcesForGroup helper successfully consolidates the resource-closing logic and parameterizes it by LeaseClosedReason. This ensures that leases closed due to pausing are correctly tagged with LeaseClosedReasonInsufficientFunds, while leases closed due to normal group closure use LeaseClosedReasonOwner.

Line 374 correctly applies the parameterized reason when closing leases, which was a key concern in earlier reviews about accurate state tracking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant