Skip to content

Conversation

@lowhung
Copy link
Collaborator

@lowhung lowhung commented Dec 16, 2025

Description

Adds governance state bootstrapping from CBOR ledger state snapshots. This enables the governance_state module to be initialized from a snapshot dump instead of requiring replay from genesis.

Key changes:

  • CBOR decoder for governance state (common/src/snapshot/governance.rs): Parses the gov_state portion of NewEpochState including proposals, committee, constitution, votes from drep_pulsing_state, and ratify state (enacted/expired actions)
  • Publish: Publishes GovernanceBootstrapMessage containing proposals, votes, committee, constitution, and proposal roots
  • Governance state module: Subscribes to snapshot topic and handles bootstrap messages to populate ConwayVoting state
  • ConwayVoting bootstrap method: bootstrap_from_snapshot() populates proposals, votes, and action_status from the bootstrap message

Related Issue(s)

Completes #385

How was this tested?

  • Manual testing with epoch 507 snapshot - verified correct epoch appears in logs:
2025-12-16T16:01:27.208078Z  INFO acropolis_common::snapshot::streaming_snapshot:     Successfully parsed governance state: 1 proposals, 0 votes
2025-12-16T16:01:27.208091Z  INFO acropolis_module_snapshot_bootstrapper::publisher: Received governance protocol parameters (current, previous, future)
2025-12-16T16:01:27.208097Z  INFO acropolis_module_snapshot_bootstrapper::publisher: Received governance state for epoch 0: 1 proposals, 0 vote records
2025-12-16T16:01:27.208352Z  INFO acropolis_module_snapshot_bootstrapper::publisher: Publishing governance bootstrap: 1 proposals, 7 committee members, constitution: ipfs://bafkreifnwj6zpu3ixa4siz2lndqybyc5wnnt3jkwyutci4e2tmbnj3xrdm
2025-12-16T16:01:27.209550Z  INFO acropolis_module_governance_state::conway_voting: ConwayVoting bootstrapped: 1 proposals, 1 actions with votes
2025-12-16T16:01:27.209557Z  INFO acropolis_module_governance_state: GovernanceState: Snapshot Bootstrap message received, 1 proposals loaded
...
2025-12-16T16:09:15.112769Z  INFO acropolis_module_governance_state::state: alonzo proposal epochs: [], conway proposals: 1, conway votes: 1, drep stake msgs (size): 0 (0)
  • Also called blockfrost API to get proposals
acropolis/processes/omnibus on  main [$!?] is 📦 v0.1.0
➜ curl http://127.0.0.1:4340/governance/proposals
["gov_action1zhuz5djmmmjg8f9s8pe6grfc98xg3szglums8cgm6qwancp4eytqqmpu0pr"]%
  • Existing tests pass

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

  • Votes bootstrapped from snapshot use a placeholder TxHash::default() since original transaction hashes are not preserved in the snapshot format

Reviewer notes / Areas to focus

  • common/src/snapshot/governance.rs: Core CBOR parsing logic - extensive but follows established patterns from other snapshot parsers
  • modules/governance_state/src/governance_state.rs:287-345: Snapshot subscription handling in init() - follows pattern from drep_state.rs
  • modules/governance_state/src/conway_voting.rs:77-110: bootstrap_from_snapshot() method - uses default voting length (6 epochs) if Conway params not yet available

@lowhung lowhung requested review from sandtreader and shd December 16, 2025 16:51
@lowhung lowhung linked an issue Dec 16, 2025 that may be closed by this pull request
6 tasks
@lowhung lowhung requested a review from buddhisthead December 16, 2025 17:00
@lowhung lowhung changed the title Add governance bootstrap support feat: add governance bootstrap Dec 16, 2025
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.

Satellite-view review really - I don't know the governance details enough to verify the decoder properly. @shd may be better placed.

}
};

// If governance parsing failed, use fallback parsing for pparams
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this still needed or just legacy?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not, I've removed it here eb263f0

gov_msg.proposals.len()
);
}
// Ignore other snapshot messages
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comment as DRepState - should we handle the completion message explicitly?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we do want to receive the Complete message and then break. Something like:

Message::Snapshot(SnapshotMessage::Complete) => {
                            info!("Snapshot complete, exiting governance state bootstrap loop");
                            break; // done processing snapshot messages
                        }

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yep! Resolved here

e
);
// Reset decoder position and try fallback parsing
remainder_decoder = Decoder::new(&remainder_buffer[gov_state_position..]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is great. Thanks for keeping the fallback, but I think we should log an error here instead of an info. At least a warn is appropriate.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

// We need to re-parse pparams from the gov_state - this is a limitation that could be improved
// For now, use defaults and rely on the protocol_parameters callback from earlier parsing
(
ProtocolParameters::default(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

If governance parsing succeeds, do we use these defaults? That will result in the protocol_parameters callback getting default data, which is not good. I don't understand how this would work. If you did parser the protocol params in the governance stat, then it seems you want to extract them here and return them in this expression.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've removed that here eb263f0, we do not want to be silently passing defaults.

`parse_gov_state()` failed, the code would silently continue by manually
navigating the CBOR structure to extract just the protocol parameters.
Now governance parsing failures propagate as errors instead of being
silently ignored.
@lowhung
Copy link
Collaborator Author

lowhung commented Dec 18, 2025

2025-12-18T17:40:08.120530Z  INFO acropolis_common::snapshot::governance:     Parsing governance state for epoch 507...
2025-12-18T17:40:08.121279Z  INFO acropolis_common::snapshot::governance:       Parsed 1 proposals
2025-12-18T17:40:08.121300Z  INFO acropolis_common::snapshot::governance:       Parsed committee with members
2025-12-18T17:40:08.121325Z  INFO acropolis_common::snapshot::governance:       Parsed constitution: ipfs://bafkreifnwj6zpu3ixa4siz2lndqybyc5wnnt3jkwyutci4e2tmbnj3xrdm
2025-12-18T17:40:08.124023Z  INFO acropolis_common::snapshot::governance:       Parsed 0 voting records, 0 enacted, 0 expired
2025-12-18T17:40:08.124033Z  INFO acropolis_common::snapshot::streaming_snapshot:     Successfully parsed governance state: 1 proposals, 0 votes
2025-12-18T17:40:08.124040Z  INFO acropolis_module_snapshot_bootstrapper::publisher: Received governance protocol parameters for epoch 507 slice Previous
2025-12-18T17:40:08.124070Z  INFO acropolis_module_snapshot_bootstrapper::publisher: Received governance protocol parameters for epoch 507 slice Current
2025-12-18T17:40:08.124074Z  INFO acropolis_module_snapshot_bootstrapper::publisher: Received governance protocol parameters for epoch 507 slice Future
2025-12-18T17:40:08.124293Z  INFO acropolis_module_snapshot_bootstrapper::publisher: Received governance state for epoch 507: 1 proposals, 0 vote records
2025-12-18T17:40:08.125758Z  INFO acropolis_module_snapshot_bootstrapper::publisher: Publishing governance bootstrap: 1 proposals, 7 committee members, constitution: ipfs://bafkreifnwj6zpu3ixa4siz2lndqybyc5wnnt3jkwyutci4e2tmbnj3xrdm
2025-12-18T17:40:08.127159Z  INFO acropolis_module_governance_state::conway_voting: ConwayVoting bootstrapped: 1 proposals, 1 actions with votes
2025-12-18T17:40:08.127252Z  INFO acropolis_module_governance_state: GovernanceState: Snapshot Bootstrap message received, 1 proposals loaded

@lowhung lowhung merged commit 5617215 into main Dec 18, 2025
2 checks passed
@lowhung lowhung deleted the lowhung/governance-state-bootstrap branch December 18, 2025 20:06
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.

Bootstrap Governance Module

6 participants