Skip to content

Conversation

@freemans13
Copy link
Collaborator

No description provided.

@freemans13 freemans13 self-assigned this Nov 19, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 19, 2025

Claude Code Review - Status: Complete

This PR implements comprehensive child transaction verification before parent deletion in UTXO pruning. The documentation is thorough and the implementation is generally sound with proper fail-safe behavior.

Issue Found:

  • Inconsistent defensive behavior between storage backends - Aerospike pruner makes child verification conditional (controlled by pruner_utxoDefensiveEnabled flag), while SQL pruner always performs verification (hardcoded in query). This could lead to different behavior depending on storage backend. See inline comment for details.

Strengths:

  • Proper fail-safe design (defaults to retention on uncertainty)
  • Comprehensive child verification (checks ALL spending children)
  • Good cancellation handling in cleanup workers
  • Thorough documentation of design evolution

History:

  • Fixed: SQL logic concerns (verified delete_at_height only set when fully spent)
  • Fixed: Cancellation handling verified as correct
  • Updated: Configuration settings concern (they ARE used, but inconsistently between backends)

AND (
-- Extract child TX hash from spending_data (first 32 bytes)
-- Check if this child is NOT stable
NOT EXISTS (
Copy link
Contributor

@github-actions github-actions bot Nov 19, 2025

Choose a reason for hiding this comment

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

Verified - The SQL logic is functionally correct. The allSpent precondition in setDeleteAtHeight ensures only fully-spent parents have delete_at_height set.

Copy link
Contributor

Choose a reason for hiding this comment

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

This concern is addressed by the implementation. Confirmed that delete_at_height is only set when all UTXOs are fully spent (see setDeleteAtHeight in teranode.lua:977-982). The condition allSpent ensures parents with unspent outputs never have delete_at_height set.

The double-negative SQL logic is functionally correct for this use case.

Copy link
Contributor

Choose a reason for hiding this comment

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

Confirmed - the logic is functionally correct. The double-negative structure (NOT EXISTS with AND NOT EXISTS) is complex but properly implements: "Delete only if no output exists with an unstable child."

While the readability concern remains (nested negatives are harder to verify), the implementation correctly ensures all spending children are stable before parent deletion. The allSpent precondition provides additional safety as noted.

@freemans13 freemans13 requested review from liam and ordishs and removed request for ordishs November 27, 2025 17:54
@github-actions
Copy link
Contributor

github-actions bot commented Nov 28, 2025

🤖 Claude Code Review

Status: Complete


Current Review: One documentation inconsistency found.

Issue: Documentation Mismatch on PreserveParentsOfOldUnminedTransactions

The documentation in docs/utxo-safe-deletion.md (lines 336-350) claims the PreserveParentsOfOldUnminedTransactions() function and related files were deleted, stating this preservation mechanism is "no longer needed" because defensive verification replaces it.

Reality:

  • Function still exists in stores/utxo/pruner_unmined.go
  • Still called in services/pruner/worker.go:82 as "Phase 1" before DAH pruning
  • System runs BOTH preservation AND defensive verification (defense-in-depth)

Impact: Low - The dual-layer approach is actually safer than documented. However, the documentation should clarify this is a hybrid approach (preservation + defensive verification) rather than claiming preservation was removed.

Recommendation: Update documentation to reflect that both mechanisms work together as defense-in-depth, rather than claiming one replaces the other.


History:

  • ✅ All previous inline comment issues have been resolved
  • ✅ Both Aerospike and SQL pruners now correctly respect pruner_utxoDefensiveEnabled flag
  • ✅ SQL defensive query logic verified correct
  • ✅ Cancellation handling confirmed proper
  • ✅ Child stability verification checks all children before parent deletion

Overall: The implementation is sound with strong safety guarantees. Only documentation needs minor clarification about the hybrid preservation + verification approach.

# Enable defensive checks before deleting UTXO transactions
# When enabled, verifies that all spending children are mined > BlockHeightRetention blocks ago
# Default: false
pruner_utxoDefensiveEnabled = false
Copy link
Contributor

Choose a reason for hiding this comment

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

Root cause identified:

The SQL pruner service does not have a defensiveEnabled field in its struct (stores/utxo/sql/pruner/pruner_service.go:26-34) and does not read the UTXODefensiveEnabled setting during initialization (pruner_service.go:88-94).

The defensive verification is hardcoded into the SQL DELETE query (lines 230-258) and always runs regardless of the flag value.

Fix needed:
Add defensiveEnabled field to SQL Service struct and conditionally build the query based on this flag, similar to Aerospike implementation at line 483.

Copy link
Contributor

@github-actions github-actions bot Nov 28, 2025

Choose a reason for hiding this comment

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

Verified and resolved - Both implementations now correctly read and respect the defensiveEnabled flag from settings.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 2, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
37.7% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

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.

1 participant