acki_nacki.rs
Overview
This file implements the handling of acknowledgment (Ack) and negative acknowledgment (Nack) messages within the consensus mechanism of a node. It provides methods to process incoming Ack and Nack messages, manage their caching and validation, and maintain consistency in block finalization states. The implementation resides as part of the generic Node struct, parameterized over a state synchronization service and a random number generator, facilitating pluggable components in the consensus workflow.
Processing acknowledgments and negative acknowledgments is critical for consensus finality and block validation. The file focuses on verifying signatures, caching messages when necessary, updating internal state repositories, and interacting with validation services. Some methods related to detailed Nack validation are stubbed or commented out, indicating ongoing or planned enhancements.
Classes and Implementations
impl<TStateSyncService, TRandomGenerator> Node<TStateSyncService, TRandomGenerator>
This implementation block adds acknowledgment and negative acknowledgment handling functionality to the Node struct. The generics constrain the node to use a StateSyncService with a RepositoryImpl and a random number generator implementing the rand::Rng trait.
Methods
on_ack(&mut self, ack: &<Self as NodeAssociatedTypes>::Ack) -> anyhow::Result<()>
Processes an incoming acknowledgment message.
Parameters:
ack: Reference to an acknowledgment message conforming to the node's associatedAcktype.
Returns:
anyhow::Result<()>: Success or error result.
Description:
Logs receipt of the
ack.Extracts the block identifier and sequence number from the acknowledgment data.
Attempts to retrieve the map of public keys for block keepers relevant to the block identifier.
If the key map is unavailable, caches the
ackfor later processing.If available, verifies the signatures on the
ack. If valid, the acknowledgment is pushed into the node's locked list of received acknowledgments.
Usage Example:
let ack_message = ...; // some ack message
node.on_ack(&ack_message)?;
on_nack(&mut self, nack: &<Self as NodeAssociatedTypes>::Nack) -> anyhow::Result<()>
Processes an incoming negative acknowledgment message.
Parameters:
nack: Reference to a negative acknowledgment message conforming to the node's associatedNacktype.
Returns:
anyhow::Result<()>: Success or error result.
Description:
Handles specific
NackReasonvariants:For
BadBlockorTooComplexExecutionreasons, retrieves the block state and marks the block as suspicious by adding the signature occurrences from thenack.Sends the suspicious block state and envelope to the validation service.
Logs receipt of the
nack.Contains extensive commented-out code for signature verification, caching, validity checks, and handling suspicious blocks, indicating planned or deprecated functionality.
Currently, other
NackReasonvariants are logged as warnings and ignored.
Usage Example:
let nack_message = ...; // some nack message
node.on_nack(&nack_message)?;
_check_cached_acks_and_nacks(&mut self, last_processed_block: &<Self as NodeAssociatedTypes>::CandidateBlock) -> anyhow::Result<()>
Checks and processes any cached acknowledgments or negative acknowledgments related to a recently processed block.
Parameters:
last_processed_block: Reference to the last processed candidate block.
Returns:
anyhow::Result<()>: Success or error result.
Description:
Uses the processed block's sequence number and identifier to find any cached
ackornackmessages.Processes the first matching cached
ackandnackfor that block.Helps ensure that delayed or out-of-order messages are eventually handled after the block is known to the node.
Usage Example:
node._check_cached_acks_and_nacks(&last_block)?;
_clear_old_acks_and_nacks(&mut self, finalized_block_seq_no: &BlockSeqNo) -> anyhow::Result<()>
Clears cached acknowledgments and negative acknowledgments up to and including a given finalized block sequence number.
Parameters:
finalized_block_seq_no: Reference to the block sequence number of the finalized block.
Returns:
anyhow::Result<()>: Success or error result.
Description:
Removes entries from the ack and nack caches whose keys are less than or equal to the finalized block sequence number.
Prunes the lists of received acks and nacks to remove messages for blocks already finalized.
Frees memory and maintains cache correctness as the blockchain progresses.
Usage Example:
node._clear_old_acks_and_nacks(&finalized_seq_no)?;
Important Implementation Details and Algorithms
Signature Verification:
on_ackandon_nackrely on retrieving a public keys map for block keepers associated with a block identifier for signature verification.The
ack.verify_signaturesmethod is called to confirm the validity of signatures. It is expected never to panic.In
on_nack, signature verification is currently commented out, but the method plans to ensure that Nack messages are validly signed.
Caching:
Both acknowledgments and negative acknowledgments are cached by block sequence number if the node cannot immediately process them (e.g., missing public keys).
Cache cleanup is performed based on finalized block heights to prevent memory bloat.
Suspicious Block Handling:
When a
NackReasonindicates a bad block or too complex execution, the block's state is marked suspicious by adding signature occurrences from thenack.The validation service is notified to re-validate or further investigate the suspicious block.
Concurrency:
Access to received acknowledgment and negative acknowledgment lists is synchronized via locking (
self.received_acks.lock()andself.received_nacks.lock()).
Commented-Out Validation Logic:
The file contains extensive commented code for detailed Nack validation, including checking block hashes, thread consistency, and signature correctness.
These methods suggest a design for complex validation of conflicting blocks and wrong negative acknowledgments, potentially to be reactivated or refactored.
Interaction with Other System Components
StateSyncService: The generic parameterTStateSyncServiceenables interaction with the service responsible for state synchronization, specifically requiring aRepositoryImplrepository.Repositories:
block_state_repository: Used to retrieve and update the state of blocks, including marking suspicious blocks.repository: (commented use) Presumably the main block and ledger repository.
Validation Service:
The file calls the
validation_serviceto send suspicious blocks for re-validation based on Nack reasons.
Message Caches:
ack_cacheandnack_cache: Store acks and nacks temporarily when they cannot be processed immediately.
Locks:
received_acksandreceived_nacks: Thread-safe vectors storing processed acknowledgments and negative acknowledgments.
Tracing:
Uses
tracingmacros (trace,warn) for logging detailed runtime information about processing steps.
Types and Traits:
NodeAssociatedTypes: Provides associated types forAck,Nack, andCandidateBlockused in method signatures.BLSSignedEnvelope: Likely a wrapper for signed messages with BLS signatures.NackReason: Enum describing reasons for negative acknowledgments.
Visual Diagram: Structure of Node Ack/Nack Handling
flowchart TD
A[Node]
A --> B(on_ack)
A --> C(on_nack)
A --> D(_check_cached_acks_and_nacks)
A --> E(_clear_old_acks_and_nacks)
B --> F{Retrieve pubkeys}
F -- Success --> G[Verify signatures]
F -- Fail --> H[Cache ack]
G -- Valid --> I[Add ack to received_acks]
G -- Invalid --> J[Ignore]
C --> K{NackReason}
K -- BadBlock/TooComplex --> L[Mark block suspicious]
L --> M[Send to validation_service]
K -- Other --> N[Warn unimplemented]
D --> O[Get cached acks for block]
O --> P[Process first matching ack]
D --> Q[Get cached nacks for block]
Q --> R[Process first matching nack]
E --> S[Remove cached acks <= finalized seq]
E --> T[Remove cached nacks <= finalized seq]
E --> U[Prune received_acks]
E --> V[Prune received_nacks]
The diagram captures the flow of acknowledgment and negative acknowledgment processing within the node, highlighting caching, verification, suspicious block handling, and cleanup operations.