sp_partner_chains_consensus_aura/
block_proposal.rs1use crate::InherentDigest;
2use futures::FutureExt;
3use sp_consensus::{Environment, Proposer};
4use sp_inherents::InherentData;
5use sp_runtime::traits::Block as BlockT;
6use sp_runtime::{Digest, DigestItem};
7use std::future::Future;
8use std::marker::PhantomData;
9use std::time;
10
11pub struct PartnerChainsProposerFactory<B: BlockT, E: Environment<B>, ID> {
13 env: E,
14 phantom_data: PhantomData<(B, ID)>,
15}
16
17impl<B: BlockT, E: Environment<B>, ID> PartnerChainsProposerFactory<B, E, ID> {
18 pub fn new(env: E) -> Self {
19 Self { env, phantom_data: PhantomData }
20 }
21}
22
23impl<B: BlockT, E: Environment<B>, ID: InherentDigest + Send + Sync + 'static> Environment<B>
24 for PartnerChainsProposerFactory<B, E, ID>
25{
26 type Proposer = PartnerChainsProposer<B, E::Proposer, ID>;
27 type CreateProposer =
28 Box<dyn Future<Output = Result<Self::Proposer, Self::Error>> + Send + Unpin + 'static>;
29 type Error = <E as Environment<B>>::Error;
30
31 fn init(&mut self, parent_header: &<B as BlockT>::Header) -> Self::CreateProposer {
32 Box::new(self.env.init(parent_header).map(|res| {
33 res.map(|proposer| PartnerChainsProposer::<B, E::Proposer, ID>::new(proposer))
34 }))
35 }
36}
37
38pub struct PartnerChainsProposer<B: BlockT, P: Proposer<B>, ID: InherentDigest> {
40 pub proposer: P,
41 phantom_data: PhantomData<(B, ID)>,
42}
43
44impl<B: BlockT, P: Proposer<B>, ID: InherentDigest> PartnerChainsProposer<B, P, ID> {
45 pub(crate) fn new(proposer: P) -> Self {
46 Self { proposer, phantom_data: PhantomData }
47 }
48}
49
50impl<B: BlockT, P: Proposer<B>, ID: InherentDigest> Proposer<B>
51 for PartnerChainsProposer<B, P, ID>
52{
53 type Error = <P as Proposer<B>>::Error;
54 type Proposal = <P as Proposer<B>>::Proposal;
55 type ProofRecording = <P as Proposer<B>>::ProofRecording;
56 type Proof = <P as Proposer<B>>::Proof;
57
58 fn propose(
59 self,
60 inherent_data: InherentData,
61 inherent_digests: Digest,
62 max_duration: time::Duration,
63 block_size_limit: Option<usize>,
64 ) -> Self::Proposal {
65 let mut logs: Vec<DigestItem> = Vec::from(inherent_digests.logs());
66 let mut inherent_logs = ID::from_inherent_data(&inherent_data)
68 .expect("InherentDigest can be created from inherent data");
69 logs.append(&mut inherent_logs);
70 self.proposer
71 .propose(inherent_data, Digest { logs }, max_duration, block_size_limit)
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use crate::InherentDigest;
78 use crate::block_proposal::PartnerChainsProposer;
79 use futures::future;
80 use sp_consensus::{DisableProofRecording, Proposal, Proposer};
81 use sp_inherents::InherentData;
82 use sp_runtime::generic::Header;
83 use sp_runtime::traits::BlakeTwo256;
84 use sp_runtime::{Digest, DigestItem, OpaqueExtrinsic};
85 use std::error::Error;
86
87 pub type Block = sp_runtime::generic::Block<Header<u32, BlakeTwo256>, OpaqueExtrinsic>;
88
89 fn expected_item() -> DigestItem {
90 DigestItem::Other(vec![1, 3, 3, 7])
91 }
92
93 fn other_item() -> DigestItem {
94 DigestItem::Other(vec![0, 0, 0, 0])
95 }
96
97 struct TestInherentDigest;
98
99 impl InherentDigest for TestInherentDigest {
100 type Value = ();
101
102 fn from_inherent_data(
103 _inherent_data: &InherentData,
104 ) -> Result<Vec<DigestItem>, Box<dyn Error + Send + Sync>> {
105 Ok(vec![expected_item()])
106 }
107
108 fn value_from_digest(
109 _digests: &[DigestItem],
110 ) -> Result<Self::Value, Box<dyn Error + Send + Sync>> {
111 todo!()
112 }
113 }
114
115 struct TestProposer {
116 expected_digest: Digest,
117 }
118
119 impl Proposer<Block> for TestProposer {
120 type Error = sp_blockchain::Error;
121 type Proposal = future::Ready<Result<Proposal<Block, ()>, sp_blockchain::Error>>;
122 type ProofRecording = DisableProofRecording;
123 type Proof = ();
124
125 fn propose(
126 self,
127 _inherent_data: InherentData,
128 inherent_digests: Digest,
129 _max_duration: std::time::Duration,
130 _block_size_limit: Option<usize>,
131 ) -> Self::Proposal {
132 let result = if inherent_digests != self.expected_digest {
133 Err(sp_blockchain::Error::Application(
134 "Inherent digest does not match expected digest".into(),
135 ))
136 } else {
137 let block = Block {
138 header: Header {
139 parent_hash: Default::default(),
140 number: 0,
141 state_root: Default::default(),
142 extrinsics_root: Default::default(),
143 digest: Default::default(),
144 },
145 extrinsics: Default::default(),
146 };
147 Ok(Proposal { block, proof: (), storage_changes: Default::default() })
148 };
149 futures::future::ready(result)
150 }
151 }
152
153 #[test]
154 fn inherent_digest_is_appended_to_logs() {
155 let inherent_data = InherentData::new();
156 let inherent_digests = Digest { logs: vec![other_item()] };
157 let test_proposer =
158 TestProposer { expected_digest: Digest { logs: vec![other_item(), expected_item()] } };
159 let proposer: PartnerChainsProposer<Block, TestProposer, TestInherentDigest> =
160 PartnerChainsProposer::new(test_proposer);
161 let proposal = proposer
162 .propose(inherent_data, inherent_digests, std::time::Duration::from_secs(0), None)
163 .into_inner();
164 assert!(proposal.is_ok());
165 }
166}