mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 16:24:45 +00:00
Adds TreeAnnounce::validate_semantics() called from handle_tree_announce before any tree-state mutation. Enforces that the ancestry accompanying a parent declaration conforms to the spanning tree rules: - first ancestry entry matches the signed sender - is_root declarations carry a single-entry ancestry - non-root declarations include the signed parent as the second entry - the advertised root is the minimum node_addr in the ancestry Non-conforming announcements are rejected with a warn log and no state change. Adds unit tests for each rejected shape plus an integration test covering the full receive path in a two-node tree. Co-authored-by: Johnathan Corgan <johnathan@corganlabs.com>
71 lines
1.9 KiB
Rust
71 lines
1.9 KiB
Rust
//! Spanning Tree Protocol Entities
|
|
//!
|
|
//! Tree coordinates and parent declarations for the FIPS spanning tree.
|
|
//! The spanning tree provides a routing topology where each node maintains
|
|
//! a path to a common root, enabling greedy distance-based routing.
|
|
|
|
mod coordinate;
|
|
mod declaration;
|
|
mod state;
|
|
|
|
use thiserror::Error;
|
|
|
|
use crate::{IdentityError, NodeAddr};
|
|
|
|
pub use coordinate::{CoordEntry, TreeCoordinate};
|
|
pub use declaration::ParentDeclaration;
|
|
pub use state::TreeState;
|
|
|
|
/// Errors related to spanning tree operations.
|
|
#[derive(Debug, Error)]
|
|
pub enum TreeError {
|
|
#[error("invalid tree coordinate: empty path")]
|
|
EmptyCoordinate,
|
|
|
|
#[error("invalid ancestry: does not reach claimed root")]
|
|
AncestryNotToRoot,
|
|
|
|
#[error("invalid ancestry: root declaration must contain only the sender")]
|
|
RootDeclarationMismatch,
|
|
|
|
#[error("invalid ancestry: non-root declaration must include a parent hop")]
|
|
AncestryTooShort,
|
|
|
|
#[error("invalid ancestry: sender {declared} does not match first path entry {ancestry}")]
|
|
AncestryNodeMismatch {
|
|
declared: NodeAddr,
|
|
ancestry: NodeAddr,
|
|
},
|
|
|
|
#[error(
|
|
"invalid ancestry: signed parent {declared} does not match first ancestry hop {ancestry}"
|
|
)]
|
|
AncestryParentMismatch {
|
|
declared: NodeAddr,
|
|
ancestry: NodeAddr,
|
|
},
|
|
|
|
#[error(
|
|
"invalid ancestry: advertised root {advertised} is not the minimum path entry {minimum}"
|
|
)]
|
|
AncestryRootNotMinimum {
|
|
advertised: NodeAddr,
|
|
minimum: NodeAddr,
|
|
},
|
|
|
|
#[error("signature verification failed for node {0:?}")]
|
|
InvalidSignature(NodeAddr),
|
|
|
|
#[error("sequence number regression: got {got}, expected > {expected}")]
|
|
SequenceRegression { got: u64, expected: u64 },
|
|
|
|
#[error("parent not in peers: {0:?}")]
|
|
ParentNotPeer(NodeAddr),
|
|
|
|
#[error("identity error: {0}")]
|
|
Identity(#[from] IdentityError),
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|