use std::collections::{BTreeMap, HashMap};
use serde::{Deserialize, Serialize};
use crate::{
websocket::BLS12381_PUBLIC_KEY_SIZE, OracleDutyConfig, OracleId, OracleUpdateResult,
TimestampMs,
};
pub type AuthorityKeyBytes = [u8; BLS12381_PUBLIC_KEY_SIZE];
pub type CommitIndex = u64;
pub type OracleDutiesMap = BTreeMap<OracleDutiesMapKey, OracleDutiesMapValue>;
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
pub struct OracleDutiesMapKey {
pub target_timestamp: TimestampMs,
pub oracle_id: OracleId,
}
impl Ord for OracleDutiesMapKey {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.target_timestamp
.cmp(&other.target_timestamp)
.then_with(|| self.oracle_id.cmp(&other.oracle_id))
}
}
impl PartialOrd for OracleDutiesMapKey {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct OracleDutiesMapValue {
#[serde(with = "serde_utils")]
pub updates: HashMap<AuthorityKeyBytes, Option<OracleUpdateResult>>,
pub config: OracleDutyConfig,
}
mod serde_utils {
use std::collections::HashMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_big_array::BigArray;
use super::{AuthorityKeyBytes, OracleUpdateResult};
pub fn serialize<S>(
map: &HashMap<AuthorityKeyBytes, Option<OracleUpdateResult>>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[derive(Serialize)]
struct Entry {
#[serde(with = "BigArray")]
key: AuthorityKeyBytes,
value: Option<OracleUpdateResult>,
}
let entries: Vec<_> = map
.iter()
.map(|(key, value)| Entry {
key: *key,
value: value.clone(),
})
.collect();
entries.serialize(serializer)
}
pub fn deserialize<'de, D>(
deserializer: D,
) -> Result<HashMap<AuthorityKeyBytes, Option<OracleUpdateResult>>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Entry {
#[serde(with = "BigArray")]
key: AuthorityKeyBytes,
value: Option<OracleUpdateResult>,
}
let entries = Vec::<Entry>::deserialize(deserializer)?;
Ok(entries.into_iter().map(|e| (e.key, e.value)).collect())
}
}
#[cfg(test)]
mod tests {
use std::cmp::{max, min};
use rialo_s_pubkey::Pubkey;
use super::*;
#[test]
fn test_oracle_duties_map_key_ordering() {
let creator1 = Pubkey::new_unique();
let creator2 = Pubkey::new_unique();
let oracle_id1 = OracleId::new(creator1, "nonce1");
let oracle_id2 = OracleId::new(creator2, "nonce2");
let [oracle_id1, oracle_id2] = [min(oracle_id1, oracle_id2), max(oracle_id1, oracle_id2)];
let key1 = OracleDutiesMapKey {
target_timestamp: 100,
oracle_id: oracle_id1,
};
let key2 = OracleDutiesMapKey {
target_timestamp: 200,
oracle_id: oracle_id1,
};
assert!(key1 < key2);
assert!(key2 > key1);
let key3 = OracleDutiesMapKey {
target_timestamp: 100,
oracle_id: oracle_id1,
};
let key4 = OracleDutiesMapKey {
target_timestamp: 100,
oracle_id: oracle_id2,
};
assert!(key3 < key4);
assert!(key4 > key3);
let key5 = OracleDutiesMapKey {
target_timestamp: 100,
oracle_id: oracle_id2,
};
let key6 = OracleDutiesMapKey {
target_timestamp: 200,
oracle_id: oracle_id1,
};
assert!(key5 < key6);
assert!(key6 > key5);
let key7 = OracleDutiesMapKey {
target_timestamp: 100,
oracle_id: oracle_id1,
};
let key8 = OracleDutiesMapKey {
target_timestamp: 100,
oracle_id: oracle_id1,
};
assert_eq!(key7, key8);
assert!(key7 >= key8);
assert!(key7 <= key8);
let mut map = BTreeMap::new();
let key9 = OracleDutiesMapKey {
target_timestamp: 200,
oracle_id: oracle_id1,
};
let key10 = OracleDutiesMapKey {
target_timestamp: 100,
oracle_id: oracle_id2,
};
let key11 = OracleDutiesMapKey {
target_timestamp: 100,
oracle_id: oracle_id1,
};
map.insert(key9, "first");
map.insert(key10, "second");
map.insert(key11, "third");
let keys: Vec<_> = map.keys().copied().collect();
assert_eq!(keys[0], key11);
assert_eq!(keys[1], key10);
assert_eq!(keys[2], key9);
}
}