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: u32,
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: u32, 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: u32,
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: u32, target: &PointerTarget) -> Vec<u8> {
100        let mut bytes = Vec::new();
101        // Add owner public key bytes
102        bytes.extend_from_slice(&owner.to_bytes());
103        // Add counter
104        bytes.extend_from_slice(&counter.to_le_bytes());
105        // Add target bytes using MessagePack serialization
106        if let Ok(target_bytes) = rmp_serde::to_vec(target) {
107            bytes.extend_from_slice(&target_bytes);
108        }
109        bytes
110    }
111
112    /// Get the address of the pointer
113    pub fn address(&self) -> PointerAddress {
114        PointerAddress::new(self.owner)
115    }
116
117    /// Get the owner of the pointer
118    pub fn owner(&self) -> &PublicKey {
119        &self.owner
120    }
121
122    /// Get the target of the pointer
123    pub fn target(&self) -> &PointerTarget {
124        &self.target
125    }
126
127    /// Get the bytes that were signed for this pointer
128    pub fn bytes_for_signature(&self) -> Vec<u8> {
129        Self::bytes_to_sign(&self.owner, self.counter, &self.target)
130    }
131
132    pub fn xorname(&self) -> XorName {
133        self.address().xorname()
134    }
135
136    /// Get the counter of the pointer, the higher the counter, the more recent the pointer is
137    /// Similarly to counter CRDTs only the latest version (highest counter) of the pointer is kept on the network
138    pub fn counter(&self) -> u32 {
139        self.counter
140    }
141
142    /// Verifies if the pointer has a valid signature
143    pub fn verify_signature(&self) -> bool {
144        let bytes = self.bytes_for_signature();
145        self.owner.verify(&self.signature, &bytes)
146    }
147
148    /// Size of the pointer
149    pub fn size() -> usize {
150        size_of::<Pointer>()
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157
158    #[test]
159    fn test_pointer_creation_and_validation() {
160        let owner_sk = SecretKey::random();
161        let counter = 1;
162        let pk = SecretKey::random().public_key();
163        let target = PointerTarget::GraphEntryAddress(GraphEntryAddress::new(pk));
164
165        // Create and sign pointer
166        let pointer = Pointer::new(&owner_sk, counter, target.clone());
167        assert!(pointer.verify_signature()); // Should be valid with correct signature
168
169        // Create pointer with wrong signature
170        let wrong_sk = SecretKey::random();
171        let sig = wrong_sk.sign(pointer.bytes_for_signature());
172        let wrong_pointer =
173            Pointer::new_with_signature(owner_sk.public_key(), counter, target.clone(), sig);
174        assert!(!wrong_pointer.verify_signature()); // Should be invalid with wrong signature
175    }
176}