use crate::chain::{CyberlinkRecord, Signal};
#[derive(Debug, PartialEq, Eq)]
pub enum ForkError {
ConflictUnderSerialize,
Empty,
}
pub trait GraphView {
fn links(&self) -> Vec<CyberlinkRecord>;
}
pub struct LinksView(pub Vec<CyberlinkRecord>);
impl GraphView for LinksView {
fn links(&self) -> Vec<CyberlinkRecord> {
self.0.clone()
}
}
pub trait ForkChoice {
fn resolve(&self, members: &[Signal], view: &dyn GraphView) -> Result<usize, ForkError>;
}
pub struct Serialize;
impl ForkChoice for Serialize {
fn resolve(&self, members: &[Signal], _view: &dyn GraphView) -> Result<usize, ForkError> {
match members.len() {
0 => Err(ForkError::Empty),
1 => Ok(0),
_ => Err(ForkError::ConflictUnderSerialize),
}
}
}
pub struct MinHash;
impl ForkChoice for MinHash {
fn resolve(&self, members: &[Signal], _view: &dyn GraphView) -> Result<usize, ForkError> {
if members.is_empty() {
return Err(ForkError::Empty);
}
let mut best = 0usize;
let mut best_id = members[0].content_id();
for (i, m) in members.iter().enumerate().skip(1) {
let id = m.content_id();
if id < best_id {
best = i;
best_id = id;
}
}
Ok(best)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::chain::{CyberlinkRecord, Signal, SELF_NETWORK};
fn sig(neuron: u8, step: u64, from: u8, to: u8) -> Signal {
Signal {
neuron: [neuron; 32],
network: SELF_NETWORK,
links: vec![CyberlinkRecord {
neuron: [neuron; 32],
from: [from; 32],
to: [to; 32],
token: [0u8; 32],
amount: 1,
valence: 1,
height: 0,
}],
delta_pi: vec![],
prev: [0u8; 32],
step,
height: 0,
proof: None,
}
}
fn empty_view() -> LinksView {
LinksView(vec![])
}
#[test]
fn serialize_accepts_singleton_rejects_conflict() {
let f = Serialize;
let v = empty_view();
assert_eq!(f.resolve(&[sig(1, 0, 2, 3)], &v), Ok(0));
assert_eq!(
f.resolve(&[sig(1, 0, 2, 3), sig(1, 0, 4, 5)], &v),
Err(ForkError::ConflictUnderSerialize)
);
assert_eq!(f.resolve(&[], &v), Err(ForkError::Empty));
}
#[test]
fn minhash_is_deterministic_and_order_independent() {
let f = MinHash;
let v = empty_view();
let a = sig(1, 0, 2, 3);
let b = sig(1, 0, 4, 5);
let ab = f.resolve(&[a.clone(), b.clone()], &v).unwrap();
let ba = f.resolve(&[b.clone(), a.clone()], &v).unwrap();
let winner_ab = [a.clone(), b.clone()][ab].content_id();
let winner_ba = [b.clone(), a.clone()][ba].content_id();
assert_eq!(winner_ab, winner_ba);
let min = a.content_id().min(b.content_id());
assert_eq!(winner_ab, min);
}
#[test]
fn minhash_rejects_empty() {
assert_eq!(MinHash.resolve(&[], &empty_view()), Err(ForkError::Empty));
}
}