ant_protocol/storage/
graph.rs

1// Copyright 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use super::address::GraphEntryAddress;
10use bls::SecretKey;
11use serde::{Deserialize, Serialize};
12
13// re-exports
14pub use bls::{PublicKey, Signature};
15
16/// Content of a graph, limited to 32 bytes
17pub type GraphContent = [u8; 32];
18
19/// A generic GraphEntry on the Network.
20///
21/// Graph entries are stored at the owner's public key. Note that there can only be one graph entry per owner.
22/// Graph entries can be linked to other graph entries as parents or descendants.
23/// Applications are free to define the meaning of these links, those are not enforced by the protocol.
24/// The protocol only ensures that the graph entry is immutable once uploaded and that the signature is valid and matches the owner.
25///
26/// For convenience it is advised to make use of BLS key derivation to create multiple graph entries from a single key.
27#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Ord, PartialOrd)]
28pub struct GraphEntry {
29    /// The owner of the graph. Note that graph entries are stored at the owner's public key
30    pub owner: PublicKey,
31    /// Other graph entries that this graph entry refers to as parents
32    pub parents: Vec<PublicKey>,
33    /// The content of the graph entry
34    pub content: GraphContent,
35    /// Other graph entries that this graph entry refers to as descendants/outputs along with some data associated to each one
36    pub descendants: Vec<(PublicKey, GraphContent)>,
37    /// signs the above 4 fields with the owners key
38    pub signature: Signature,
39}
40
41impl std::fmt::Debug for GraphEntry {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        f.debug_struct("GraphEntry")
44            .field("owner", &self.owner.to_hex())
45            .field(
46                "parents",
47                &self.parents.iter().map(|p| p.to_hex()).collect::<Vec<_>>(),
48            )
49            .field("content", &hex::encode(self.content))
50            .field(
51                "descendants",
52                &self
53                    .descendants
54                    .iter()
55                    .map(|(p, c)| format!("{}: {}", p.to_hex(), hex::encode(c)))
56                    .collect::<Vec<_>>(),
57            )
58            .field("signature", &hex::encode(self.signature.to_bytes()))
59            .finish()
60    }
61}
62
63impl GraphEntry {
64    /// Maximum size of a graph entry: 100KB
65    pub const MAX_SIZE: usize = 100 * 1024;
66
67    /// Create a new graph entry, signing it with the provided secret key.
68    pub fn new(
69        owner: &SecretKey,
70        parents: Vec<PublicKey>,
71        content: GraphContent,
72        descendants: Vec<(PublicKey, GraphContent)>,
73    ) -> Self {
74        let key = owner;
75        let owner = key.public_key();
76        let signature = key.sign(Self::bytes_to_sign(
77            &owner,
78            &parents,
79            &content,
80            &descendants,
81        ));
82        Self {
83            owner,
84            parents,
85            content,
86            descendants,
87            signature,
88        }
89    }
90
91    /// Create a new graph entry, with the signature already calculated.
92    pub fn new_with_signature(
93        owner: PublicKey,
94        parents: Vec<PublicKey>,
95        content: GraphContent,
96        descendants: Vec<(PublicKey, GraphContent)>,
97        signature: Signature,
98    ) -> Self {
99        Self {
100            owner,
101            parents,
102            content,
103            descendants,
104            signature,
105        }
106    }
107
108    /// Get the bytes that the signature is calculated from.
109    pub fn bytes_to_sign(
110        owner: &PublicKey,
111        parents: &[PublicKey],
112        content: &[u8],
113        descendants: &[(PublicKey, GraphContent)],
114    ) -> Vec<u8> {
115        let mut bytes = Vec::new();
116        bytes.extend_from_slice(&owner.to_bytes());
117        bytes.extend_from_slice("parent".as_bytes());
118        bytes.extend_from_slice(
119            &parents
120                .iter()
121                .map(|p| p.to_bytes())
122                .collect::<Vec<_>>()
123                .concat(),
124        );
125        bytes.extend_from_slice("content".as_bytes());
126        bytes.extend_from_slice(content);
127        bytes.extend_from_slice("descendants".as_bytes());
128        bytes.extend_from_slice(
129            &descendants
130                .iter()
131                .flat_map(|(p, c)| [&p.to_bytes(), c.as_slice()].concat())
132                .collect::<Vec<_>>(),
133        );
134        bytes
135    }
136
137    pub fn address(&self) -> GraphEntryAddress {
138        GraphEntryAddress::new(self.owner)
139    }
140
141    /// Get the bytes that the signature is calculated from.
142    pub fn bytes_for_signature(&self) -> Vec<u8> {
143        Self::bytes_to_sign(&self.owner, &self.parents, &self.content, &self.descendants)
144    }
145
146    /// Verify the signature of the graph entry
147    pub fn verify_signature(&self) -> bool {
148        self.owner
149            .verify(&self.signature, self.bytes_for_signature())
150    }
151
152    /// Size of the graph entry
153    pub fn size(&self) -> usize {
154        size_of::<GraphEntry>()
155            + self
156                .descendants
157                .iter()
158                .map(|(p, c)| p.to_bytes().len() + c.len())
159                .sum::<usize>()
160            + self
161                .parents
162                .iter()
163                .map(|p| p.to_bytes().len())
164                .sum::<usize>()
165    }
166
167    /// Returns true if the graph entry is too big
168    pub fn is_too_big(&self) -> bool {
169        self.size() > Self::MAX_SIZE
170    }
171}