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 let domain_runtime = runtime_api
74 .domain_runtime_code(*consensus_block_header.parent_hash(), domain_id)
75 .ok()
76 .flatten()?;
77
78 let domain_state = runtime_api
80 .domain_instance_data(*consensus_block_header.parent_hash(), domain_id)
81 .ok()
82 .flatten()
83 .map(|(data, _)| data.raw_genesis.into_storage())?;
84 let mut domain_stateless_runtime = StatelessRuntime::<Block, DomainBlock, _>::new(
85 self.domain_executor.clone(),
86 domain_runtime.into(),
87 );
88
89 domain_stateless_runtime.set_storage(domain_state);
90 Some(domain_stateless_runtime)
91 }
92}
93
94impl<Block, Client, DomainBlock, Executor> MessengerHostFunctions
95 for MessengerHostFunctionsImpl<Block, Client, DomainBlock, Executor>
96where
97 Block: BlockT,
98 Block::Hash: From<H256>,
99 DomainBlock: BlockT,
100 Client: HeaderBackend<Block> + ProvideRuntimeApi<Block>,
101 Client::Api:
102 MessengerApi<Block, NumberFor<Block>, Block::Hash> + DomainsApi<Block, DomainBlock::Header>,
103 Executor: CodeExecutor + RuntimeVersionOf,
104{
105 fn get_storage_key(&self, req: StorageKeyRequest) -> Option<Vec<u8>> {
106 let best_hash = self.consensus_client.info().best_hash;
107 let runtime_api = self.consensus_client.runtime_api();
108 match req {
109 StorageKeyRequest::ConfirmedDomainBlockStorageKey(domain_id) => runtime_api
110 .confirmed_domain_block_storage_key(best_hash, domain_id)
111 .map(Some),
112 StorageKeyRequest::OutboxStorageKey {
113 message_key,
114 chain_id: ChainId::Consensus,
115 } => runtime_api
116 .outbox_storage_key(best_hash, message_key)
117 .map(Some),
118 StorageKeyRequest::OutboxStorageKey {
119 message_key,
120 chain_id: ChainId::Domain(domain_id),
121 } => {
122 let domain_stateless_runtime = self.get_domain_runtime(best_hash, domain_id)?;
123 domain_stateless_runtime
124 .outbox_storage_key(message_key)
125 .map(Some)
126 }
127 StorageKeyRequest::InboxResponseStorageKey {
128 message_key,
129 chain_id: ChainId::Consensus,
130 } => runtime_api
131 .inbox_response_storage_key(best_hash, message_key)
132 .map(Some),
133 StorageKeyRequest::InboxResponseStorageKey {
134 message_key,
135 chain_id: ChainId::Domain(domain_id),
136 } => {
137 let domain_stateless_runtime = self.get_domain_runtime(best_hash, domain_id)?;
138 domain_stateless_runtime
139 .inbox_response_storage_key(message_key)
140 .map(Some)
141 }
142 }
143 .expect(
144 "Runtime Api should not fail in host function, there is no recovery from this; qed.",
145 )
146 }
147}