1use crate::{ChainId, Result, StateKey, StateValue, XenithError};
2use async_trait::async_trait;
3
4#[async_trait]
22pub trait ConflictResolver: Send + Sync {
23 async fn resolve(
25 &self,
26 key: &StateKey,
27 candidates: Vec<(ChainId, StateValue)>,
28 ) -> Result<StateValue>;
29}
30
31pub struct LatestVersionResolver;
36
37#[async_trait]
38impl ConflictResolver for LatestVersionResolver {
39 async fn resolve(
40 &self,
41 key: &StateKey,
42 candidates: Vec<(ChainId, StateValue)>,
43 ) -> Result<StateValue> {
44 candidates
45 .into_iter()
46 .map(|(_, v)| v)
47 .max_by_key(|v| v.version)
48 .ok_or_else(|| XenithError::StoreError(format!("no candidates for key {key}")))
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use bytes::Bytes;
56
57 fn val(chain: u64, ts: u64) -> (ChainId, StateValue) {
58 use crate::StateVersion;
59 (
60 ChainId(chain),
61 StateValue {
62 data: Bytes::from_static(b"d"),
63 version: StateVersion {
64 timestamp_ms: ts,
65 sequence: 0,
66 source_chain: chain,
67 },
68 updated_at: 0,
69 source_chain: ChainId(chain),
70 },
71 )
72 }
73
74 #[tokio::test]
75 async fn picks_highest_version() {
76 use crate::StateVersion;
77 let key = StateKey::new("p", "e", "1");
78 let result = LatestVersionResolver
79 .resolve(&key, vec![val(1, 3), val(42161, 7), val(10, 2)])
80 .await
81 .unwrap();
82 assert_eq!(
83 result.version,
84 StateVersion {
85 timestamp_ms: 7,
86 sequence: 0,
87 source_chain: 42161
88 }
89 );
90 }
91
92 #[tokio::test]
93 async fn empty_candidates_returns_error() {
94 let key = StateKey::new("p", "e", "1");
95 assert!(LatestVersionResolver.resolve(&key, vec![]).await.is_err());
96 }
97}