Skip to content

Conversation

@lowhung
Copy link
Collaborator

@lowhung lowhung commented Dec 11, 2025

Description

Fixes incorrect reward calculation during snapshot bootstrap. Previously, the bootstrap process used instantaneous reward balances from DState, which didn't match the actual stake distribution used by Cardano for epoch calculations. This PR updates the parser to extract rewards from the pulsing_rew_update snapshot, ensuring accurate stake distribution and correct SPDD generation.

Related Issue(s)

Fixes #388

How was this tested?

  • Ensure make run for local snapshot bootstrap with epoch 509 works
  • SPDD output verified against cardano-db-sync epoch_stake table using (spdd generation code was unstaged, only used as means to test stake address map creation was valid)
acropolis/tests/integration on  lowhung/generate-spdd-from-bootstrap [$!?] via  v23.8.0
➜ npm run test:spdd

> acropolis-integration-tests@1.0.0 test:spdd
> ts-node spdd.test.ts

(node:88377) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Validating Acropolis SPDD vs DB Sync...

Epoch 509: ✅ 3023 match, ⚠️ 0 mismatch, ❌ 0 missing, 🌀 0 extra (total 3023)
Reached end of available epochs (HTTP 404).

Finished.

Checklist

  • My code builds and passes local tests
  • I added/updated tests for my changes, where applicable
  • I updated documentation (if applicable)
  • CI is green for this PR

Impact / Side effects

Positive: SPDD now matches cardano-db-sync data, enabling accurate stake calculations and proper node initialization when booting from snapshot. It provides the basis for future utxo / address deltas being applied to the correct base state for the stake address map (which is what the spdd is generated from).

Performance: Minimal impact - snapshot parsing is still quick.

Reviewer notes / Areas to focus

  • parse_pulsing_reward_update() method - handles both pulsing and completed reward states
  • Bootstrap message structure changes - ensure downstream consumers handle new fields correctly

@lowhung lowhung force-pushed the lowhung/generate-spdd-from-bootstrap branch from 47a4ee5 to f718dac Compare December 12, 2025 18:25
@lowhung lowhung changed the title feat: test generation of spdd feat: fix rewards calculations with stake address map in bootstrap Dec 13, 2025
@lowhung lowhung requested review from alexwoods, buddhisthead, sandtreader and whankinsiv and removed request for alexwoods December 14, 2025 16:56
@lowhung lowhung linked an issue Dec 14, 2025 that may be closed by this pull request
9 tasks
Copy link
Collaborator

@sandtreader sandtreader left a comment

Choose a reason for hiding this comment

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

Great stuff - agree that UTXOs should be decoded into existing core types in the future. Requested change is watch out for flattening rationals too early - better to preserve them.

d.array()?;
let num: i64 = d.decode()?;
let den: u64 = d.decode()?;
return Ok(num as f64 / den as f64);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Beware of flattening rationals into f64 - precision can be lost. Better to keep as a RationalNumber

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done here :) 8e166e0

use crate::snapshot::utxo::{TransactionInput, TransactionOutput, Value};

/// Helper to create a test UtxoEntry with just an address
fn make_test_utxo(address_bytes: Vec<u8>) -> UtxoEntry {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This and the tests that use it should be in utxos.rs now, I think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done here

/// - Base addresses (type 0-3): 1 byte header + 28 bytes payment + 28 bytes stake
/// - For types 0,1: stake part is key hash
/// - For types 2,3: stake part is script hash
pub fn extract_stake_credential(&self) -> Option<StakeCredential> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We already have this code in address.rs I think

Copy link
Collaborator Author

@lowhung lowhung Dec 16, 2025

Choose a reason for hiding this comment

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

Good point, I wonder if this would suffice? d8a7a4a

context.publish(&snapshot_topic, message).await.unwrap_or_else(|e| {
tracing::error!("Failed to publish SPO bootstrap message: {}", e)
});
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Callbacks should be async I think - noted on Chris' PR

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The parser isn't properly async at the moment, so we're blocking the calls for now. I'd like to discuss this further -- whether this process be fully synchronous or async.

- Add SignedRationalNumber type to support signed numerators (needed for
  log-likelihood values which are typically negative)
- Update Likelihood to use Vec<SignedRationalNumber> instead of Vec<f64>
- Refactor decode_likelihood_value to return SignedRationalNumber
- Consolidate duplicate test modules in utxo.rs
# Conflicts:
#	common/src/snapshot/streaming_snapshot.rs
#	modules/snapshot_bootstrapper/src/publisher.rs
…dd-from-bootstrap

# Conflicts:
#	common/examples/test_streaming_parser.rs
#	common/src/snapshot/streaming_snapshot.rs
#	common/src/snapshot/utxo.rs
@lowhung lowhung changed the base branch from main to ajw/386-bootstrap-utxo-module December 15, 2025 22:21
Base automatically changed from ajw/386-bootstrap-utxo-module to main December 16, 2025 01:34
@sandtreader sandtreader self-requested a review December 16, 2025 17:59
Copy link
Collaborator

@sandtreader sandtreader left a comment

Choose a reason for hiding this comment

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

Looks great - async stuff can wait

Copy link
Collaborator

@whankinsiv whankinsiv left a comment

Choose a reason for hiding this comment

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

Looks good!

@lowhung lowhung merged commit c284611 into main Dec 16, 2025
2 checks passed
@lowhung lowhung deleted the lowhung/generate-spdd-from-bootstrap branch December 16, 2025 21:52
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.

Test SPDD generation through StakeAddress map that's initialized in accounts state Bootstrap Accounts Module

4 participants