vex_anchor/
backend.rs

1//! Core backend trait for anchoring
2
3use async_trait::async_trait;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use vex_core::Hash;
7
8use crate::error::AnchorError;
9
10/// Metadata about the data being anchored
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct AnchorMetadata {
13    /// Tenant identifier
14    pub tenant_id: String,
15    /// Number of events in this anchor batch
16    pub event_count: u64,
17    /// Timestamp when anchor was requested
18    pub timestamp: DateTime<Utc>,
19    /// Optional description
20    pub description: Option<String>,
21}
22
23impl AnchorMetadata {
24    /// Create new anchor metadata
25    pub fn new(tenant_id: impl Into<String>, event_count: u64) -> Self {
26        Self {
27            tenant_id: tenant_id.into(),
28            event_count,
29            timestamp: Utc::now(),
30            description: None,
31        }
32    }
33
34    /// Add a description
35    pub fn with_description(mut self, desc: impl Into<String>) -> Self {
36        self.description = Some(desc.into());
37        self
38    }
39}
40
41/// Receipt proving that a root was anchored
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct AnchorReceipt {
44    /// Backend that performed the anchoring
45    pub backend: String,
46    /// The Merkle root that was anchored
47    pub root_hash: String,
48    /// Unique identifier from the backend (commit hash, tx hash, etc.)
49    pub anchor_id: String,
50    /// When the anchoring occurred
51    pub anchored_at: DateTime<Utc>,
52    /// Optional proof data (OTS proof, blob commitment, etc.)
53    pub proof: Option<String>,
54    /// Metadata that was anchored
55    pub metadata: AnchorMetadata,
56}
57
58impl AnchorReceipt {
59    /// Export receipt as JSON
60    pub fn to_json(&self) -> Result<String, serde_json::Error> {
61        serde_json::to_string_pretty(self)
62    }
63
64    /// Import receipt from JSON
65    pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
66        serde_json::from_str(json)
67    }
68}
69
70/// Trait for anchoring backends
71///
72/// Implementations should be:
73/// - Append-only (no deletion of anchors)
74/// - Tamper-evident (modifications are detectable)
75/// - Verifiable (anchors can be independently verified)
76#[async_trait]
77pub trait AnchorBackend: Send + Sync {
78    /// Anchor a Merkle root to the external system
79    ///
80    /// Returns a receipt that can be used to verify the anchor later.
81    async fn anchor(
82        &self,
83        root: &Hash,
84        metadata: AnchorMetadata,
85    ) -> Result<AnchorReceipt, AnchorError>;
86
87    /// Verify that a previously issued receipt is still valid
88    ///
89    /// Returns `true` if the anchor exists and matches the receipt.
90    async fn verify(&self, receipt: &AnchorReceipt) -> Result<bool, AnchorError>;
91
92    /// Get the human-readable name of this backend
93    fn name(&self) -> &str;
94
95    /// Check if the backend is available and healthy
96    async fn is_healthy(&self) -> bool;
97}