1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Implementations and definitions of traits used in legacy & current abft

use std::{cmp::Ordering, fmt::Debug, hash::Hash as StdHash, marker::PhantomData, pin::Pin};

use futures::{channel::oneshot, Future, TryFutureExt};
use network_clique::SpawnHandleT;
use parity_scale_codec::{Codec, Decode, Encode};
use sc_service::SpawnTaskHandle;
use sp_runtime::traits::Hash as SpHash;

/// A convenience trait for gathering all the desired hash characteristics.
#[allow(dead_code)]
pub trait Hash: AsRef<[u8]> + StdHash + Eq + Clone + Codec + Debug + Send + Sync {}

impl<T: AsRef<[u8]> + StdHash + Eq + Clone + Codec + Debug + Send + Sync> Hash for T {}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Wrapper<H: SpHash> {
    phantom: PhantomData<H>,
}

/// AlephBFT requires an order on hashes and `SpHash` does not have one, so we wrap it to add it.
#[derive(Debug, PartialEq, Eq, Clone, Copy, StdHash, Encode, Decode)]
pub struct OrdForHash<O: Eq + Copy + Clone + Send + Debug + StdHash + Encode + Decode + AsRef<[u8]>>
{
    inner: O,
}

impl<O: Eq + Copy + Clone + Send + Sync + Debug + StdHash + Encode + Decode + AsRef<[u8]>>
    PartialOrd for OrdForHash<O>
{
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<O: Eq + Copy + Clone + Send + Sync + Debug + StdHash + Encode + Decode + AsRef<[u8]>> Ord
    for OrdForHash<O>
{
    fn cmp(&self, other: &Self) -> Ordering {
        self.inner.as_ref().cmp(other.inner.as_ref())
    }
}

impl<O: Eq + Copy + Clone + Send + Sync + Debug + StdHash + Encode + Decode + AsRef<[u8]>>
    AsRef<[u8]> for OrdForHash<O>
{
    fn as_ref(&self) -> &[u8] {
        self.inner.as_ref()
    }
}

impl<H: SpHash> Wrapper<H> {
    fn hash(s: &[u8]) -> OrdForHash<H::Output> {
        OrdForHash {
            inner: <H as SpHash>::hash(s),
        }
    }
}

impl<H: SpHash> current_aleph_bft::Hasher for Wrapper<H> {
    type Hash = OrdForHash<H::Output>;

    fn hash(s: &[u8]) -> Self::Hash {
        Wrapper::<H>::hash(s)
    }
}

impl<H: SpHash> legacy_aleph_bft::Hasher for Wrapper<H> {
    type Hash = OrdForHash<H::Output>;

    fn hash(s: &[u8]) -> Self::Hash {
        Wrapper::<H>::hash(s)
    }
}

/// A wrapper for spawning tasks in a way compatible with AlephBFT.
#[derive(Clone)]
pub struct SpawnHandle(SpawnTaskHandle);

impl SpawnHandle {
    pub fn spawn_essential_with_result(
        &self,
        name: &'static str,
        task: impl Future<Output = Result<(), ()>> + Send + 'static,
    ) -> Pin<Box<dyn Future<Output = Result<(), ()>> + Send>> {
        let (tx, rx) = oneshot::channel();
        let wrapped_task = async move {
            let result = task.await;
            let _ = tx.send(result);
        };
        let result = <Self as SpawnHandleT>::spawn_essential(self, name, wrapped_task);
        let wrapped_result = async move {
            let main_result = result.await;
            if main_result.is_err() {
                return Err(());
            }
            let rx_result = rx.await;
            rx_result.unwrap_or(Err(()))
        };
        Box::pin(wrapped_result)
    }
}

impl From<SpawnTaskHandle> for SpawnHandle {
    fn from(sth: SpawnTaskHandle) -> Self {
        SpawnHandle(sth)
    }
}

impl SpawnHandleT for SpawnHandle {
    fn spawn(&self, name: &'static str, task: impl Future<Output = ()> + Send + 'static) {
        self.0.spawn(name, None, task)
    }

    fn spawn_essential(
        &self,
        name: &'static str,
        task: impl Future<Output = ()> + Send + 'static,
    ) -> Pin<Box<dyn Future<Output = Result<(), ()>> + Send>> {
        let (tx, rx) = oneshot::channel();
        self.spawn(name, async move {
            task.await;
            let _ = tx.send(());
        });
        Box::pin(rx.map_err(|_| ()))
    }
}

impl current_aleph_bft::SpawnHandle for SpawnHandle {
    fn spawn(&self, name: &'static str, task: impl Future<Output = ()> + Send + 'static) {
        SpawnHandleT::spawn(self, name, task)
    }

    fn spawn_essential(
        &self,
        name: &'static str,
        task: impl Future<Output = ()> + Send + 'static,
    ) -> current_aleph_bft::TaskHandle {
        SpawnHandleT::spawn_essential(self, name, task)
    }
}

impl legacy_aleph_bft::SpawnHandle for SpawnHandle {
    fn spawn(&self, name: &'static str, task: impl Future<Output = ()> + Send + 'static) {
        SpawnHandleT::spawn(self, name, task)
    }

    fn spawn_essential(
        &self,
        name: &'static str,
        task: impl Future<Output = ()> + Send + 'static,
    ) -> legacy_aleph_bft::TaskHandle {
        SpawnHandleT::spawn_essential(self, name, task)
    }
}