sp_messenger_host_functions/
host_functions.rs1use crate::StorageKeyRequest;
2use domain_block_preprocessor::stateless_runtime::StatelessRuntime;
3use sc_executor::RuntimeVersionOf;
4use sp_api::ProvideRuntimeApi;
5use sp_blockchain::HeaderBackend;
6use sp_core::traits::CodeExecutor;
7use sp_core::H256;
8use sp_domains::{DomainId, DomainsApi};
9use sp_messenger::messages::ChainId;
10pub use sp_messenger::MessengerApi;
11use sp_runtime::traits::{Block as BlockT, Header, NumberFor};
12use std::marker::PhantomData;
13use std::sync::Arc;
14
15pub trait MessengerHostFunctions: Send + Sync {
17 fn get_storage_key(&self, req: StorageKeyRequest) -> Option<Vec<u8>>;
19}
20
21sp_externalities::decl_extension! {
22 pub struct MessengerExtension(Arc<dyn MessengerHostFunctions>);
23}
24
25impl MessengerExtension {
26 pub fn new(inner: Arc<dyn MessengerHostFunctions>) -> Self {
28 Self(inner)
29 }
30}
31
32pub struct MessengerHostFunctionsImpl<Block, Client, DomainBlock, Executor> {
34 consensus_client: Arc<Client>,
35 domain_executor: Arc<Executor>,
36 _phantom: PhantomData<(Block, DomainBlock)>,
37}
38
39impl<Block, Client, DomainBlock, Executor>
40 MessengerHostFunctionsImpl<Block, Client, DomainBlock, Executor>
41{
42 pub fn new(consensus_client: Arc<Client>, domain_executor: Arc<Executor>) -> Self {
43 MessengerHostFunctionsImpl {
44 consensus_client,
45 domain_executor,
46 _phantom: Default::default(),
47 }
48 }
49}
50
51impl<Block, Client, DomainBlock, Executor>
52 MessengerHostFunctionsImpl<Block, Client, DomainBlock, Executor>
53where
54 Block: BlockT,
55 DomainBlock: BlockT,
56 Client: HeaderBackend<Block> + ProvideRuntimeApi<Block>,
57 Client::Api: DomainsApi<Block, DomainBlock::Header>,
58 Executor: CodeExecutor + RuntimeVersionOf,
59{
60 fn get_domain_runtime(
61 &self,
62 consensus_block_hash: Block::Hash,
63 domain_id: DomainId,
64 ) -> Option<StatelessRuntime<Block, DomainBlock, Executor>> {
65 let runtime_api = self.consensus_client.runtime_api();
66 let consensus_block_header = self
69 .consensus_client
70 .header(consensus_block_hash)
71 .ok()
72 .flatten()?;
73
74 let block_hash = match self
80 .consensus_client
81 .header(*consensus_block_header.parent_hash())
82 .ok()
83 .flatten()
84 {
85 None => consensus_block_hash,
88 Some(header) => header.hash(),
89 };
90
91 let domain_runtime = runtime_api
92 .domain_runtime_code(block_hash, domain_id)
93 .ok()
94 .flatten()?;
95
96 let domain_state = runtime_api
98 .domain_instance_data(block_hash, domain_id)
99 .ok()
100 .flatten()
101 .map(|(data, _)| data.raw_genesis.into_storage())?;
102 let mut domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
103 self.domain_executor.clone(),
104 domain_runtime.into(),
105 );
106
107 domain_stateless_runtime.set_storage(domain_state);
108 Some(domain_stateless_runtime)
109 }
110}
111
112impl<Block, Client, DomainBlock, Executor> MessengerHostFunctions
113 for MessengerHostFunctionsImpl<Block, Client, DomainBlock, Executor>
114where
115 Block: BlockT,
116 Block::Hash: From<H256>,
117 DomainBlock: BlockT,
118 Client: HeaderBackend<Block> + ProvideRuntimeApi<Block>,
119 Client::Api:
120 MessengerApi<Block, NumberFor<Block>, Block::Hash> + DomainsApi<Block, DomainBlock::Header>,
121 Executor: CodeExecutor + RuntimeVersionOf,
122{
123 fn get_storage_key(&self, req: StorageKeyRequest) -> Option<Vec<u8>> {
124 let best_hash = self.consensus_client.info().best_hash;
125 let runtime_api = self.consensus_client.runtime_api();
126 match req {
127 StorageKeyRequest::ConfirmedDomainBlockStorageKey(domain_id) => runtime_api
128 .confirmed_domain_block_storage_key(best_hash, domain_id)
129 .map(Some),
130 StorageKeyRequest::OutboxStorageKey {
131 message_key,
132 chain_id: ChainId::Consensus,
133 } => runtime_api
134 .outbox_storage_key(best_hash, message_key)
135 .map(Some),
136 StorageKeyRequest::OutboxStorageKey {
137 message_key,
138 chain_id: ChainId::Domain(domain_id),
139 } => {
140 let domain_stateless_runtime = self.get_domain_runtime(best_hash, domain_id)?;
141 domain_stateless_runtime
142 .outbox_storage_key(message_key)
143 .map(Some)
144 }
145 StorageKeyRequest::InboxResponseStorageKey {
146 message_key,
147 chain_id: ChainId::Consensus,
148 } => runtime_api
149 .inbox_response_storage_key(best_hash, message_key)
150 .map(Some),
151 StorageKeyRequest::InboxResponseStorageKey {
152 message_key,
153 chain_id: ChainId::Domain(domain_id),
154 } => {
155 let domain_stateless_runtime = self.get_domain_runtime(best_hash, domain_id)?;
156 domain_stateless_runtime
157 .inbox_response_storage_key(message_key)
158 .map(Some)
159 }
160 }
161 .expect(
162 "Runtime Api should not fail in host function, there is no recovery from this; qed.",
163 )
164 }
165}