Skip to content

Conversation

@louisinger
Copy link
Collaborator

@louisinger louisinger commented Oct 13, 2025

Ban script trying to double-spend a VTXO.

@altafan @Kukks please review

Summary by CodeRabbit

  • New Features

    • Automatic banning of detected double-spend attempts using existing ban durations.
    • New "DoubleSpend" conviction category visible in conviction/ban records.
    • Fraud handling now triggers an additional asynchronous reaction path for double-spend cases without changing non-fraud flows.
  • Tests

    • E2E test helpers to locate and pardon convictions for a given script for cleanup and validation.

@louisinger louisinger requested a review from altafan October 13, 2025 15:25
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

Walkthrough

Adds CrimeTypeDoubleSpend, implements banDoubleSpendAttempt to persist single-script DoubleSpend convictions, triggers that ban asynchronously from fraud handling (reactToFraud/service), and adds test helper and calls to pardon convictions in e2e tests.

Changes

Cohort / File(s) Summary
Domain: Conviction enum update
internal/core/domain/conviction.go
Adds CrimeTypeDoubleSpend constant and extends String() mapping to include "DoubleSpend".
Application: Ban logic
internal/core/application/ban.go
New banDoubleSpendAttempt(ctx, vtxo) computes the vtxo output script, constructs a single_script DoubleSpend conviction with existing duration, persists via Convictions repository, and logs warnings on failures.
Application: Fraud handling & service hook
internal/core/application/fraud.go, internal/core/application/service.go
Introduces asynchronous invocations of banDoubleSpendAttempt (goroutine) when a vtxo is detected/settled as Spent (fraud); existing forfeit/broadcast flows remain unchanged.
Tests: e2e updates & helper
test/e2e/e2e_test.go, test/e2e/utils_test.go
Adds pardonConvictionsForScript test helper and inserts calls to it in e2e tests to retrieve and pardon active convictions for a script during test flow/cleanup.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Detector as Fraud Detector
  participant Service as Application Service
  participant Fraud as reactToFraud
  participant Ban as banDoubleSpendAttempt
  participant Repo as Convictions Repo
  participant Log as Logger

  Detector->>Service: vtxo flagged as Spent
  activate Service
  Service->>Fraud: reactToFraud(ctx, vtxo, ...)
  note right of Service #f0f9ff: spawn goroutine for banDoubleSpendAttempt
  Service-->>Ban: async banDoubleSpendAttempt(context.Background(), vtxo)
  deactivate Service

  activate Ban
  Ban->>Ban: compute vtxo output script
  alt script computed
    Ban->>Repo: add conviction {type: DoubleSpend, single_script, duration}
    alt persisted
      Note right of Repo: Conviction stored
    else failed
      Ban->>Log: warn("failed to add DoubleSpend conviction")
    end
  else script error
    Ban->>Log: warn("script computation error")
  end
  deactivate Ban
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Add conviction on double-spend attempt" directly and accurately summarizes the main change in the changeset. The core modifications involve adding a new banDoubleSpendAttempt method, introducing a new CrimeTypeDoubleSpend conviction type, and integrating this logic into the fraud-handling flow to create convictions when double-spend attempts are detected. The title is concise, specific, and uses clear terminology that aligns with both the code changes and the stated PR objectives. A teammate reviewing the commit history would immediately understand that this PR adds conviction/banning logic for double-spend attempts.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd11c2a and cae856a.

📒 Files selected for processing (1)
  • test/e2e/e2e_test.go (1 hunks)
⏰ 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). (3)
  • GitHub Check: unit tests
  • GitHub Check: Build and Scan
  • GitHub Check: integration tests
🔇 Additional comments (1)
test/e2e/e2e_test.go (1)

501-502: The code change is correct. No additional cleanup is required in other tests.

The original review concern was based on an incorrect assumption. TestReactToRedemptionOfRefreshedVtxos deliberately broadcasts a redemption transaction outside the vault process, triggering fraud detection, which bans the script and requires the pardonConvictionsForScript cleanup.

In contrast, TestReactToRedemptionOfVtxosSpentAsync uses normal SDK operations (Receive, NotifyIncomingFunds, SendOffChain, generateBlock) without triggering fraud detection, so no cleanup is needed there.

The pardon call at line 502 is correctly placed as cleanup specific to the fraud detection test.


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.

Copy link
Contributor

@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)
internal/core/application/ban.go (1)

186-207: LGTM! Consider enriching the reason string for better traceability.

The implementation correctly mirrors the existing ban pattern. The empty RoundID is appropriate since double-spend detection occurs via the scanner, outside of round execution.

Optionally, you could include the vtxo outpoint in the reason for enhanced observability:

 	convictions = append(convictions, domain.NewScriptConviction(
 		hex.EncodeToString(outputScript),
 		domain.Crime{
 			Type:   domain.CrimeTypeDoubleSpend,
-			Reason: "double spend attempt",
+			Reason: fmt.Sprintf("double spend attempt on vtxo %s", vtxo.Outpoint),
 		}, &s.banDuration))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d803c98 and 061d75c.

📒 Files selected for processing (3)
  • internal/core/application/ban.go (1 hunks)
  • internal/core/application/service.go (1 hunks)
  • internal/core/domain/conviction.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
internal/core/application/ban.go (2)
internal/core/domain/vtxo.go (2)
  • Vtxo (38-53)
  • Outpoint (15-18)
internal/core/domain/conviction.go (4)
  • Conviction (50-58)
  • NewScriptConviction (135-140)
  • Crime (38-42)
  • CrimeTypeDoubleSpend (21-21)
⏰ 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). (3)
  • GitHub Check: unit tests
  • GitHub Check: integration tests
  • GitHub Check: Build and Scan
🔇 Additional comments (2)
internal/core/application/service.go (1)

2729-2731: LGTM! Double-spend ban integrated correctly.

The new ban path follows the existing fraud reaction pattern at line 2732-2738, executing asynchronously alongside the established fraud handling logic.

internal/core/domain/conviction.go (1)

21-21: LGTM! New crime type properly defined.

The CrimeTypeDoubleSpend constant and its string mapping follow the existing pattern correctly.

Also applies to: 34-34

@louisinger louisinger changed the title Add conviction on double-spent attempt Add conviction on double-spend attempt Oct 13, 2025
Copy link
Contributor

@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: 3

🧹 Nitpick comments (1)
internal/core/application/service.go (1)

731-738: Consider using context.Background() for fraud reaction.

The fraud reaction is spawned asynchronously and may take time to complete. Using the ctx parameter couples this operation to the scanner's context lifetime. Consider using context.Background() to ensure fraud reactions complete independently, similar to the pattern in fraud.go lines 45-54.

Based on learnings.

Apply this diff:

 		if vtxo.Spent {
 			log.Infof("fraud detected on vtxo %s", vtxo.Outpoint.String())
 
 			go func() {
-				if err := s.reactToFraud(ctx, vtxo, mutx); err != nil {
+				if err := s.reactToFraud(context.Background(), vtxo, mutx); err != nil {
 					log.WithError(err).Warnf(
 						"failed to react to fraud for vtxo %s", vtxo.Outpoint.String(),
 					)
 				}
 			}()
 		}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 061d75c and 84885ce.

📒 Files selected for processing (4)
  • internal/core/application/fraud.go (1 hunks)
  • internal/core/application/service.go (1 hunks)
  • test/e2e/e2e_test.go (3 hunks)
  • test/e2e/utils_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-28T08:21:01.170Z
Learnt from: louisinger
PR: arkade-os/arkd#686
File: internal/core/application/fraud.go:47-61
Timestamp: 2025-08-28T08:21:01.170Z
Learning: In reactToFraud function in internal/core/application/fraud.go, the goroutine that waits for confirmation and schedules checkpoint sweep should use context.Background() instead of the request context, as this is intentional design to decouple the checkpoint sweep scheduling from the request lifetime.

Applied to files:

  • internal/core/application/fraud.go
⏰ 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). (3)
  • GitHub Check: unit tests
  • GitHub Check: Build and Scan
  • GitHub Check: integration tests

Copy link
Collaborator

@altafan altafan left a comment

Choose a reason for hiding this comment

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

@louisinger the tx can be put onchain by somebody else and we may end up banning an innocent? Maybe better to handle this case manually?

@Kukks
Copy link
Contributor

Kukks commented Oct 14, 2025

Since the code is here, let's ,make it configurable. Also ensure to write to logs and otel so that we can issue alerts through filters

Co-authored-by: Pietralberto Mazza <18440657+altafan@users.noreply.github.com>
Signed-off-by: louisinger <41042567+louisinger@users.noreply.github.com>
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.

3 participants