use crate::{ChainId, Result, StateKey, StateValue, XenithError};
use async_trait::async_trait;
#[async_trait]
pub trait ConflictResolver: Send + Sync {
async fn resolve(
&self,
key: &StateKey,
candidates: Vec<(ChainId, StateValue)>,
) -> Result<StateValue>;
}
pub struct LatestVersionResolver;
#[async_trait]
impl ConflictResolver for LatestVersionResolver {
async fn resolve(
&self,
key: &StateKey,
candidates: Vec<(ChainId, StateValue)>,
) -> Result<StateValue> {
candidates
.into_iter()
.map(|(_, v)| v)
.max_by_key(|v| v.version)
.ok_or_else(|| XenithError::StoreError(format!("no candidates for key {key}")))
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::Bytes;
fn val(chain: u64, ts: u64) -> (ChainId, StateValue) {
use crate::StateVersion;
(
ChainId(chain),
StateValue {
data: Bytes::from_static(b"d"),
version: StateVersion {
timestamp_ms: ts,
sequence: 0,
source_chain: chain,
},
updated_at: 0,
source_chain: ChainId(chain),
},
)
}
#[tokio::test]
async fn picks_highest_version() {
use crate::StateVersion;
let key = StateKey::new("p", "e", "1");
let result = LatestVersionResolver
.resolve(&key, vec![val(1, 3), val(42161, 7), val(10, 2)])
.await
.unwrap();
assert_eq!(
result.version,
StateVersion {
timestamp_ms: 7,
sequence: 0,
source_chain: 42161
}
);
}
#[tokio::test]
async fn empty_candidates_returns_error() {
let key = StateKey::new("p", "e", "1");
assert!(LatestVersionResolver.resolve(&key, vec![]).await.is_err());
}
}