aranya_runtime/sync/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Interface for syncing state between clients.

use core::{convert::Infallible, fmt};

use aranya_buggy::Bug;
use postcard::Error as PostcardError;
use serde::{Deserialize, Serialize};

use crate::{
    command::{Command, CommandId, Priority},
    storage::{StorageError, MAX_COMMAND_LENGTH},
    Address, Prior,
};

mod requester;
mod responder;

pub use requester::SyncRequester;
pub use responder::{PeerCache, SyncResponder};

// TODO: These should all be compile time parameters

/// The maximum number of heads that will be stored for a peer.
pub const PEER_HEAD_MAX: usize = 10;

/// The maximum number of samples in a request
const COMMAND_SAMPLE_MAX: usize = 100;

/// The maximum number of missing segments that can be requested
/// in a single message
const REQUEST_MISSING_MAX: usize = 100;

/// The maximum number of commands in a response
pub const COMMAND_RESPONSE_MAX: usize = 100;

/// The maximum number of segments which can be stored to send
const SEGMENT_BUFFER_MAX: usize = 100;

/// The maximum size of a sync message
// TODO: Use postcard to calculate max size (which accounts for overhead)
// https://docs.rs/postcard/latest/postcard/experimental/max_size/index.html
pub const MAX_SYNC_MESSAGE_SIZE: usize = 1024 + MAX_COMMAND_LENGTH * COMMAND_RESPONSE_MAX;

/// Represents high-level data of a command.
#[derive(Serialize, Deserialize, Debug)]
pub struct CommandMeta {
    id: CommandId,
    priority: Priority,
    parent: Prior<Address>,
    policy_length: u32,
    length: u32,
    max_cut: usize,
}

/// Enum of all supported sync messages.
// TODO: Use compile-time args. This initial definition results in this clippy warning:
// https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant.
// As the buffer consts will be compile-time variables in the future, we will be
// able to tune these buffers for smaller footprints. Right now, this enum is not
// suitable for small devices (`SyncResponse` is 8448 bytes).

/// An error returned by the syncer.
#[derive(Debug)]
pub enum SyncError {
    UnexpectedMessage,
    SessionMismatch,
    MissingSyncResponse,
    SessionState,
    StorageError,
    NotReady,
    SerilizeError,
    CommandOverflow,
    Bug(Bug),
}

impl fmt::Display for SyncError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::UnexpectedMessage => write!(f, "unexpected message"),
            Self::SessionMismatch => write!(f, "session mismatch"),
            Self::MissingSyncResponse => write!(f, "missing sync response"),
            Self::SessionState => write!(f, "session state error"),
            Self::StorageError => write!(f, "storage error"),
            Self::NotReady => write!(f, "not ready"),
            Self::SerilizeError => write!(f, "serialize error"),
            Self::CommandOverflow => write!(f, "too many commands sent"),
            Self::Bug(bug) => write!(f, "{bug}"),
        }
    }
}

impl core::error::Error for SyncError {}

impl From<Bug> for SyncError {
    fn from(error: Bug) -> Self {
        SyncError::Bug(error)
    }
}

impl From<Infallible> for SyncError {
    fn from(error: Infallible) -> Self {
        match error {}
    }
}

impl From<StorageError> for SyncError {
    fn from(_error: StorageError) -> Self {
        SyncError::StorageError
    }
}

impl From<PostcardError> for SyncError {
    fn from(_error: PostcardError) -> Self {
        SyncError::SerilizeError
    }
}

/// Sync command to be committed to graph.
#[derive(Serialize, Deserialize, Debug)]
pub struct SyncCommand<'a> {
    priority: Priority,
    id: CommandId,
    parent: Prior<Address>,
    policy: Option<&'a [u8]>,
    data: &'a [u8],
    max_cut: usize,
}

impl<'a> Command for SyncCommand<'a> {
    fn priority(&self) -> Priority {
        self.priority.clone()
    }

    fn id(&self) -> CommandId {
        self.id
    }

    fn parent(&self) -> Prior<Address> {
        self.parent
    }

    fn policy(&self) -> Option<&'a [u8]> {
        self.policy
    }

    fn bytes(&self) -> &'a [u8] {
        self.data
    }

    fn max_cut(&self) -> Result<usize, Bug> {
        Ok(self.max_cut)
    }
}