sp_consensus_beefy/
payload.rs1use alloc::{vec, vec::Vec};
19use codec::{Decode, DecodeWithMemTracking, Encode};
20use scale_info::TypeInfo;
21use sp_runtime::traits::Block;
22
23pub type BeefyPayloadId = [u8; 2];
25
26pub mod known_payloads {
28 use crate::BeefyPayloadId;
29
30 pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh";
34}
35
36#[derive(
43 Decode,
44 DecodeWithMemTracking,
45 Encode,
46 Debug,
47 PartialEq,
48 Eq,
49 Clone,
50 Ord,
51 PartialOrd,
52 Hash,
53 TypeInfo,
54)]
55pub struct Payload(Vec<(BeefyPayloadId, Vec<u8>)>);
56
57impl Payload {
58 pub fn from_single_entry(id: BeefyPayloadId, value: Vec<u8>) -> Self {
60 Self(vec![(id, value)])
61 }
62
63 pub fn get_raw(&self, id: &BeefyPayloadId) -> Option<&Vec<u8>> {
67 let index = self.0.binary_search_by(|probe| probe.0.cmp(id)).ok()?;
68 Some(&self.0[index].1)
69 }
70
71 pub fn get_all_raw<'a>(
73 &'a self,
74 id: &'a BeefyPayloadId,
75 ) -> impl Iterator<Item = &'a Vec<u8>> + 'a {
76 self.0
77 .iter()
78 .filter_map(move |probe| if &probe.0 != id { return None } else { Some(&probe.1) })
79 }
80
81 pub fn get_decoded<T: Decode>(&self, id: &BeefyPayloadId) -> Option<T> {
85 self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok())
86 }
87
88 pub fn get_all_decoded<'a, T: Decode>(
90 &'a self,
91 id: &'a BeefyPayloadId,
92 ) -> impl Iterator<Item = Option<T>> + 'a {
93 self.get_all_raw(id).map(|raw| T::decode(&mut &raw[..]).ok())
94 }
95
96 pub fn push_raw(mut self, id: BeefyPayloadId, value: Vec<u8>) -> Self {
101 self.0.push((id, value));
102 self.0.sort_by_key(|(id, _)| *id);
103 self
104 }
105}
106
107pub trait PayloadProvider<B: Block> {
109 fn payload(&self, header: &B::Header) -> Option<Payload>;
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn payload_methods_work_as_expected() {
119 let id1: BeefyPayloadId = *b"hw";
120 let msg1: String = "1. Hello World!".to_string();
121 let id2: BeefyPayloadId = *b"yb";
122 let msg2: String = "2. Yellow Board!".to_string();
123 let id3: BeefyPayloadId = *b"cs";
124 let msg3: String = "3. Cello Cord!".to_string();
125
126 let payload = Payload::from_single_entry(id1, msg1.encode())
127 .push_raw(id2, msg2.encode())
128 .push_raw(id3, msg3.encode());
129
130 assert_eq!(payload.get_decoded(&id1), Some(msg1));
131 assert_eq!(payload.get_decoded(&id2), Some(msg2));
132 assert_eq!(payload.get_raw(&id3), Some(&msg3.encode()));
133 assert_eq!(payload.get_raw(&known_payloads::MMR_ROOT_ID), None);
134 }
135}