extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use core::num::NonZeroUsize;
use crate::metis::{
AdoptionReportDecodeError, AdoptionReportRecord, ConfirmationDecodeError, ConfirmationRecord,
Cut, Declaration, DeclarationDecodeError, Dot, DotSet, EpochAddress, EpochLedgerDecodeBudget,
EpochLedgerSnapshot, EpochRefusal, Epochs, InvalidEpochAddress, LineageProofDecodeBudget,
LineageProofDecodeError, LineageProofEntry, LineageProofRecord, SealDecodeBudget,
SealDecodeError, SealRecord, Stability, Vouched, WireCutError,
};
use super::{cut, d, declaration, displaced_window, rank};
fn address(generation: u64, dot: (u32, u64)) -> EpochAddress {
EpochAddress::try_from_parts(generation, dot).unwrap()
}
mod endorsement;
mod joint;
mod layout;
mod lineage;
mod refusals;
#[test]
fn test_identical_node_chains_do_not_determine_the_retained_sets() {
let (epochs, sealed, loser) = contested_window();
let full = SealRecord::from_sealed(&sealed);
let frame = full.to_bytes();
let mut stripped = frame[..25].to_vec();
stripped[21..25].copy_from_slice(&1u32.to_be_bytes());
stripped.extend_from_slice(&frame[45..]);
let hollow = SealRecord::from_bytes(&stripped).expect("the stripped twin is canonical");
assert_eq!(hollow.declaration(), full.declaration());
assert_eq!(hollow.sealed_join(), full.sealed_join());
assert_eq!(full.candidates().count(), 2);
assert_eq!(
hollow.candidates().collect::<Vec<_>>(),
[full.declaration()]
);
let node = [0xCC; 32];
let genuine = LineageProofRecord::try_new(vec![LineageProofEntry::new(full, node)]).unwrap();
let forged = LineageProofRecord::try_new(vec![LineageProofEntry::new(hollow, node)]).unwrap();
assert_eq!(genuine.entries()[0].node(), forged.entries()[0].node());
assert_ne!(genuine, forged);
assert_eq!(
LineageProofRecord::from_bytes(&genuine.to_bytes()),
Ok(genuine)
);
assert_eq!(
LineageProofRecord::from_bytes(&forged.to_bytes()),
Ok(forged)
);
let snapshot = epochs.snapshot().to_bytes();
assert_eq!(&snapshot[61..69], &2u64.to_be_bytes());
let mut stripped = snapshot[..61].to_vec();
stripped.extend_from_slice(&1u64.to_be_bytes());
stripped.extend_from_slice(&snapshot[81..]);
let budget = EpochLedgerDecodeBudget::new(2, 2, 2, 2, 2);
let decoded = EpochLedgerSnapshot::from_bytes(&stripped, budget)
.expect("the reduced checkpoint remains structurally valid");
let reduced = Epochs::rehydrate(&decoded, [1, 2], NonZeroUsize::new(2).unwrap())
.expect("the checkpoint matches the deployment");
assert_eq!(epochs.recognize(loser, loser.declaration()), Ok(()));
assert_eq!(
reduced.recognize(loser, loser.declaration()),
Err(EpochRefusal::BeyondHorizon { epoch: loser })
);
}
fn contested_window() -> (Epochs, crate::metis::SealedEpoch, EpochAddress) {
let loser = declaration(&[1, 2], d(1, 3), 7, &[(1, 2), (2, 2)]);
let winner = declaration(&[1, 2], d(2, 3), 9, &[(1, 2), (2, 2)]);
let mut epochs = Epochs::new([1, 2], NonZeroUsize::new(2).unwrap());
let mut stability = Stability::new([1, 2]);
let base = cut(&[(1, 2), (2, 2)]);
for station in [1, 2] {
stability.report_cut(station, &base).unwrap();
}
epochs
.deliver(loser.clone(), &stability, &Cut::bottom())
.unwrap();
epochs
.deliver(winner.clone(), &stability, &Cut::bottom())
.unwrap();
let delivered = cut(&[(1, 3), (2, 3)]);
for station in [1, 2] {
stability.report_cut(station, &delivered).unwrap();
}
epochs
.confirm(loser.address(), &Vouched::trust(1, delivered.clone()))
.unwrap();
epochs
.confirm(winner.address(), &Vouched::trust(2, delivered.clone()))
.unwrap();
let adopted = epochs.adopt(1, 3, &stability).unwrap();
assert_eq!(adopted.address(), winner.address());
epochs
.adopt_report(winner.address(), &Vouched::trust(2, 3))
.unwrap();
let sealed = epochs.try_seal(&stability).unwrap().clone();
assert!(sealed.contains(loser.address()));
assert!(sealed.contains(winner.address()));
(epochs, sealed, loser.address())
}