subsoil/consensus/beefy/
payload.rs1use crate::runtime::traits::Block;
8use alloc::{vec, vec::Vec};
9use codec::{Decode, DecodeWithMemTracking, Encode};
10use scale_info::TypeInfo;
11
12pub type BeefyPayloadId = [u8; 2];
14
15pub mod known_payloads {
17 use super::BeefyPayloadId;
18
19 pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh";
23}
24
25#[derive(
32 Decode,
33 DecodeWithMemTracking,
34 Encode,
35 Debug,
36 PartialEq,
37 Eq,
38 Clone,
39 Ord,
40 PartialOrd,
41 Hash,
42 TypeInfo,
43)]
44pub struct Payload(Vec<(BeefyPayloadId, Vec<u8>)>);
45
46impl Payload {
47 pub fn from_single_entry(id: BeefyPayloadId, value: Vec<u8>) -> Self {
49 Self(vec![(id, value)])
50 }
51
52 pub fn get_raw(&self, id: &BeefyPayloadId) -> Option<&Vec<u8>> {
56 let index = self.0.binary_search_by(|probe| probe.0.cmp(id)).ok()?;
57 Some(&self.0[index].1)
58 }
59
60 pub fn get_all_raw<'a>(
62 &'a self,
63 id: &'a BeefyPayloadId,
64 ) -> impl Iterator<Item = &'a Vec<u8>> + 'a {
65 self.0
66 .iter()
67 .filter_map(move |probe| if &probe.0 != id { return None } else { Some(&probe.1) })
68 }
69
70 pub fn get_decoded<T: Decode>(&self, id: &BeefyPayloadId) -> Option<T> {
74 self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok())
75 }
76
77 pub fn get_all_decoded<'a, T: Decode>(
79 &'a self,
80 id: &'a BeefyPayloadId,
81 ) -> impl Iterator<Item = Option<T>> + 'a {
82 self.get_all_raw(id).map(|raw| T::decode(&mut &raw[..]).ok())
83 }
84
85 pub fn push_raw(mut self, id: BeefyPayloadId, value: Vec<u8>) -> Self {
90 self.0.push((id, value));
91 self.0.sort_by_key(|(id, _)| *id);
92 self
93 }
94}
95
96pub trait PayloadProvider<B: Block> {
98 fn payload(&self, header: &B::Header) -> Option<Payload>;
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn payload_methods_work_as_expected() {
108 let id1: BeefyPayloadId = *b"hw";
109 let msg1: String = "1. Hello World!".to_string();
110 let id2: BeefyPayloadId = *b"yb";
111 let msg2: String = "2. Yellow Board!".to_string();
112 let id3: BeefyPayloadId = *b"cs";
113 let msg3: String = "3. Cello Cord!".to_string();
114
115 let payload = Payload::from_single_entry(id1, msg1.encode())
116 .push_raw(id2, msg2.encode())
117 .push_raw(id3, msg3.encode());
118
119 assert_eq!(payload.get_decoded(&id1), Some(msg1));
120 assert_eq!(payload.get_decoded(&id2), Some(msg2));
121 assert_eq!(payload.get_raw(&id3), Some(&msg3.encode()));
122 assert_eq!(payload.get_raw(&known_payloads::MMR_ROOT_ID), None);
123 }
124}