1use aura_consensus::ConsensusId;
9use aura_core::effects::StorageEffects;
10use aura_core::types::identifiers::{AuthorityId, ContextId};
11use aura_core::{AuraError, Result};
12use serde::{Deserialize, Serialize};
13use std::collections::BTreeMap;
14
15#[derive(Debug, Clone, Serialize, Deserialize, Default)]
21pub struct EvidenceRecord {
22 pub entries: BTreeMap<String, Vec<u8>>,
24}
25
26impl EvidenceRecord {
27 pub fn merge(&mut self, delta: EvidenceDelta) {
29 for (cid, bytes) in delta.entries {
30 self.entries.insert(cid, bytes);
31 }
32 }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, Default)]
37pub struct EvidenceDelta {
38 pub entries: BTreeMap<String, Vec<u8>>,
39}
40
41pub const AMP_EVIDENCE_KEY_PREFIX: &str = "amp/evidence/";
49
50pub(crate) fn evidence_key(cid: ConsensusId) -> String {
52 format!("{}{}", AMP_EVIDENCE_KEY_PREFIX, hex::encode(cid.0 .0))
53}
54
55#[async_trait::async_trait]
64pub trait AmpEvidenceEffects: StorageEffects + Sized {
65 async fn merge_evidence_delta(&self, cid: ConsensusId, delta: EvidenceDelta) -> Result<()>;
67
68 async fn evidence_for(&self, cid: ConsensusId) -> Result<Option<EvidenceRecord>>;
70
71 async fn insert_evidence_delta(
73 &self,
74 witness: AuthorityId,
75 consensus_id: ConsensusId,
76 context: ContextId,
77 ) -> Result<()>;
78
79 fn evidence_store(&self) -> AmpEvidenceStore<'_, Self>
81 where
82 Self: Sized,
83 {
84 AmpEvidenceStore { effects: self }
85 }
86}
87
88#[async_trait::async_trait]
90impl<E: StorageEffects> AmpEvidenceEffects for E {
91 async fn merge_evidence_delta(&self, cid: ConsensusId, delta: EvidenceDelta) -> Result<()> {
92 self.evidence_store().merge_delta(cid, delta).await
93 }
94
95 async fn evidence_for(&self, cid: ConsensusId) -> Result<Option<EvidenceRecord>> {
96 self.evidence_store().current(cid).await
97 }
98
99 async fn insert_evidence_delta(
100 &self,
101 witness: AuthorityId,
102 consensus_id: ConsensusId,
103 context: ContextId,
104 ) -> Result<()> {
105 let evidence_entry = format!("witness:{witness}:context:{context}");
107 let mut delta = EvidenceDelta::default();
108 delta
109 .entries
110 .insert(hex::encode(consensus_id.0 .0), evidence_entry.into_bytes());
111
112 self.merge_evidence_delta(consensus_id, delta).await
113 }
114}
115
116pub struct AmpEvidenceStore<'a, E: ?Sized + StorageEffects> {
125 effects: &'a E,
126}
127
128impl<'a, E: ?Sized + StorageEffects> AmpEvidenceStore<'a, E> {
129 pub async fn merge_delta(&self, cid: ConsensusId, delta: EvidenceDelta) -> Result<()> {
131 let mut record = self.current(cid).await?.unwrap_or_default();
132 record.merge(delta);
133 let bytes =
134 serde_json::to_vec(&record).map_err(|e| AuraError::serialization(e.to_string()))?;
135 self.effects
136 .store(&evidence_key(cid), bytes)
137 .await
138 .map_err(|e| AuraError::storage(e.to_string()))
139 }
140
141 pub async fn current(&self, cid: ConsensusId) -> Result<Option<EvidenceRecord>> {
143 match self.effects.retrieve(&evidence_key(cid)).await {
144 Ok(Some(bytes)) => {
145 let record: EvidenceRecord = serde_json::from_slice(&bytes)
146 .map_err(|e| AuraError::serialization(e.to_string()))?;
147 Ok(Some(record))
148 }
149 Ok(None) => Ok(None),
150 Err(e) => Err(AuraError::storage(e.to_string())),
151 }
152 }
153}