Skip to content

fix(cardano): fix multiple accounting details - #767

Merged
scarmuega merged 2 commits into
mainfrom
fix/accounting-details
Oct 24, 2025
Merged

fix(cardano): fix multiple accounting details#767
scarmuega merged 2 commits into
mainfrom
fix/accounting-details

Conversation

@scarmuega

@scarmuega scarmuega commented Oct 24, 2025

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Collateral-aware fee computation for Alonzo-era transactions.
    • Enabled debug printing for multi-era stake delegations.
  • Bug Fixes

    • Reward application now validates spendability before applying.
    • Deregistration records pool and delegation states more explicitly.
    • Account exports now include all accounts (no special filtering).
  • Breaking Changes

    • Removed public methods for clearing epoch values.
    • Block/transaction visitor API signatures changed; callers must adapt.

@coderabbitai

coderabbitai Bot commented Oct 24, 2025

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

Walkthrough

This PR adds collateral-aware fee computation for Alonzo-era transactions (UTXO lookup), tightens reward application to require spendability and changes missing-account handling to a panic, removes two public EpochValue clearing methods, switches deregistration to explicit replace calls, and simplifies account dump output.

Changes

Cohort / File(s) Summary
Collateral-aware fee computation & visitor API
crates/cardano/src/roll/epochs.rs, crates/cardano/src/roll/mod.rs, crates/cardano/src/roll/txs.rs
Introduced compute_alonzo_collateral and define_tx_fees to derive fees from collateral when explicit fees are invalid; extended BlockVisitor::visit_tx to accept utxos: &HashMap<TxoRef, OwnedMultiEraOutput> and propagated the new parameter to implementations (one implementation receives it but does not use it).
Reward application & validation
crates/cardano/src/estart/rewards.rs, crates/cardano/src/rewards/mod.rs
AssignRewards::apply now expects the target account (panics if missing) instead of early-returning with a warning; BoundaryVisitor::visit_account logs reward amount; RewardMap::take_for_apply requires both account registration and reward spendability to move rewards to applied, and updates counters accordingly.
EpochValue API change
crates/cardano/src/model.rs
Removed public methods pub fn clear(&mut self, epoch: Epoch) and pub fn clear_unchecked(&mut self) from EpochValue<T> (no other behavioral changes to transition/snapshot logic reported).
Deregistration state update
crates/cardano/src/roll/accounts.rs
StakeDeregistration::apply replaced clear(epoch) calls with targeted replace(...) calls: pool set to PoolDelegation::NotDelegated, drep replaced with None.
Minor UX / loader / dump changes
crates/cardano/src/rupd/loading.rs, src/bin/dolos/data/dump_state.rs
Replaced a dedicated dump_account filter with generic dump_state::<AccountState> for accounts; a comment was changed to a TODO questioning a registration-status check.
Pallas extras debug derive
crates/cardano/src/pallas_extras.rs
Added #[derive(Debug)] to MultiEraStakeDelegation.

Sequence Diagram(s)

sequenceDiagram
    participant DeltaBuilder as DeltaBuilder (crawler)
    participant BlockVisitor as BlockVisitor::visit_tx
    participant FeeLogic as define_tx_fees / compute_alonzo_collateral
    participant UtxoMap as UTXO Map

    DeltaBuilder->>BlockVisitor: visit_tx(block, tx, utxos)
    BlockVisitor->>FeeLogic: define_tx_fees(tx, utxos)
    alt tx.fee is valid
        FeeLogic-->>BlockVisitor: return explicit fee
    else tx.fee invalid
        FeeLogic->>UtxoMap: lookup collateral inputs
        alt collateral inputs found
            FeeLogic-->>BlockVisitor: return sum(collateral)
        else collateral inputs missing
            FeeLogic->>FeeLogic: compute_alonzo_collateral(tx)
            FeeLogic-->>BlockVisitor: return computed collateral fee
        end
    end
Loading
sequenceDiagram
    participant RewardApplier as AssignRewards::apply
    participant RewardMap as RewardMap::take_for_apply
    participant AccountState as AccountState (lookup)

    RewardApplier->>AccountState: lookup account for reward.target
    alt account exists
        RewardMap->>RewardMap: check registered && reward.spendable
        alt both true
            RewardMap-->>RewardApplier: Some(reward) (applied_effective++)
        else
            RewardMap-->>RewardApplier: None (applied_unspendable++)
        end
    else account missing
        RewardApplier->>RewardApplier: panic ("existing account")
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

"I'm a rabbit with a patch and a pen,
Fees from UTXOs now counted again,
Rewards must be spendable to apply,
Missing accounts will loudly cry — oh my! 🐇✨"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title "fix(cardano): fix multiple accounting details" uses generic and non-descriptive language that fails to communicate the specific nature of the changes to someone scanning PR history. While the title is loosely related to the changeset (these are fixes in the cardano crate), the term "accounting details" is vague and could refer to numerous different types of changes. The changeset spans diverse areas including reward handling, fee computation with collateral awareness, account deregistration logic, epoch value clearing, and reward mapping conditions, but the title provides no indication of which of these areas (or combination thereof) represents the main focus of the PR. Consider revising the title to be more specific about the primary fix or the most significant change. For example, if the main focus is the collateral-aware fee computation, that should be highlighted. If the PR addresses multiple distinct issues, the title could reference the most impactful one, or the title could be more specific about the scope (e.g., "fix(cardano): correct reward spendability and fee computation logic" would better convey the substantive changes).
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

📜 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 5467003 and 513d035.

📒 Files selected for processing (3)
  • crates/cardano/src/estart/rewards.rs (2 hunks)
  • crates/cardano/src/roll/epochs.rs (3 hunks)
  • src/bin/dolos/data/dump_state.rs (1 hunks)

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

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
crates/cardano/src/rupd/loading.rs (1)

131-131: Fix typo in TODO comment.

The comment contains "ths" which should be "this".

-            // TODO: check if we really need to make ths check. It might be adding noise to the data.
+            // TODO: check if we really need to make this check. It might be adding noise to the data.
crates/cardano/src/roll/epochs.rs (2)

217-230: Collapse else { if .. } and keep logic identical.

Minor readability fix flagged by static analysis. No behavior change.

-    } else {
-        if let Some(collateral) = tx.total_collateral() {
-            Ok(collateral)
-        } else {
-            compute_alonzo_collateral(tx, utxos)
-        }
-    }
+    } else if let Some(collateral) = tx.total_collateral() {
+        Ok(collateral)
+    } else {
+        compute_alonzo_collateral(tx, utxos)
+    }

193-215: Use of consumes() for invalid Alonzo collateral is correct; apply optional style/safety improvements.

The consumes() accessor correctly returns only collateral inputs for invalid transactions in Alonzo, so the semantic logic is sound. The code is safe as-is.

Consider these optional style and safety improvements:

-    let mut total = 0;
+    let mut total: u64 = 0;
     
      for input in tx.consumes() {
          let utxo = utxos
              .get(&TxoRef::from(&input))
              .ok_or(ChainError::BrokenInvariant(BrokenInvariant::MissingUtxo(
                  TxoRef::from(&input),
              )))?;
          utxo.with_dependent(|_, utxo| {
-            total += utxo.value().coin();
+            total = total.saturating_add(utxo.value().coin());
          });
      }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ce1aa2 and 5467003.

📒 Files selected for processing (10)
  • crates/cardano/src/estart/rewards.rs (3 hunks)
  • crates/cardano/src/model.rs (0 hunks)
  • crates/cardano/src/pallas_extras.rs (1 hunks)
  • crates/cardano/src/rewards/mod.rs (1 hunks)
  • crates/cardano/src/roll/accounts.rs (1 hunks)
  • crates/cardano/src/roll/epochs.rs (3 hunks)
  • crates/cardano/src/roll/mod.rs (2 hunks)
  • crates/cardano/src/roll/txs.rs (3 hunks)
  • crates/cardano/src/rupd/loading.rs (1 hunks)
  • src/bin/dolos/data/dump_state.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • crates/cardano/src/model.rs
🧰 Additional context used
🧬 Code graph analysis (4)
crates/cardano/src/roll/mod.rs (2)
crates/cardano/src/roll/epochs.rs (1)
  • visit_tx (261-273)
crates/cardano/src/roll/txs.rs (2)
  • visit_tx (100-114)
  • tx (109-109)
crates/cardano/src/estart/rewards.rs (1)
crates/cardano/src/rewards/mod.rs (2)
  • total_value (38-40)
  • total_value (131-136)
src/bin/dolos/data/dump_state.rs (2)
crates/cardano/src/rupd/loading.rs (2)
  • state (115-115)
  • state (125-125)
crates/cardano/src/ewrap/loading.rs (6)
  • state (38-38)
  • state (77-77)
  • state (95-95)
  • state (113-113)
  • state (123-123)
  • state (133-133)
crates/cardano/src/roll/epochs.rs (2)
crates/core/src/lib.rs (8)
  • hash (498-498)
  • from (77-79)
  • from (83-85)
  • from (89-91)
  • from (122-124)
  • from (128-132)
  • from (139-141)
  • from (145-147)
crates/cardano/src/owned.rs (1)
  • hash (34-36)
🪛 GitHub Actions: CI
crates/cardano/src/estart/rewards.rs

[error] 3-3: unused import: pallas::ledger::primitives::StakeCredential

🪛 GitHub Check: Check Build
crates/cardano/src/estart/rewards.rs

[failure] 3-3:
unused import: pallas::ledger::primitives::StakeCredential

crates/cardano/src/roll/epochs.rs

[failure] 223-223:
this else { if .. } block can be collapsed

🔇 Additional comments (11)
crates/cardano/src/pallas_extras.rs (1)

114-114: LGTM!

Adding Debug derive improves debugging capabilities for MultiEraStakeDelegation.

src/bin/dolos/data/dump_state.rs (1)

307-307: LGTM!

The change to use the generic dump_state function aligns with the existing pattern and reduces code duplication.

crates/cardano/src/roll/accounts.rs (1)

312-316: LGTM!

The explicit replace calls make the deregistration logic clearer by showing exactly what state is being set (NotDelegated and None respectively) instead of using generic clear methods.

crates/cardano/src/estart/rewards.rs (2)

72-74: LGTM!

The enhanced warning message with the reward amount provides better debugging information.


24-25: The change is correct and the expect() cannot panic.

The verification confirms that accounts are guaranteed to exist when AssignRewards::apply() is called because:

  1. visit_account iterates only over existing AccountState entities loaded directly from the state store
  2. AssignRewards deltas are created only when the reward exists (line 71 check)
  3. During commit, the entity is initialized as Some(entity) and no prior deltas remove or delete accounts
  4. The expect("existing account") is safe and appropriate

The upstream checks in the state store iteration provide sufficient guarantee that accounts exist at this stage. The change from warning + early return to expect() is justified.

crates/cardano/src/roll/mod.rs (2)

250-250: LGTM!

The call site correctly passes the utxos reference to visit_tx.


54-62: All BlockVisitor trait implementations properly updated.

Verification confirms that both visit_tx implementations (in TxLogVisitor and EpochStateVisitor) have been updated with the new utxos parameter. EpochStateVisitor actively uses it for collateral-aware fee computation via define_tx_fees(tx, utxos). Other implementations inherit the default trait implementation.

crates/cardano/src/roll/txs.rs (2)

1-2: LGTM!

The HashMap import is necessary to support the updated visit_tx signature.


100-114: LGTM!

The visit_tx signature has been correctly updated to match the BlockVisitor trait. The unused utxos parameter is appropriately marked with _ since this implementation doesn't require UTXO lookups.

crates/cardano/src/rewards/mod.rs (1)

242-256: Disregard this review comment — code logic is correct and not a recent change.

The review describes a scenario that doesn't match the current implementation. The code already checks both registration and spendability at application time, which is the correct design given Cardano's reward timing model. Registration changes take effect over a 2-4 epoch lag, so an account's registration status can differ between when rewards are earned (snapshot time) and when they're applied (2+ epochs later).

The claim about a previous "Some(None) path" doesn't match the current code—there are only Some(reward) and None branches. The TODO comment already documents this architectural decision and the acknowledged uncertainty. Unspendable rewards are tracked separately and can be drained via dedicated methods, and a warning in estart/rewards.rs logs mismatches for monitoring. The current logic is stable and intentional, not a recent "tightening."

Likely an incorrect or invalid review comment.

crates/cardano/src/roll/epochs.rs (1)

266-269: All visit_tx implementations properly updated—no further action needed.

Verification confirms that all visit_tx method definitions have been updated with the new utxos: &HashMap<TxoRef, OwnedMultiEraOutput> parameter:

  • Trait definition (mod.rs): includes parameter ✓
  • TxLogVisitor (txs.rs): includes parameter ✓
  • EpochStateVisitor (epochs.rs): includes parameter ✓

The breaking trait signature change has been consistently propagated across the trait definition and all implementing types.

Comment thread crates/cardano/src/estart/rewards.rs Outdated
@scarmuega
scarmuega merged commit f98781f into main Oct 24, 2025
11 of 12 checks passed
@scarmuega
scarmuega deleted the fix/accounting-details branch October 24, 2025 00:49
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