ant_protocol/storage/
pointer.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 crate::storage::{ChunkAddress, GraphEntryAddress, PointerAddress, ScratchpadAddress};
10use bls::{PublicKey, SecretKey, Signature};
11use serde::{Deserialize, Serialize};
12use xor_name::XorName;
13
14/// Pointer, a mutable address pointing to other data on the Network
15/// It is stored at the owner's public key and can only be updated by the owner
16#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
17pub struct Pointer {
18    owner: PublicKey,
19    counter: u64,
20    target: PointerTarget,
21    signature: Signature,
22}
23
24impl std::fmt::Debug for Pointer {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        f.debug_struct("Pointer")
27            .field("owner", &self.owner.to_hex())
28            .field("counter", &self.counter)
29            .field("target", &self.target)
30            .field("signature", &hex::encode(self.signature.to_bytes()))
31            .finish()
32    }
33}
34
35/// The target of a pointer, the address it points to
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd)]
37pub enum PointerTarget {
38    ChunkAddress(ChunkAddress),
39    GraphEntryAddress(GraphEntryAddress),
40    PointerAddress(PointerAddress),
41    ScratchpadAddress(ScratchpadAddress),
42}
43
44impl PointerTarget {
45    /// Returns the xorname of the target
46    pub fn xorname(&self) -> XorName {
47        match self {
48            PointerTarget::ChunkAddress(addr) => *addr.xorname(),
49            PointerTarget::GraphEntryAddress(addr) => addr.xorname(),
50            PointerTarget::PointerAddress(addr) => addr.xorname(),
51            PointerTarget::ScratchpadAddress(addr) => addr.xorname(),
52        }
53    }
54
55    /// Returns the hex string representation of the target
56    pub fn to_hex(&self) -> String {
57        match self {
58            PointerTarget::ChunkAddress(addr) => addr.to_hex(),
59            PointerTarget::GraphEntryAddress(addr) => addr.to_hex(),
60            PointerTarget::PointerAddress(addr) => addr.to_hex(),
61            PointerTarget::ScratchpadAddress(addr) => addr.to_hex(),
62        }
63    }
64}
65
66impl Pointer {
67    /// Create a new pointer, signing it with the provided secret key.
68    /// This pointer would be stored on the network at the provided key's public key.
69    /// There can only be one pointer at a time at the same address (one per key).
70    pub fn new(owner: &SecretKey, counter: u64, target: PointerTarget) -> Self {
71        let pubkey = owner.public_key();
72        let bytes_to_sign = Self::bytes_to_sign(&pubkey, counter, &target);
73        let signature = owner.sign(&bytes_to_sign);
74
75        Self {
76            owner: pubkey,
77            counter,
78            target,
79            signature,
80        }
81    }
82
83    /// Create a new pointer with an existing signature
84    pub fn new_with_signature(
85        owner: PublicKey,
86        counter: u64,
87        target: PointerTarget,
88        signature: Signature,
89    ) -> Self {
90        Self {
91            owner,
92            counter,
93            target,
94            signature,
95        }
96    }
97
98    /// Get the bytes that the signature is calculated from
99    fn bytes_to_sign(owner: &PublicKey, counter: u64, target: &PointerTarget) -> Vec<u8> {
100        // to support retrocompatibility with old pointers (u32 counter), we need to cast the counter to u32
101        // the support is limited to counters under u32::MAX
102        let counter_bytes: Vec<u8> = if counter > u32::MAX as u64 {
103            counter.to_le_bytes().to_vec()
104        } else {
105            let u32_counter = counter as u32;
106            u32_counter.to_le_bytes().to_vec()
107        };
108
109        let mut bytes = Vec::new();
110        // Add owner public key bytes
111        bytes.extend_from_slice(&owner.to_bytes());
112        // Add counter
113        bytes.extend_from_slice(&counter_bytes);
114        // Add target bytes using MessagePack serialization
115        if let Ok(target_bytes) = rmp_serde::to_vec(target) {
116            bytes.extend_from_slice(&target_bytes);
117        }
118        bytes
119    }
120
121    /// Get the address of the pointer
122    pub fn address(&self) -> PointerAddress {
123        PointerAddress::new(self.owner)
124    }
125
126    /// Get the owner of the pointer
127    pub fn owner(&self) -> &PublicKey {
128        &self.owner
129    }
130
131    /// Get the target of the pointer
132    pub fn target(&self) -> &PointerTarget {
133        &self.target
134    }
135
136    /// Get the bytes that were signed for this pointer
137    pub fn bytes_for_signature(&self) -> Vec<u8> {
138        Self::bytes_to_sign(&self.owner, self.counter, &self.target)
139    }
140
141    pub fn xorname(&self) -> XorName {
142        self.address().xorname()
143    }
144
145    /// Get the counter of the pointer, the higher the counter, the more recent the pointer is
146    /// Similarly to counter CRDTs only the latest version (highest counter) of the pointer is kept on the network
147    pub fn counter(&self) -> u64 {
148        self.counter
149    }
150
151    /// Verifies if the pointer has a valid signature
152    pub fn verify_signature(&self) -> bool {
153        let bytes = self.bytes_for_signature();
154        self.owner.verify(&self.signature, &bytes)
155    }
156
157    /// Size of the pointer
158    pub fn size() -> usize {
159        size_of::<Pointer>()
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn test_pointer_creation_and_validation() {
169        let owner_sk = SecretKey::random();
170        let counter = 1;
171        let pk = SecretKey::random().public_key();
172        let target = PointerTarget::GraphEntryAddress(GraphEntryAddress::new(pk));
173
174        // Create and sign pointer
175        let pointer = Pointer::new(&owner_sk, counter, target.clone());
176        assert!(pointer.verify_signature()); // Should be valid with correct signature
177
178        // Create pointer with wrong signature
179        let wrong_sk = SecretKey::random();
180        let sig = wrong_sk.sign(pointer.bytes_for_signature());
181        let wrong_pointer =
182            Pointer::new_with_signature(owner_sk.public_key(), counter, target.clone(), sig);
183        assert!(!wrong_pointer.verify_signature()); // Should be invalid with wrong signature
184    }
185
186    #[test]
187    fn test_pointer_deserialize_counter_compatibility() {
188        #[derive(Serialize, Deserialize)]
189        struct OldPointer {
190            owner: PublicKey,
191            counter: u32,
192            target: PointerTarget,
193            signature: Signature,
194        }
195        fn bytes_to_sign_old_pointer(
196            owner: &PublicKey,
197            counter: u32,
198            target: &PointerTarget,
199        ) -> Vec<u8> {
200            let mut bytes = Vec::new();
201            // Add owner public key bytes
202            bytes.extend_from_slice(&owner.to_bytes());
203            // Add counter
204            bytes.extend_from_slice(&counter.to_le_bytes());
205            // Add target bytes using MessagePack serialization
206            if let Ok(target_bytes) = rmp_serde::to_vec(target) {
207                bytes.extend_from_slice(&target_bytes);
208            }
209            bytes
210        }
211
212        let xor = XorName::random(&mut rand::thread_rng());
213        let sk = SecretKey::random();
214        let old_pointer = OldPointer {
215            owner: sk.public_key(),
216            counter: 42u32,
217            target: PointerTarget::ChunkAddress(ChunkAddress::new(xor)),
218            signature: sk.sign(bytes_to_sign_old_pointer(
219                &sk.public_key(),
220                42u32,
221                &PointerTarget::ChunkAddress(ChunkAddress::new(xor)),
222            )),
223        };
224
225        // Serialize the old pointer format
226        let serialized_old =
227            rmp_serde::to_vec(&old_pointer).expect("Failed to serialize old pointer");
228
229        // Deserialize into new pointer format
230        let deserialized_as_new: Pointer =
231            rmp_serde::from_slice(&serialized_old).expect("Failed to deserialize");
232
233        // Verify the counter was correctly converted to u64
234        assert_eq!(deserialized_as_new.counter(), 42u64);
235        assert_eq!(deserialized_as_new.owner(), &old_pointer.owner);
236        assert_eq!(deserialized_as_new.target(), &old_pointer.target);
237        assert_eq!(deserialized_as_new.signature, old_pointer.signature);
238
239        // Serialize the new pointer format
240        let new_pointer =
241            Pointer::new(&sk, 42, PointerTarget::ChunkAddress(ChunkAddress::new(xor)));
242
243        // Serialize the new pointer format
244        let serialized_new =
245            rmp_serde::to_vec(&new_pointer).expect("Failed to serialize new pointer");
246
247        // Deserialize into pointer format
248        let deserialized_new: Pointer =
249            rmp_serde::from_slice(&serialized_new).expect("Failed to deserialize");
250
251        // Verify the counter was correctly converted to u64
252        assert_eq!(deserialized_new.counter(), 42u64);
253        assert_eq!(deserialized_new.owner(), &new_pointer.owner);
254        assert_eq!(deserialized_new.target(), &new_pointer.target);
255        assert_eq!(deserialized_new.signature, new_pointer.signature);
256
257        // Deserialize into old pointer format
258        let deserialized_as_old: OldPointer =
259            rmp_serde::from_slice(&serialized_new).expect("Failed to deserialize");
260
261        // Verify the counter was correctly converted to u32
262        assert_eq!(deserialized_as_old.counter, 42u32);
263        assert_eq!(deserialized_as_old.owner, new_pointer.owner);
264        assert_eq!(deserialized_as_old.target, new_pointer.target);
265        assert_eq!(deserialized_as_old.signature, new_pointer.signature);
266
267        // compare old and new pointer
268        assert_eq!(old_pointer.counter as u64, new_pointer.counter);
269        assert_eq!(old_pointer.owner, new_pointer.owner);
270        assert_eq!(old_pointer.target, new_pointer.target);
271
272        // signature is the same
273        assert_eq!(old_pointer.signature, new_pointer.signature);
274    }
275}