Skip to main content

tempo_commonware_node/
utils.rs

1use std::{
2    future::Future,
3    ops::{Deref, DerefMut},
4    pin::Pin,
5    task::{Poll, ready},
6};
7
8use alloy_primitives::B256;
9use commonware_cryptography::ed25519::PublicKey;
10use futures::future::FusedFuture;
11use pin_project::pin_project;
12
13pub(crate) fn public_key_to_b256(key: &PublicKey) -> B256 {
14    key.as_ref()
15        .try_into()
16        .expect("ed25519 pub keys always map to B256")
17}
18
19pub(crate) fn public_key_to_tempo_primitive(
20    key: &PublicKey,
21) -> tempo_primitives::ed25519::PublicKey {
22    tempo_primitives::ed25519::PublicKey::try_from(B256::from_slice(key.as_ref()))
23        .expect("shared implementation of ed25519 pub keys")
24}
25
26/// A vendored version of [`commonware_utils::futures::OptionFuture`] to implement
27/// [`futures::future::FusedFuture`].
28///
29/// An optional future that yields [Poll::Pending] when [None]. Useful within `select!` macros,
30/// where a future may be conditionally present.
31///
32/// Not to be confused with [futures::future::OptionFuture], which resolves to [None] immediately
33/// when the inner future is `None`.
34#[pin_project]
35pub(crate) struct OptionFuture<F>(#[pin] Option<F>);
36
37impl<F> OptionFuture<F> {
38    pub(crate) fn new(maybe_fut: Option<F>) -> Self {
39        Self(maybe_fut)
40    }
41
42    pub(crate) fn none() -> Self {
43        Self::new(None)
44    }
45
46    pub(crate) fn some(fut: F) -> Self {
47        Self::new(Some(fut))
48    }
49
50    pub(crate) fn is_none(&self) -> bool {
51        self.0.is_none()
52    }
53
54    pub(crate) fn replace(&mut self, fut: F) -> Option<F> {
55        self.0.replace(fut)
56    }
57}
58
59impl<F: Future> Default for OptionFuture<F> {
60    fn default() -> Self {
61        Self::none()
62    }
63}
64
65impl<F: Future> From<Option<F>> for OptionFuture<F> {
66    fn from(opt: Option<F>) -> Self {
67        Self::new(opt)
68    }
69}
70
71impl<F: Future> Deref for OptionFuture<F> {
72    type Target = Option<F>;
73
74    fn deref(&self) -> &Self::Target {
75        &self.0
76    }
77}
78
79impl<F: Future> DerefMut for OptionFuture<F> {
80    fn deref_mut(&mut self) -> &mut Self::Target {
81        &mut self.0
82    }
83}
84
85impl<F: Future> Future for OptionFuture<F> {
86    type Output = F::Output;
87
88    fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
89        let output = match self.as_mut().project().0.as_pin_mut() {
90            Some(fut) => ready!(fut.poll(cx)),
91            None => return Poll::Pending,
92        };
93        self.as_mut().project().0.set(None);
94        Poll::Ready(output)
95    }
96}
97
98impl<F: Future> FusedFuture for OptionFuture<F> {
99    fn is_terminated(&self) -> bool {
100        self.0.is_none()
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use std::task::Poll;
107
108    use commonware_cryptography::ed25519::PublicKey as CommonwarePublicKey;
109    use futures::{channel::oneshot, executor::block_on, pin_mut};
110    use tempo_primitives::ed25519::PublicKey as TempoPublicKey;
111
112    use crate::utils::{OptionFuture, public_key_to_tempo_primitive};
113
114    #[test]
115    fn commonware_public_key_to_tempo_primitive_conversion() {
116        let tempo_key = TempoPublicKey::from_seed([42u8; 32]);
117        let cw_key = CommonwarePublicKey::from(tempo_key.get());
118        assert_eq!(public_key_to_tempo_primitive(&cw_key), tempo_key);
119        assert_eq!(tempo_key.get().to_bytes(), cw_key.as_ref());
120    }
121
122    #[test]
123    fn option_future() {
124        block_on(async {
125            let option_future = OptionFuture::<oneshot::Receiver<()>>::from(None);
126            pin_mut!(option_future);
127
128            let waker = futures::task::noop_waker();
129            let mut cx = std::task::Context::from_waker(&waker);
130            assert!(option_future.poll(&mut cx).is_pending());
131
132            let (tx, rx) = oneshot::channel();
133            let option_future: OptionFuture<_> = Some(rx).into();
134            pin_mut!(option_future);
135
136            tx.send(1usize).unwrap();
137            assert_eq!(option_future.poll(&mut cx), Poll::Ready(Ok(1)));
138        });
139    }
140}