safe_nd/messaging/
mod.rs

1// Copyright 2020 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under the MIT license <LICENSE-MIT
4// https://opensource.org/licenses/MIT> or the Modified BSD license <LICENSE-BSD
5// https://opensource.org/licenses/BSD-3-Clause>, at your option. This file may not be copied,
6// modified, or distributed except according to those terms. Please review the Licences for the
7// specific language governing permissions and limitations relating to use of the SAFE Network
8// Software.
9
10mod account;
11mod auth;
12mod blob;
13mod cmd;
14mod data;
15mod duty;
16mod map;
17mod network;
18mod query;
19mod sequence;
20mod transfer;
21
22pub use self::{
23    account::{Account, AccountRead, AccountWrite, MAX_LOGIN_PACKET_BYTES},
24    auth::{AuthCmd, AuthQuery},
25    blob::{BlobRead, BlobWrite},
26    cmd::Cmd,
27    data::{DataCmd, DataQuery},
28    duty::{AdultDuties, Duty, ElderDuties, NodeDuties},
29    map::{MapRead, MapWrite},
30    network::{
31        NodeCmd, NodeCmdError, NodeDataCmd, NodeDataError, NodeDataQuery, NodeDataQueryResponse,
32        NodeEvent, NodeQuery, NodeQueryResponse, NodeRewardError, NodeRewardQuery,
33        NodeRewardQueryResponse, NodeSystemCmd, NodeTransferCmd, NodeTransferError,
34        NodeTransferQuery, NodeTransferQueryResponse,
35    },
36    query::Query,
37    sequence::{SequenceRead, SequenceWrite},
38    transfer::{TransferCmd, TransferQuery},
39};
40use crate::{
41    errors::ErrorDebug, utils, AppPermissions, Blob, BlsProof, DebitAgreementProof, Error, Map,
42    MapEntries, MapPermissionSet, MapValue, MapValues, Money, Proof, PublicKey, ReplicaEvent,
43    ReplicaPublicKeySet, Result, Sequence, SequenceEntries, SequenceEntry, SequencePermissions,
44    Signature, TransferValidated,
45};
46use serde::{Deserialize, Serialize};
47use std::{
48    collections::{BTreeMap, BTreeSet},
49    convert::TryFrom,
50    fmt,
51};
52use xor_name::XorName;
53///
54#[allow(clippy::large_enum_variant)]
55#[derive(Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
56pub struct MsgEnvelope {
57    ///
58    pub message: Message,
59    /// The source of the message.
60    pub origin: MsgSender,
61    /// Intermediate actors, so far, on the path of this message.
62    /// Every new actor handling this message, would add itself here.
63    pub proxies: Vec<MsgSender>, // or maybe enough with just option of `proxy` (leaning heavily towards it now)
64}
65
66impl MsgEnvelope {
67    /// Gets the message ID.
68    pub fn id(&self) -> MessageId {
69        self.message.id()
70    }
71
72    /// This is not quite good.
73    /// It does work for the cases we have,
74    /// but it does so without being clearly robust/flexible.
75    /// So, needs some improvement..
76    pub fn verify(&self) -> bool {
77        let data = if self.proxies.is_empty() {
78            utils::serialise(&self.message)
79        } else {
80            let mut msg = self.clone();
81            let _ = msg.proxies.pop();
82            utils::serialise(&msg)
83        };
84        let signer = self.most_recent_sender();
85        signer.id().verify(&signer.signature(), data).is_ok()
86    }
87
88    /// The proxy would first sign the MsgEnvelope,
89    /// and then call this method to add itself
90    /// (public key + the signature) to the envelope.
91    pub fn add_proxy(&mut self, proxy: MsgSender) {
92        self.proxies.push(proxy);
93    }
94
95    ///
96    pub fn most_recent_sender(&self) -> &MsgSender {
97        match self.proxies.last() {
98            None => &self.origin,
99            Some(proxy) => proxy,
100        }
101    }
102
103    ///
104    pub fn destination(&self) -> Address {
105        use Address::*;
106        use Message::*;
107        match &self.message {
108            Cmd { cmd, .. } => self.cmd_dst(cmd),
109            Query { query, .. } => Section(query.dst_address()),
110            Event { event, .. } => Client(event.dst_address()), // TODO: needs the correct client address
111            QueryResponse { query_origin, .. } => query_origin.clone(),
112            CmdError { cmd_origin, .. } => cmd_origin.clone(),
113            NodeCmd { cmd, .. } => cmd.dst_address(),
114            NodeEvent { event, .. } => event.dst_address(),
115            NodeQuery { query, .. } => query.dst_address(),
116            NodeCmdError { cmd_origin, .. } => cmd_origin.clone(),
117            NodeQueryResponse { query_origin, .. } => query_origin.clone(),
118        }
119    }
120
121    fn cmd_dst(&self, cmd: &Cmd) -> Address {
122        use Address::*;
123        use Cmd::*;
124        match cmd {
125            // temporary case, while not impl at `Authenticator`
126            Auth(_) => Section(self.origin.id().into()),
127            // always to `Payment` section
128            Transfer(c) => Section(c.dst_address()),
129            // Data dst (after reaching `Gateway`)
130            // is `Payment` and then `Metadata`.
131            Data { cmd, payment } => {
132                match self.most_recent_sender() {
133                    // From `Client` to `Gateway`.
134                    MsgSender::Client { .. } => Section(self.origin.id().into()),
135                    // From `Gateway` to `Payment`.
136                    MsgSender::Node {
137                        duty: Duty::Elder(ElderDuties::Gateway),
138                        ..
139                    } => Section(payment.from().into()),
140                    // From `Payment` to `Metadata`.
141                    MsgSender::Node {
142                        duty: Duty::Elder(ElderDuties::Payment),
143                        ..
144                    } => Section(cmd.dst_address()),
145                    // Accumulated at `Metadata`.
146                    // I.e. this means we accumulated a section signature from `Payment` Elders.
147                    // (this is done at `Metadata` Elders, and the accumulated section is added to most recent sender)
148                    MsgSender::Section {
149                        duty: Duty::Elder(ElderDuties::Payment),
150                        ..
151                    } => Section(cmd.dst_address()),
152                    _ => {
153                        // this should not be a valid case
154                        // just putting a default address here for now
155                        // (pointing at `Gateway` seems best)
156                        Section(self.origin.id().into())
157                    }
158                }
159            }
160        }
161    }
162}
163
164///
165#[derive(Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
166pub enum MsgSender {
167    ///
168    Client(Proof),
169    ///
170    Node {
171        ///
172        duty: Duty,
173        ///
174        proof: Proof,
175    },
176    ///
177    Section {
178        ///
179        duty: Duty,
180        ///
181        proof: BlsProof,
182    },
183}
184
185impl MsgSender {
186    ///
187    pub fn id(&self) -> PublicKey {
188        use MsgSender::*;
189        match self {
190            Client(proof) | Node { proof, .. } => proof.id(),
191            Section { proof, .. } => proof.id(),
192        }
193    }
194
195    ///
196    pub fn address(&self) -> Address {
197        use MsgSender::*;
198        match self {
199            Client(_) => Address::Client(self.id().into()),
200            Node { .. } => Address::Node(self.id().into()),
201            Section { .. } => Address::Section(self.id().into()),
202        }
203    }
204
205    ///
206    pub fn signature(&self) -> Signature {
207        use MsgSender::*;
208        match self {
209            Client(proof) => proof.signature(),
210            Node { proof, .. } => proof.signature(),
211            Section { proof, .. } => proof.signature(),
212        }
213    }
214}
215
216///
217#[derive(Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
218pub enum Address {
219    ///
220    Client(XorName),
221    ///
222    Node(XorName),
223    ///
224    Section(XorName),
225}
226
227impl Address {
228    /// Extracts the underlying XorName.
229    pub fn xorname(&self) -> XorName {
230        use Address::*;
231        match self {
232            Client(xorname) | Node(xorname) | Section(xorname) => *xorname,
233        }
234    }
235}
236
237///
238#[allow(clippy::large_enum_variant)]
239#[derive(Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
240pub enum Message {
241    /// A Cmd is leads to a write / change of state.
242    /// We expect them to be successful, and only return a msg
243    /// if something went wrong.
244    Cmd {
245        /// Cmd.
246        cmd: Cmd,
247        /// Message ID.
248        id: MessageId,
249    },
250    /// Queries is a read-only operation.
251    Query {
252        /// Query.
253        query: Query,
254        /// Message ID.
255        id: MessageId,
256    },
257    /// An Event is a fact about something that happened.
258    Event {
259        /// Request.
260        event: Event,
261        /// Message ID.
262        id: MessageId,
263        /// ID of causing cmd.
264        correlation_id: MessageId,
265    },
266    /// The response to a query, containing the query result.
267    QueryResponse {
268        /// QueryResponse.
269        response: QueryResponse,
270        /// Message ID.
271        id: MessageId,
272        /// ID of causing query.
273        correlation_id: MessageId,
274        /// The sender of the causing query.
275        query_origin: Address,
276    },
277    /// Cmd error.
278    CmdError {
279        /// The error.
280        error: CmdError,
281        /// Message ID.
282        id: MessageId,
283        /// ID of causing cmd.
284        correlation_id: MessageId,
285        /// The sender of the causing cmd.
286        cmd_origin: Address,
287    },
288    /// Cmds only sent internally in the network.
289    NodeCmd {
290        /// NodeCmd.
291        cmd: NodeCmd,
292        /// Message ID.
293        id: MessageId,
294    },
295    /// An error of a NodeCmd.
296    NodeCmdError {
297        /// The error.
298        error: NodeCmdError,
299        /// Message ID.
300        id: MessageId,
301        /// ID of causing cmd.
302        correlation_id: MessageId,
303        /// The sender of the causing cmd.
304        cmd_origin: Address,
305    },
306    /// Events only sent internally in the network.
307    NodeEvent {
308        /// Request.
309        event: NodeEvent,
310        /// Message ID.
311        id: MessageId,
312        /// ID of causing cmd.
313        correlation_id: MessageId,
314    },
315    /// Queries is a read-only operation.
316    NodeQuery {
317        /// Query.
318        query: NodeQuery,
319        /// Message ID.
320        id: MessageId,
321    },
322    /// The response to a query, containing the query result.
323    NodeQueryResponse {
324        /// QueryResponse.
325        response: NodeQueryResponse,
326        /// Message ID.
327        id: MessageId,
328        /// ID of causing query.
329        correlation_id: MessageId,
330        /// The sender of the causing query.
331        query_origin: Address,
332    },
333}
334
335impl Message {
336    /// Gets the message ID.
337    pub fn id(&self) -> MessageId {
338        match self {
339            Self::Cmd { id, .. }
340            | Self::Query { id, .. }
341            | Self::Event { id, .. }
342            | Self::QueryResponse { id, .. }
343            | Self::CmdError { id, .. }
344            | Self::NodeCmd { id, .. }
345            | Self::NodeEvent { id, .. }
346            | Self::NodeQuery { id, .. }
347            | Self::NodeCmdError { id, .. }
348            | Self::NodeQueryResponse { id, .. } => *id,
349        }
350    }
351}
352
353/// Unique ID for messages.
354///
355/// This is used for deduplication: Since the network sends messages redundantly along different
356/// routes, the same message will usually arrive more than once at any given node. A message with
357/// an ID that is already in the cache will be ignored.
358#[derive(Ord, PartialOrd, Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Hash)]
359pub struct MessageId(pub XorName);
360
361impl MessageId {
362    /// Generates a new `MessageId` with random content.
363    pub fn new() -> Self {
364        Self(XorName::random())
365    }
366}
367
368impl Default for MessageId {
369    fn default() -> Self {
370        Self::new()
371    }
372}
373
374///
375#[derive(Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
376pub enum CmdError {
377    ///
378    Auth(Error), // temporary, while Authenticator is not handling this
379    ///
380    Data(Error), // DataError enum for better differentiation?
381    ///
382    Transfer(TransferError),
383}
384
385///
386#[derive(Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
387pub enum TransferError {
388    /// The error of a ValidateTransfer cmd.
389    TransferValidation(Error),
390    /// The error of a RegisterTransfer cmd.
391    TransferRegistration(Error),
392}
393
394/// Events from the network that
395/// are pushed to the client.
396#[allow(clippy::large_enum_variant, clippy::type_complexity)]
397#[derive(Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
398pub enum Event {
399    /// The transfer was validated by a Replica instance.
400    TransferValidated {
401        /// This is the client id.
402        /// A client can fhave any number of accounts.
403        client: XorName,
404        /// This is the validation of the transfer
405        /// requested by the client for an account.
406        event: TransferValidated,
407    },
408    /// An aggregate event created client side
409    /// (for upper Client layers) out of a quorum of TransferValidated events.
410    /// This is a temporary variant, until
411    /// SignatureAccumulation has been broken out
412    /// to its own crate, and can be used at client.
413    TransferDebitAgreementReached {
414        /// This is the client id.
415        /// A client can fhave any number of accounts.
416        client: XorName,
417        /// The accumulated proof.
418        proof: DebitAgreementProof,
419    },
420}
421
422impl Event {
423    /// Returns the address of the destination for `request`.
424    pub fn dst_address(&self) -> XorName {
425        use Event::*;
426        match self {
427            TransferValidated { client, .. } => *client,
428            TransferDebitAgreementReached { client, .. } => *client,
429        }
430    }
431}
432
433/// Query responses from the network.
434#[allow(clippy::large_enum_variant, clippy::type_complexity)]
435#[derive(Hash, Eq, PartialEq, Clone, Serialize, Deserialize)]
436pub enum QueryResponse {
437    //
438    // ===== Blob =====
439    //
440    /// Get Blob.
441    GetBlob(Result<Blob>),
442    //
443    // ===== Map =====
444    //
445    /// Get Map.
446    GetMap(Result<Map>),
447    /// Get Map shell.
448    GetMapShell(Result<Map>),
449    /// Get Map version.
450    GetMapVersion(Result<u64>),
451    /// List all Map entries (key-value pairs).
452    ListMapEntries(Result<MapEntries>),
453    /// List all Map keys.
454    ListMapKeys(Result<BTreeSet<Vec<u8>>>),
455    /// List all Map values.
456    ListMapValues(Result<MapValues>),
457    /// Get Map permissions for a user.
458    ListMapUserPermissions(Result<MapPermissionSet>),
459    /// List all Map permissions.
460    ListMapPermissions(Result<BTreeMap<PublicKey, MapPermissionSet>>),
461    /// Get Map value.
462    GetMapValue(Result<MapValue>),
463    //
464    // ===== Sequence Data =====
465    //
466    /// Get Sequence.
467    GetSequence(Result<Sequence>),
468    /// Get Sequence owners.
469    GetSequenceOwner(Result<PublicKey>),
470    /// Get Sequence entries from a range.
471    GetSequenceRange(Result<SequenceEntries>),
472    /// Get Sequence last entry.
473    GetSequenceLastEntry(Result<(u64, SequenceEntry)>),
474    /// Get Sequence permissions for a user.
475    GetSequencePermissions(Result<SequencePermissions>),
476    //
477    // ===== Money =====
478    //
479    /// Get replica keys
480    GetReplicaKeys(Result<ReplicaPublicKeySet>),
481    /// Get key balance.
482    GetBalance(Result<Money>),
483    /// Get key transfer history.
484    GetHistory(Result<Vec<ReplicaEvent>>),
485    //
486    // ===== Account =====
487    //
488    /// Get an encrypted account.
489    GetAccount(Result<(Vec<u8>, Signature)>),
490    //
491    // ===== Client auth =====
492    //
493    /// Get a list of authorised keys and the version of the auth keys container from Elders.
494    ListAuthKeysAndVersion(Result<(BTreeMap<PublicKey, AppPermissions>, u64)>),
495}
496
497/// The kind of authorisation needed for a request.
498pub enum AuthorisationKind {
499    /// Authorisation for data requests.
500    Data(DataAuthKind),
501    /// Authorisation for money requests.
502    Money(MoneyAuthKind),
503    /// Miscellaneous authorisation kinds.
504    /// NB: Not very well categorized yet
505    Misc(MiscAuthKind),
506    /// When none required.
507    None,
508}
509
510/// Authorisation for data requests.
511pub enum DataAuthKind {
512    /// Read of public data.
513    PublicRead,
514    /// Read of private data.
515    PrivateRead,
516    /// Write of data/metadata.
517    Write,
518}
519
520/// Authorisation for money requests.
521pub enum MoneyAuthKind {
522    /// Request to get key balance.
523    ReadBalance,
524    /// Request to get key transfer history.
525    ReadHistory,
526    /// Request to transfer money from key.
527    Transfer,
528}
529
530/// Miscellaneous authorisation kinds.
531/// NB: Not very well categorized yet
532pub enum MiscAuthKind {
533    /// Request to manage app keys.
534    ManageAppKeys,
535    /// Request to mutate and transfer money from key.
536    WriteAndTransfer,
537}
538
539/// Error type for an attempted conversion from `QueryResponse` to a type implementing
540/// `TryFrom<Response>`.
541#[derive(Debug, PartialEq)]
542pub enum TryFromError {
543    /// Wrong variant found in `QueryResponse`.
544    WrongType,
545    /// The `QueryResponse` contained an error.
546    Response(Error),
547}
548
549macro_rules! try_from {
550    ($ok_type:ty, $($variant:ident),*) => {
551        impl TryFrom<QueryResponse> for $ok_type {
552            type Error = TryFromError;
553            fn try_from(response: QueryResponse) -> std::result::Result<Self, Self::Error> {
554                match response {
555                    $(
556                        QueryResponse::$variant(Ok(data)) => Ok(data),
557                        QueryResponse::$variant(Err(error)) => Err(TryFromError::Response(error)),
558                    )*
559                    _ => Err(TryFromError::WrongType),
560                }
561            }
562        }
563    };
564}
565
566try_from!(Blob, GetBlob);
567try_from!(Map, GetMap, GetMapShell);
568try_from!(u64, GetMapVersion);
569try_from!(MapEntries, ListMapEntries);
570try_from!(BTreeSet<Vec<u8>>, ListMapKeys);
571try_from!(MapValues, ListMapValues);
572try_from!(MapPermissionSet, ListMapUserPermissions);
573try_from!(BTreeMap<PublicKey, MapPermissionSet>, ListMapPermissions);
574try_from!(MapValue, GetMapValue);
575try_from!(Sequence, GetSequence);
576try_from!(PublicKey, GetSequenceOwner);
577try_from!(SequenceEntries, GetSequenceRange);
578try_from!((u64, SequenceEntry), GetSequenceLastEntry);
579try_from!(SequencePermissions, GetSequencePermissions);
580try_from!(Money, GetBalance);
581try_from!(ReplicaPublicKeySet, GetReplicaKeys);
582try_from!(Vec<ReplicaEvent>, GetHistory);
583try_from!(
584    (BTreeMap<PublicKey, AppPermissions>, u64),
585    ListAuthKeysAndVersion
586);
587try_from!((Vec<u8>, Signature), GetAccount);
588
589impl fmt::Debug for QueryResponse {
590    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
591        use QueryResponse::*;
592
593        match self {
594            // Blob
595            GetBlob(res) => write!(f, "QueryResponse::GetBlob({:?})", ErrorDebug(res)),
596            // Map
597            GetMap(res) => write!(f, "QueryResponse::GetMap({:?})", ErrorDebug(res)),
598            GetMapShell(res) => write!(f, "QueryResponse::GetMapShell({:?})", ErrorDebug(res)),
599            GetMapVersion(res) => write!(f, "QueryResponse::GetMapVersion({:?})", ErrorDebug(res)),
600            ListMapEntries(res) => {
601                write!(f, "QueryResponse::ListMapEntries({:?})", ErrorDebug(res))
602            }
603            ListMapKeys(res) => write!(f, "QueryResponse::ListMapKeys({:?})", ErrorDebug(res)),
604            ListMapValues(res) => write!(f, "QueryResponse::ListMapValues({:?})", ErrorDebug(res)),
605            ListMapPermissions(res) => write!(
606                f,
607                "QueryResponse::ListMapPermissions({:?})",
608                ErrorDebug(res)
609            ),
610            ListMapUserPermissions(res) => write!(
611                f,
612                "QueryResponse::ListMapUserPermissions({:?})",
613                ErrorDebug(res)
614            ),
615            GetMapValue(res) => write!(f, "QueryResponse::GetMapValue({:?})", ErrorDebug(res)),
616            // Sequence
617            GetSequence(res) => write!(f, "QueryResponse::GetSequence({:?})", ErrorDebug(res)),
618            GetSequenceRange(res) => {
619                write!(f, "QueryResponse::GetSequenceRange({:?})", ErrorDebug(res))
620            }
621            GetSequenceLastEntry(res) => write!(
622                f,
623                "QueryResponse::GetSequenceLastEntry({:?})",
624                ErrorDebug(res)
625            ),
626            GetSequencePermissions(res) => write!(
627                f,
628                "QueryResponse::GetSequencePermissions({:?})",
629                ErrorDebug(res)
630            ),
631            GetSequenceOwner(res) => {
632                write!(f, "QueryResponse::GetSequenceOwner({:?})", ErrorDebug(res))
633            }
634            // Money
635            GetReplicaKeys(res) => {
636                write!(f, "QueryResponse::GetReplicaKeys({:?})", ErrorDebug(res))
637            }
638            GetBalance(res) => write!(f, "QueryResponse::GetBalance({:?})", ErrorDebug(res)),
639            GetHistory(res) => write!(f, "QueryResponse::GetHistory({:?})", ErrorDebug(res)),
640            // Account
641            GetAccount(res) => write!(f, "QueryResponse::GetAccount({:?})", ErrorDebug(res)),
642            // Client Auth
643            ListAuthKeysAndVersion(res) => write!(
644                f,
645                "QueryResponse::ListAuthKeysAndVersion({:?})",
646                ErrorDebug(res)
647            ),
648        }
649    }
650}
651
652#[cfg(test)]
653mod tests {
654    use super::*;
655    use crate::{PublicBlob, UnseqMap};
656    use std::convert::{TryFrom, TryInto};
657    use unwrap::{unwrap, unwrap_err};
658
659    #[test]
660    fn debug_format() {
661        use crate::Error;
662        let errored_response = QueryResponse::GetSequence(Err(Error::AccessDenied));
663        assert_eq!(
664            format!("{:?}", errored_response),
665            "QueryResponse::GetSequence(AccessDenied)"
666        );
667    }
668
669    #[test]
670    fn try_from() {
671        use QueryResponse::*;
672
673        let i_data = Blob::Public(PublicBlob::new(vec![1, 3, 1, 4]));
674        let e = Error::AccessDenied;
675        assert_eq!(i_data, unwrap!(GetBlob(Ok(i_data.clone())).try_into()));
676        assert_eq!(
677            TryFromError::Response(e.clone()),
678            unwrap_err!(Blob::try_from(GetBlob(Err(e.clone()))))
679        );
680
681        let mut data = BTreeMap::new();
682        let _ = data.insert(vec![1], vec![10]);
683        let owners = PublicKey::Bls(threshold_crypto::SecretKey::random().public_key());
684        let m_data = Map::Unseq(UnseqMap::new_with_data(
685            *i_data.name(),
686            1,
687            data,
688            BTreeMap::new(),
689            owners,
690        ));
691        assert_eq!(m_data, unwrap!(GetMap(Ok(m_data.clone())).try_into()));
692        assert_eq!(
693            TryFromError::Response(e.clone()),
694            unwrap_err!(Map::try_from(GetMap(Err(e))))
695        );
696    }
697}