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}