/__w/smoldot/smoldot/repo/full-node/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Smoldot |
2 | | // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. |
3 | | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 |
4 | | |
5 | | // This program is free software: you can redistribute it and/or modify |
6 | | // it under the terms of the GNU General Public License as published by |
7 | | // the Free Software Foundation, either version 3 of the License, or |
8 | | // (at your option) any later version. |
9 | | |
10 | | // This program is distributed in the hope that it will be useful, |
11 | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | // GNU General Public License for more details. |
14 | | |
15 | | // You should have received a copy of the GNU General Public License |
16 | | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | |
18 | | #![deny(rustdoc::broken_intra_doc_links)] |
19 | | // TODO: #![deny(unused_crate_dependencies)] doesn't work because some deps are used only by the binary, figure if this can be fixed? |
20 | | |
21 | | use futures_util::{future, StreamExt as _}; |
22 | | use rand::RngCore as _; |
23 | | use smol::lock::Mutex; |
24 | | use smoldot::{ |
25 | | chain, chain_spec, |
26 | | database::full_sqlite, |
27 | | executor, header, |
28 | | identity::keystore, |
29 | | informant::HashDisplay, |
30 | | libp2p::{ |
31 | | connection, multiaddr, |
32 | | peer_id::{self, PeerId}, |
33 | | }, |
34 | | trie, |
35 | | }; |
36 | | use std::{array, borrow::Cow, io, iter, mem, net::SocketAddr, path::PathBuf, sync::Arc}; |
37 | | |
38 | | mod consensus_service; |
39 | | mod database_thread; |
40 | | mod jaeger_service; |
41 | | mod json_rpc_service; |
42 | | mod network_service; |
43 | | mod util; |
44 | | |
45 | | pub struct Config<'a> { |
46 | | /// Chain to connect to. |
47 | | pub chain: ChainConfig<'a>, |
48 | | /// If [`Config::chain`] contains a parachain, this field contains the configuration of the |
49 | | /// relay chain. |
50 | | pub relay_chain: Option<ChainConfig<'a>>, |
51 | | /// Ed25519 private key of network identity. |
52 | | pub libp2p_key: Box<[u8; 32]>, |
53 | | /// List of addresses to listen on. |
54 | | pub listen_addresses: Vec<multiaddr::Multiaddr>, |
55 | | /// Function that can be used to spawn background tasks. |
56 | | /// |
57 | | /// The tasks passed as parameter must be executed until they shut down. |
58 | | pub tasks_executor: Arc<dyn Fn(future::BoxFuture<'static, ()>) + Send + Sync>, |
59 | | /// Function called whenever a part of the node wants to notify of something. |
60 | | pub log_callback: Arc<dyn LogCallback + Send + Sync>, |
61 | | /// Address of a Jaeger agent to send traces to. If `None`, do not send Jaeger traces. |
62 | | pub jaeger_agent: Option<SocketAddr>, |
63 | | } |
64 | | |
65 | | /// See [`ChainConfig::json_rpc_listen`]. |
66 | | #[derive(Debug, Clone)] |
67 | | pub struct JsonRpcListenConfig { |
68 | | /// Bind point of the JSON-RPC server. |
69 | | pub address: SocketAddr, |
70 | | /// Maximum number of JSON-RPC clients that can be connected at the same time. |
71 | | pub max_json_rpc_clients: u32, |
72 | | } |
73 | | |
74 | | /// Allow generating logs. |
75 | | /// |
76 | | /// Implemented on closures. |
77 | | /// |
78 | | /// > **Note**: The `log` crate isn't used because dependencies complete pollute the logs. |
79 | | pub trait LogCallback { |
80 | | /// Add a log entry. |
81 | | fn log(&self, log_level: LogLevel, message: String); |
82 | | } |
83 | | |
84 | | impl<T: ?Sized + Fn(LogLevel, String)> LogCallback for T { |
85 | 42 | fn log(&self, log_level: LogLevel, message: String) { |
86 | 42 | (*self)(log_level, message) |
87 | 42 | } _RNvXCsiUjFBJteJ7x_17smoldot_full_nodeNCNCNvCsiLzmwikkc22_14json_rpc_basics_30send_request_errs_if_malformed0s_0NtB2_11LogCallback3logBF_ Line | Count | Source | 85 | 2 | fn log(&self, log_level: LogLevel, message: String) { | 86 | 2 | (*self)(log_level, message) | 87 | 2 | } |
_RNvXCsiUjFBJteJ7x_17smoldot_full_nodeNCNCNvCsiLzmwikkc22_14json_rpc_basics_37send_request_works_if_unknown_request0s_0NtB2_11LogCallback3logBF_ Line | Count | Source | 85 | 2 | fn log(&self, log_level: LogLevel, message: String) { | 86 | 2 | (*self)(log_level, message) | 87 | 2 | } |
Unexecuted instantiation: _RNvXINICsiUjFBJteJ7x_17smoldot_full_node0pEpNtB5_11LogCallback3logB5_ Unexecuted instantiation: _RNvXCsiUjFBJteJ7x_17smoldot_full_nodeNCNCNvCscDgN54JpMGG_6authors_21basic_block_generated0s_0NtB2_11LogCallback3logBF_ _RNvXCsiUjFBJteJ7x_17smoldot_full_nodeNCNCNvCsibGXYHQB8Ea_25json_rpc_general_requests12start_client0s_0NtB2_11LogCallback3logBF_ Line | Count | Source | 85 | 38 | fn log(&self, log_level: LogLevel, message: String) { | 86 | 38 | (*self)(log_level, message) | 87 | 38 | } |
Unexecuted instantiation: _RNvXINICshBwayKnNXDT_17smoldot_full_node0pEpNtB5_11LogCallback3logB5_ |
88 | | } |
89 | | |
90 | | /// Log level of a log entry. |
91 | | #[derive(Debug)] |
92 | | pub enum LogLevel { |
93 | | Error = 1, |
94 | | Warn = 2, |
95 | | Info = 3, |
96 | | Debug = 4, |
97 | | Trace = 5, |
98 | | } |
99 | | |
100 | | #[derive(Debug)] |
101 | | pub struct ChainConfig<'a> { |
102 | | /// Specification of the chain. |
103 | | pub chain_spec: Cow<'a, [u8]>, |
104 | | /// Identity and address of nodes to try to connect to on startup. |
105 | | pub additional_bootnodes: Vec<(peer_id::PeerId, multiaddr::Multiaddr)>, |
106 | | /// List of secret phrases to insert in the keystore of the node. Used to author blocks. |
107 | | // TODO: also automatically add the same keys through ed25519? |
108 | | pub keystore_memory: Vec<Box<[u8; 64]>>, |
109 | | /// Path to the SQLite database. If `None`, the database is opened in memory. |
110 | | pub sqlite_database_path: Option<PathBuf>, |
111 | | /// Maximum size, in bytes, of the cache SQLite uses. |
112 | | pub sqlite_cache_size: usize, |
113 | | /// Path to the directory where cryptographic keys are stored on disk. |
114 | | /// |
115 | | /// If `None`, no keys are stored in disk. |
116 | | pub keystore_path: Option<PathBuf>, |
117 | | /// Configuration of the JSON-RPC server. If `None`, no TCP server is started. |
118 | | pub json_rpc_listen: Option<JsonRpcListenConfig>, |
119 | | } |
120 | | |
121 | | /// Running client. As long as this object is alive, the client reads/writes the database and has |
122 | | /// a JSON-RPC server open. |
123 | | pub struct Client { |
124 | | json_rpc_service: json_rpc_service::JsonRpcService, |
125 | | relay_chain_json_rpc_service: Option<json_rpc_service::JsonRpcService>, |
126 | | consensus_service: Arc<consensus_service::ConsensusService>, |
127 | | relay_chain_consensus_service: Option<Arc<consensus_service::ConsensusService>>, |
128 | | network_service: Arc<network_service::NetworkService>, |
129 | | network_known_best: Arc<Mutex<Option<u64>>>, |
130 | | } |
131 | | |
132 | | impl Client { |
133 | | /// Returns the address the JSON-RPC server is listening on. |
134 | | /// |
135 | | /// Returns `None` if and only if [`ChainConfig::json_rpc_listen`] was `None` |
136 | | /// in [`Config::chain`]. |
137 | 0 | pub fn json_rpc_server_addr(&self) -> Option<SocketAddr> { |
138 | 0 | self.json_rpc_service.listen_addr() |
139 | 0 | } Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client20json_rpc_server_addr Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client20json_rpc_server_addr |
140 | | |
141 | | /// Returns the address the relay chain JSON-RPC server is listening on. |
142 | | /// |
143 | | /// Returns `None` if and only if [`Config::relay_chain`] was `None` or if |
144 | | /// [`ChainConfig::json_rpc_listen`] was `None` in [`Config::relay_chain`]. |
145 | 0 | pub fn relay_chain_json_rpc_server_addr(&self) -> Option<SocketAddr> { |
146 | 0 | self.relay_chain_json_rpc_service |
147 | 0 | .as_ref() |
148 | 0 | .and_then(|j| j.listen_addr()) Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client32relay_chain_json_rpc_server_addr0B6_ Unexecuted instantiation: _RNCNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB6_6Client32relay_chain_json_rpc_server_addr0B6_ |
149 | 0 | } Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client32relay_chain_json_rpc_server_addr Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client32relay_chain_json_rpc_server_addr |
150 | | |
151 | | /// Returns the best block according to the networking. |
152 | 0 | pub async fn network_known_best(&self) -> Option<u64> { Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client18network_known_best Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client18network_known_best |
153 | 0 | *self.network_known_best.lock().await |
154 | 0 | } Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client18network_known_best0B6_ Unexecuted instantiation: _RNCNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB6_6Client18network_known_best0B6_ |
155 | | |
156 | | /// Returns the current total number of peers of the client. |
157 | | // TODO: weird API |
158 | 0 | pub async fn num_peers(&self) -> u64 { Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client9num_peers Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client9num_peers |
159 | 0 | u64::try_from(self.network_service.num_total_peers().await).unwrap_or(u64::MAX) |
160 | 0 | } Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client9num_peers0B6_ Unexecuted instantiation: _RNCNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB6_6Client9num_peers0B6_ |
161 | | |
162 | | /// Returns the current total number of network connections of the client. |
163 | | // TODO: weird API |
164 | 0 | pub async fn num_network_connections(&self) -> u64 { Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client23num_network_connections Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client23num_network_connections |
165 | 0 | u64::try_from(self.network_service.num_connections().await).unwrap_or(u64::MAX) |
166 | 0 | } Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client23num_network_connections0B6_ Unexecuted instantiation: _RNCNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB6_6Client23num_network_connections0B6_ |
167 | | |
168 | | // TODO: not the best API |
169 | 0 | pub async fn sync_state(&self) -> consensus_service::SyncState { Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client10sync_state Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client10sync_state |
170 | 0 | self.consensus_service.sync_state().await |
171 | 0 | } Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client10sync_state0B6_ Unexecuted instantiation: _RNCNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB6_6Client10sync_state0B6_ |
172 | | |
173 | | // TODO: not the best API |
174 | 0 | pub async fn relay_chain_sync_state(&self) -> Option<consensus_service::SyncState> { Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client22relay_chain_sync_state Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client22relay_chain_sync_state |
175 | 0 | if let Some(s) = &self.relay_chain_consensus_service { |
176 | 0 | Some(s.sync_state().await) |
177 | | } else { |
178 | 0 | None |
179 | | } |
180 | 0 | } Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client22relay_chain_sync_state0B6_ Unexecuted instantiation: _RNCNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB6_6Client22relay_chain_sync_state0B6_ |
181 | | |
182 | | /// Adds a JSON-RPC request to the queue of requests of the virtual endpoint of the chain. |
183 | | /// |
184 | | /// The virtual endpoint doesn't have any limit. |
185 | 25 | pub fn send_json_rpc_request(&self, request: String) { |
186 | 25 | self.json_rpc_service.send_request(request) |
187 | 25 | } _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client21send_json_rpc_request Line | Count | Source | 185 | 25 | pub fn send_json_rpc_request(&self, request: String) { | 186 | 25 | self.json_rpc_service.send_request(request) | 187 | 25 | } |
Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client21send_json_rpc_request |
188 | | |
189 | | /// Returns the new JSON-RPC response or notification for requests sent using |
190 | | /// [`Client::send_json_rpc_request`]. |
191 | | /// |
192 | | /// If this function is called multiple times simultaneously, only one invocation will receive |
193 | | /// each response. Which one is unspecified. |
194 | 25 | pub async fn next_json_rpc_response(&self) -> String { _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client22next_json_rpc_response Line | Count | Source | 194 | 25 | pub async fn next_json_rpc_response(&self) -> String { |
Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client22next_json_rpc_response |
195 | 25 | self.json_rpc_service.next_response().await14 |
196 | 25 | } _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client22next_json_rpc_response0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 194 | 2 | pub async fn next_json_rpc_response(&self) -> String { | 195 | 2 | self.json_rpc_service.next_response().await1 | 196 | 2 | } |
Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client22next_json_rpc_response0B6_ Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client22next_json_rpc_response0CscDgN54JpMGG_6author _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client22next_json_rpc_response0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 194 | 23 | pub async fn next_json_rpc_response(&self) -> String { | 195 | 23 | self.json_rpc_service.next_response().await13 | 196 | 23 | } |
Unexecuted instantiation: _RNCNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB6_6Client22next_json_rpc_response0B6_ |
197 | | |
198 | | /// Adds a JSON-RPC request to the queue of requests of the virtual endpoint of the |
199 | | /// relay chain. |
200 | | /// |
201 | | /// The virtual endpoint doesn't have any limit. |
202 | 0 | pub fn relay_chain_send_json_rpc_request( |
203 | 0 | &self, |
204 | 0 | request: String, |
205 | 0 | ) -> Result<(), RelayChainSendJsonRpcRequestError> { |
206 | 0 | let Some(relay_chain_json_rpc_service) = &self.relay_chain_json_rpc_service else { |
207 | 0 | return Err(RelayChainSendJsonRpcRequestError::NoRelayChain); |
208 | | }; |
209 | | |
210 | 0 | relay_chain_json_rpc_service.send_request(request); |
211 | 0 | Ok(()) |
212 | 0 | } Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client33relay_chain_send_json_rpc_request Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client33relay_chain_send_json_rpc_request |
213 | | |
214 | | /// Returns the new JSON-RPC response or notification for requests sent using |
215 | | /// [`Client::relay_chain_send_json_rpc_request`]. |
216 | | /// |
217 | | /// If this function is called multiple times simultaneously, only one invocation will receive |
218 | | /// each response. Which one is unspecified. |
219 | | /// |
220 | | /// If [`Config::relay_chain`] was `None`, this function waits indefinitely. |
221 | 0 | pub async fn relay_chain_next_json_rpc_response(&self) -> String { Unexecuted instantiation: _RNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB4_6Client34relay_chain_next_json_rpc_response Unexecuted instantiation: _RNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB4_6Client34relay_chain_next_json_rpc_response |
222 | 0 | if let Some(relay_chain_json_rpc_service) = &self.relay_chain_json_rpc_service { |
223 | 0 | relay_chain_json_rpc_service.next_response().await |
224 | | } else { |
225 | 0 | future::pending().await |
226 | | } |
227 | 0 | } Unexecuted instantiation: _RNCNvMs_CsiUjFBJteJ7x_17smoldot_full_nodeNtB6_6Client34relay_chain_next_json_rpc_response0B6_ Unexecuted instantiation: _RNCNvMs_CshBwayKnNXDT_17smoldot_full_nodeNtB6_6Client34relay_chain_next_json_rpc_response0B6_ |
228 | | } |
229 | | |
230 | | /// Error potentially returned by [`start`]. |
231 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs5_CsiUjFBJteJ7x_17smoldot_full_nodeNtB5_10StartErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs5_CshBwayKnNXDT_17smoldot_full_nodeNtB5_10StartErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
232 | | pub enum StartError { |
233 | | /// Failed to parse the chain specification. |
234 | | ChainSpecParse(chain_spec::ParseError), |
235 | | /// Error building the chain information of the genesis block. |
236 | | InvalidGenesisInformation(chain_spec::FromGenesisStorageError), |
237 | | /// Failed to parse the chain specification of the relay chain. |
238 | | RelayChainSpecParse(chain_spec::ParseError), |
239 | | /// Error building the chain information of the genesis block of the relay chain. |
240 | | InvalidRelayGenesisInformation(chain_spec::FromGenesisStorageError), |
241 | | /// Error initializing the networking service. |
242 | | NetworkInit(network_service::InitError), |
243 | | /// Error initializing the JSON-RPC service. |
244 | | JsonRpcServiceInit(json_rpc_service::InitError), |
245 | | /// Error initializing the JSON-RPC service of the relay chain. |
246 | | RelayChainJsonRpcServiceInit(json_rpc_service::InitError), |
247 | | ConsensusServiceInit(consensus_service::InitError), |
248 | | RelayChainConsensusServiceInit(consensus_service::InitError), |
249 | | /// Error initializing the keystore of the chain. |
250 | | KeystoreInit(io::Error), |
251 | | /// Error initializing the keystore of the relay chain. |
252 | | RelayChainKeystoreInit(io::Error), |
253 | | /// Error initializing the Jaeger service. |
254 | | JaegerInit(io::Error), |
255 | | } |
256 | | |
257 | | /// Error potentially returned by [`Client::relay_chain_send_json_rpc_request`]. |
258 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs7_CsiUjFBJteJ7x_17smoldot_full_nodeNtB5_33RelayChainSendJsonRpcRequestErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs7_CshBwayKnNXDT_17smoldot_full_nodeNtB5_33RelayChainSendJsonRpcRequestErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
259 | | pub enum RelayChainSendJsonRpcRequestError { |
260 | | /// There is no relay chain to send the JSON-RPC request to. |
261 | | NoRelayChain, |
262 | | } |
263 | | |
264 | | /// Runs the node using the given configuration. |
265 | | // TODO: this function has several code paths that panic instead of returning an error; it is especially unclear what to do in case of database corruption, given that a database corruption would crash the node later on anyway |
266 | 21 | pub async fn start(mut config: Config<'_>) -> Result<Client, StartError> { _RNvCsiUjFBJteJ7x_17smoldot_full_node5start Line | Count | Source | 266 | 21 | pub async fn start(mut config: Config<'_>) -> Result<Client, StartError> { |
Unexecuted instantiation: _RNvCshBwayKnNXDT_17smoldot_full_node5start |
267 | 21 | let chain_spec = { |
268 | 21 | chain_spec::ChainSpec::from_json_bytes(&config.chain.chain_spec) |
269 | 21 | .map_err(StartError::ChainSpecParse)?0 |
270 | | }; |
271 | | |
272 | | // TODO: don't just throw away the runtime |
273 | | // TODO: building the genesis chain information is pretty expensive and we throw away most of the information |
274 | 21 | let genesis_chain_information = chain_spec |
275 | 21 | .to_chain_information() |
276 | 21 | .map_err(StartError::InvalidGenesisInformation)?0 |
277 | | .0; |
278 | | |
279 | 21 | let relay_chain_spec = match &config.relay_chain { |
280 | 0 | Some(cfg) => Some( |
281 | 0 | chain_spec::ChainSpec::from_json_bytes(&cfg.chain_spec) |
282 | 0 | .map_err(StartError::RelayChainSpecParse)?, |
283 | | ), |
284 | 21 | None => None, |
285 | | }; |
286 | | |
287 | | // TODO: don't just throw away the runtime |
288 | | // TODO: building the genesis chain information is pretty expensive and we throw away most of the information |
289 | 21 | let relay_genesis_chain_information = match &relay_chain_spec { |
290 | 0 | Some(r) => Some( |
291 | 0 | r.to_chain_information() |
292 | 0 | .map_err(StartError::InvalidRelayGenesisInformation)? |
293 | | .0, |
294 | | ), |
295 | 21 | None => None, |
296 | | }; |
297 | | |
298 | | // The `protocolId` field of chain specifications is deprecated. Print a warning. |
299 | 21 | if chain_spec.protocol_id().is_some() { |
300 | 0 | config.log_callback.log( |
301 | 0 | LogLevel::Warn, |
302 | 0 | format!("chain-spec-has-protocol-id; chain={}", chain_spec.id()), |
303 | 0 | ); |
304 | 21 | } |
305 | 21 | if let Some(relay_chain_spec0 ) = &relay_chain_spec { |
306 | 0 | if relay_chain_spec.protocol_id().is_some() { |
307 | 0 | config.log_callback.log( |
308 | 0 | LogLevel::Warn, |
309 | 0 | format!( |
310 | 0 | "chain-spec-has-protocol-id; chain={}", |
311 | 0 | relay_chain_spec.id() |
312 | 0 | ), |
313 | 0 | ); |
314 | 0 | } |
315 | 21 | } |
316 | | |
317 | | // The `telemetryEndpoints` field of chain specifications isn't supported. |
318 | 21 | if chain_spec.telemetry_endpoints().count() != 0 { |
319 | 0 | config.log_callback.log( |
320 | 0 | LogLevel::Warn, |
321 | 0 | format!( |
322 | 0 | "chain-spec-has-telemetry-endpoints; chain={}", |
323 | 0 | chain_spec.id() |
324 | 0 | ), |
325 | 0 | ); |
326 | 21 | } |
327 | 21 | if let Some(relay_chain_spec0 ) = &relay_chain_spec { |
328 | 0 | if relay_chain_spec.telemetry_endpoints().count() != 0 { |
329 | 0 | config.log_callback.log( |
330 | 0 | LogLevel::Warn, |
331 | 0 | format!( |
332 | 0 | "chain-spec-has-telemetry-endpoints; chain={}", |
333 | 0 | relay_chain_spec.id() |
334 | 0 | ), |
335 | 0 | ); |
336 | 0 | } |
337 | 21 | } |
338 | | |
339 | | // Printing the SQLite version number can be useful for debugging purposes for example in case |
340 | | // a query fails. |
341 | 21 | config.log_callback.log( |
342 | 21 | LogLevel::Debug, |
343 | 21 | format!("sqlite-version; version={}", full_sqlite::sqlite_version()), |
344 | 21 | ); |
345 | | |
346 | 21 | let (database, database_existed) = { |
347 | 21 | let (db, existed) = open_database( |
348 | 21 | &chain_spec, |
349 | 21 | genesis_chain_information.as_ref(), |
350 | 21 | config.chain.sqlite_database_path, |
351 | 21 | config.chain.sqlite_cache_size, |
352 | 21 | ) |
353 | 0 | .await; |
354 | | |
355 | 21 | (Arc::new(database_thread::DatabaseThread::from(db)), existed) |
356 | | }; |
357 | | |
358 | 21 | let relay_chain_database = if let Some(relay_chain0 ) = &config.relay_chain { |
359 | | Some(Arc::new(database_thread::DatabaseThread::from( |
360 | 0 | open_database( |
361 | 0 | relay_chain_spec.as_ref().unwrap(), |
362 | 0 | relay_genesis_chain_information.as_ref().unwrap().as_ref(), |
363 | 0 | relay_chain.sqlite_database_path.clone(), |
364 | 0 | relay_chain.sqlite_cache_size, |
365 | 0 | ) |
366 | 0 | .await |
367 | | .0, |
368 | | ))) |
369 | | } else { |
370 | 21 | None |
371 | | }; |
372 | | |
373 | 21 | let database_finalized_block_hash = database |
374 | 21 | .with_database(|db| db.finalized_block_hash().unwrap()) _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start00CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 374 | 2 | .with_database(|db| db.finalized_block_hash().unwrap()) |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start00B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start00CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start00CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 374 | 19 | .with_database(|db| db.finalized_block_hash().unwrap()) |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start00B5_ |
375 | 21 | .await; |
376 | 21 | let database_finalized_block_number = header::decode( |
377 | 21 | &database |
378 | 21 | .with_database(move |db| { |
379 | 21 | db.block_scale_encoded_header(&database_finalized_block_hash) |
380 | 21 | .unwrap() |
381 | 21 | .unwrap() |
382 | 21 | }) _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s_0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 378 | 2 | .with_database(move |db| { | 379 | 2 | db.block_scale_encoded_header(&database_finalized_block_hash) | 380 | 2 | .unwrap() | 381 | 2 | .unwrap() | 382 | 2 | }) |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s_0CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s_0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 378 | 19 | .with_database(move |db| { | 379 | 19 | db.block_scale_encoded_header(&database_finalized_block_hash) | 380 | 19 | .unwrap() | 381 | 19 | .unwrap() | 382 | 19 | }) |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s_0B5_ |
383 | 21 | .await, |
384 | 21 | chain_spec.block_number_bytes().into(), |
385 | 21 | ) |
386 | 21 | .unwrap() |
387 | 21 | .number; |
388 | 21 | |
389 | 21 | let noise_key = { |
390 | 21 | let mut noise_static_key = zeroize::Zeroizing::new([0u8; 32]); |
391 | 21 | rand::thread_rng().fill_bytes(&mut *noise_static_key); |
392 | 21 | connection::NoiseKey::new(&config.libp2p_key, &noise_static_key) |
393 | 21 | }; |
394 | 21 | zeroize::Zeroize::zeroize(&mut *config.libp2p_key); |
395 | 21 | let local_peer_id = |
396 | 21 | peer_id::PublicKey::Ed25519(*noise_key.libp2p_public_ed25519_key()).into_peer_id(); |
397 | 21 | |
398 | 21 | let genesis_block_hash = genesis_chain_information |
399 | 21 | .as_ref() |
400 | 21 | .finalized_block_header |
401 | 21 | .hash(chain_spec.block_number_bytes().into()); |
402 | | |
403 | 21 | let jaeger_service = jaeger_service::JaegerService::new(jaeger_service::Config { |
404 | 21 | tasks_executor: &mut |task| (config.tasks_executor)(task)0 , Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s0_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s0_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s0_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s0_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s0_0B5_ |
405 | 21 | service_name: local_peer_id.to_string(), |
406 | 21 | jaeger_agent: config.jaeger_agent, |
407 | 21 | }) |
408 | 0 | .await |
409 | 21 | .map_err(StartError::JaegerInit)?0 ; |
410 | | |
411 | 21 | let (network_service, network_service_chain_ids, network_events_receivers) = |
412 | | network_service::NetworkService::new(network_service::Config { |
413 | 21 | listen_addresses: config.listen_addresses, |
414 | 21 | num_events_receivers: 2 + if relay_chain_database.is_some() { 10 } else { 0 }, |
415 | | chains: iter::once(network_service::ChainConfig { |
416 | 21 | log_name: chain_spec.id().to_owned(), |
417 | 21 | fork_id: chain_spec.fork_id().map(|n| n.to_owned()0 ), Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s1_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s1_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s1_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s1_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s1_0B5_ |
418 | 21 | block_number_bytes: usize::from(chain_spec.block_number_bytes()), |
419 | 21 | database: database.clone(), |
420 | 0 | grandpa_protocol_finalized_block_height: if matches!( |
421 | 21 | genesis_chain_information.as_ref().finality, |
422 | | chain::chain_information::ChainInformationFinalityRef::Grandpa { .. } |
423 | | ) { |
424 | | Some({ |
425 | 21 | let block_number_bytes = chain_spec.block_number_bytes(); |
426 | 21 | database |
427 | 21 | .with_database(move |database| { |
428 | 21 | let hash = database.finalized_block_hash().unwrap(); |
429 | 21 | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); |
430 | 21 | header::decode(&header, block_number_bytes.into(),).unwrap().number |
431 | 21 | }) _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s2_0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 427 | 2 | .with_database(move |database| { | 428 | 2 | let hash = database.finalized_block_hash().unwrap(); | 429 | 2 | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); | 430 | 2 | header::decode(&header, block_number_bytes.into(),).unwrap().number | 431 | 2 | }) |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s2_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s2_0CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s2_0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 427 | 19 | .with_database(move |database| { | 428 | 19 | let hash = database.finalized_block_hash().unwrap(); | 429 | 19 | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); | 430 | 19 | header::decode(&header, block_number_bytes.into(),).unwrap().number | 431 | 19 | }) |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s2_0B5_ |
432 | 21 | .await |
433 | | }) |
434 | | } else { |
435 | 0 | None |
436 | | }, |
437 | 21 | genesis_block_hash, |
438 | 21 | best_block: { |
439 | 21 | let block_number_bytes = chain_spec.block_number_bytes(); |
440 | 21 | database |
441 | 21 | .with_database(move |database| { |
442 | 21 | let hash = database.finalized_block_hash().unwrap(); |
443 | 21 | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); |
444 | 21 | let number = header::decode(&header, block_number_bytes.into(),).unwrap().number; |
445 | 21 | (number, hash) |
446 | 21 | }) _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s3_0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 441 | 2 | .with_database(move |database| { | 442 | 2 | let hash = database.finalized_block_hash().unwrap(); | 443 | 2 | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); | 444 | 2 | let number = header::decode(&header, block_number_bytes.into(),).unwrap().number; | 445 | 2 | (number, hash) | 446 | 2 | }) |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s3_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s3_0CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s3_0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 441 | 19 | .with_database(move |database| { | 442 | 19 | let hash = database.finalized_block_hash().unwrap(); | 443 | 19 | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); | 444 | 19 | let number = header::decode(&header, block_number_bytes.into(),).unwrap().number; | 445 | 19 | (number, hash) | 446 | 19 | }) |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s3_0B5_ |
447 | 21 | .await |
448 | | }, |
449 | | max_in_peers: 25, |
450 | | max_slots: 15, |
451 | | bootstrap_nodes: { |
452 | 21 | let mut list = Vec::with_capacity( |
453 | 21 | chain_spec.boot_nodes().len() + config.chain.additional_bootnodes.len(), |
454 | 21 | ); |
455 | | |
456 | 21 | for node0 in chain_spec.boot_nodes() { |
457 | 0 | match node { |
458 | 0 | chain_spec::Bootnode::UnrecognizedFormat(raw) => { |
459 | 0 | config.log_callback.log( |
460 | 0 | LogLevel::Warn, |
461 | 0 | format!("bootnode-unrecognized-addr; value={:?}", raw), |
462 | 0 | ); |
463 | 0 | } |
464 | 0 | chain_spec::Bootnode::Parsed { multiaddr, peer_id } => { |
465 | 0 | let multiaddr: multiaddr::Multiaddr = match multiaddr.parse() { |
466 | 0 | Ok(a) => a, |
467 | | Err(_) => { |
468 | 0 | config.log_callback.log( |
469 | 0 | LogLevel::Warn, |
470 | 0 | format!("bootnode-unrecognized-addr; value={:?}", multiaddr), |
471 | 0 | ); |
472 | 0 | continue; |
473 | | }, |
474 | | }; |
475 | 0 | let peer_id = PeerId::from_bytes(peer_id.to_vec()).unwrap(); |
476 | 0 | list.push((peer_id, multiaddr)); |
477 | | } |
478 | | } |
479 | | } |
480 | | |
481 | 21 | list.extend(config.chain.additional_bootnodes); |
482 | 21 | list |
483 | | }, |
484 | | }) |
485 | | .chain( |
486 | 21 | if let Some(relay_chains_specs0 ) = &relay_chain_spec { |
487 | | Some(network_service::ChainConfig { |
488 | 0 | log_name: relay_chains_specs.id().to_owned(), |
489 | 0 | fork_id: relay_chains_specs.fork_id().map(|n| n.to_owned()), Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s4_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s4_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s4_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s4_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s4_0B5_ |
490 | 0 | block_number_bytes: usize::from(relay_chains_specs.block_number_bytes()), |
491 | 0 | database: relay_chain_database.clone().unwrap(), |
492 | 0 | grandpa_protocol_finalized_block_height: if matches!( |
493 | 0 | genesis_chain_information.as_ref().finality, |
494 | | chain::chain_information::ChainInformationFinalityRef::Grandpa { .. } |
495 | | ) { |
496 | 0 | Some(relay_chain_database |
497 | 0 | .as_ref() |
498 | 0 | .unwrap() |
499 | 0 | .with_database({ |
500 | 0 | let block_number_bytes = chain_spec.block_number_bytes(); |
501 | 0 | move |db| { |
502 | 0 | let hash = db.finalized_block_hash().unwrap(); |
503 | 0 | let header = db.block_scale_encoded_header(&hash).unwrap().unwrap(); |
504 | 0 | header::decode(&header, block_number_bytes.into()).unwrap().number |
505 | 0 | } Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s5_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s5_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s5_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s5_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s5_0B5_ |
506 | 0 | }) |
507 | 0 | .await) |
508 | | } else { |
509 | 0 | None |
510 | | }, |
511 | 0 | genesis_block_hash: relay_genesis_chain_information |
512 | 0 | .as_ref() |
513 | 0 | .unwrap() |
514 | 0 | .as_ref().finalized_block_header |
515 | 0 | .hash(chain_spec.block_number_bytes().into(),), |
516 | 0 | best_block: relay_chain_database |
517 | 0 | .as_ref() |
518 | 0 | .unwrap() |
519 | 0 | .with_database({ |
520 | 0 | let block_number_bytes = chain_spec.block_number_bytes(); |
521 | 0 | move |db| { |
522 | 0 | let hash = db.finalized_block_hash().unwrap(); |
523 | 0 | let header = db.block_scale_encoded_header(&hash).unwrap().unwrap(); |
524 | 0 | let number = header::decode(&header, block_number_bytes.into()).unwrap().number; |
525 | 0 | (number, hash) |
526 | 0 | } Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s6_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s6_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s6_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s6_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s6_0B5_ |
527 | 0 | }) |
528 | 0 | .await, |
529 | | max_in_peers: 25, |
530 | | max_slots: 15, |
531 | | bootstrap_nodes: { |
532 | 0 | let mut list = |
533 | 0 | Vec::with_capacity(relay_chains_specs.boot_nodes().len()); |
534 | 0 | for node in relay_chains_specs.boot_nodes() { |
535 | 0 | match node { |
536 | 0 | chain_spec::Bootnode::UnrecognizedFormat(raw) => { |
537 | 0 | config.log_callback.log( |
538 | 0 | LogLevel::Warn, |
539 | 0 | format!("relay-chain-bootnode-unrecognized-addr; value={:?}", raw), |
540 | 0 | ); |
541 | 0 | } |
542 | 0 | chain_spec::Bootnode::Parsed { multiaddr, peer_id } => { |
543 | 0 | let multiaddr: multiaddr::Multiaddr = match multiaddr.parse() { |
544 | 0 | Ok(a) => a, |
545 | | Err(_) => { |
546 | 0 | config.log_callback.log( |
547 | 0 | LogLevel::Warn, |
548 | 0 | format!("relay-chain-bootnode-unrecognized-addr; value={:?}", multiaddr), |
549 | 0 | ); |
550 | 0 | continue; |
551 | | } |
552 | | }; |
553 | 0 | let peer_id = PeerId::from_bytes(peer_id.to_vec()).unwrap(); |
554 | 0 | list.push((peer_id, multiaddr)); |
555 | | } |
556 | | } |
557 | | } |
558 | 0 | list |
559 | | }, |
560 | | }) |
561 | | } else { |
562 | 21 | None |
563 | | } |
564 | 21 | .into_iter(), |
565 | 21 | ) |
566 | 21 | .collect(), |
567 | 21 | identify_agent_version: concat!(env!("CARGO_PKG_NAME"), " ", env!("CARGO_PKG_VERSION")).to_owned(), |
568 | 21 | noise_key, |
569 | 21 | tasks_executor: { |
570 | 21 | let executor = config.tasks_executor.clone(); |
571 | 21 | Box::new(move |task| executor(task)) _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s7_0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 571 | 2 | Box::new(move |task| executor(task)) |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s7_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s7_0CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s7_0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 571 | 19 | Box::new(move |task| executor(task)) |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s7_0B5_ |
572 | 21 | }, |
573 | 21 | log_callback: config.log_callback.clone(), |
574 | 21 | jaeger_service: jaeger_service.clone(), |
575 | | }) |
576 | 0 | .await |
577 | 21 | .map_err(StartError::NetworkInit)?0 ; |
578 | | |
579 | 21 | let mut network_events_receivers = network_events_receivers.into_iter(); |
580 | | |
581 | 21 | let keystore = Arc::new({ |
582 | 21 | let mut keystore = keystore::Keystore::new(config.chain.keystore_path, rand::random()) |
583 | 0 | .await |
584 | 21 | .map_err(StartError::KeystoreInit)?0 ; |
585 | 21 | for mut private_key0 in config.chain.keystore_memory { |
586 | 0 | keystore.insert_sr25519_memory(keystore::KeyNamespace::all(), &private_key); |
587 | 0 | zeroize::Zeroize::zeroize(&mut *private_key); |
588 | 0 | } |
589 | 21 | keystore |
590 | | }); |
591 | | |
592 | 21 | let consensus_service = consensus_service::ConsensusService::new(consensus_service::Config { |
593 | 21 | tasks_executor: { |
594 | 21 | let executor = config.tasks_executor.clone(); |
595 | 21 | Box::new(move |task| executor(task)) _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s8_0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 595 | 2 | Box::new(move |task| executor(task)) |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s8_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s8_0CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s8_0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 595 | 19 | Box::new(move |task| executor(task)) |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s8_0B5_ |
596 | 21 | }, |
597 | 21 | log_callback: config.log_callback.clone(), |
598 | 21 | genesis_block_hash, |
599 | 21 | network_events_receiver: network_events_receivers.next().unwrap(), |
600 | 21 | network_service: (network_service.clone(), network_service_chain_ids[0]), |
601 | 21 | database: database.clone(), |
602 | 21 | block_number_bytes: usize::from(chain_spec.block_number_bytes()), |
603 | 21 | keystore, |
604 | 21 | jaeger_service: jaeger_service.clone(), |
605 | 21 | slot_duration_author_ratio: 43691_u16, |
606 | 21 | }) |
607 | 21 | .await |
608 | 21 | .map_err(StartError::ConsensusServiceInit)?0 ; |
609 | | |
610 | 21 | let relay_chain_consensus_service = if let Some(relay_chain_database0 ) = &relay_chain_database { |
611 | | Some( |
612 | | consensus_service::ConsensusService::new(consensus_service::Config { |
613 | | tasks_executor: { |
614 | 0 | let executor = config.tasks_executor.clone(); |
615 | 0 | Box::new(move |task| executor(task)) Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s9_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s9_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s9_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0s9_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0s9_0B5_ |
616 | 0 | }, |
617 | 0 | log_callback: config.log_callback.clone(), |
618 | 0 | genesis_block_hash: relay_genesis_chain_information |
619 | 0 | .as_ref() |
620 | 0 | .unwrap() |
621 | 0 | .as_ref() |
622 | 0 | .finalized_block_header |
623 | 0 | .hash(usize::from( |
624 | 0 | relay_chain_spec.as_ref().unwrap().block_number_bytes(), |
625 | 0 | )), |
626 | 0 | network_events_receiver: network_events_receivers.next().unwrap(), |
627 | 0 | network_service: (network_service.clone(), network_service_chain_ids[1]), |
628 | 0 | database: relay_chain_database.clone(), |
629 | 0 | block_number_bytes: usize::from( |
630 | 0 | relay_chain_spec.as_ref().unwrap().block_number_bytes(), |
631 | 0 | ), |
632 | | keystore: Arc::new({ |
633 | 0 | let mut keystore = keystore::Keystore::new( |
634 | 0 | config.relay_chain.as_ref().unwrap().keystore_path.clone(), |
635 | 0 | rand::random(), |
636 | 0 | ) |
637 | 0 | .await |
638 | 0 | .map_err(StartError::RelayChainKeystoreInit)?; |
639 | 0 | for mut private_key in |
640 | 0 | mem::take(&mut config.relay_chain.as_mut().unwrap().keystore_memory) |
641 | 0 | { |
642 | 0 | keystore.insert_sr25519_memory(keystore::KeyNamespace::all(), &private_key); |
643 | 0 | zeroize::Zeroize::zeroize(&mut *private_key); |
644 | 0 | } |
645 | 0 | keystore |
646 | 0 | }), |
647 | 0 | jaeger_service, // TODO: consider passing a different jaeger service with a different service name |
648 | | slot_duration_author_ratio: 43691_u16, |
649 | | }) |
650 | 0 | .await |
651 | 0 | .map_err(StartError::RelayChainConsensusServiceInit)?, |
652 | | ) |
653 | | } else { |
654 | 21 | None |
655 | | }; |
656 | | |
657 | | // Start the JSON-RPC service. |
658 | | // It only needs to be kept alive in order to function. |
659 | | // |
660 | | // Note that initialization can fail if, for example, the port is already occupied. It is |
661 | | // preferable to fail to start the node altogether rather than make the user believe that they |
662 | | // are connected to the JSON-RPC endpoint of the node while they are in reality connected to |
663 | | // something else. |
664 | 21 | let json_rpc_service = json_rpc_service::JsonRpcService::new(json_rpc_service::Config { |
665 | 21 | tasks_executor: config.tasks_executor.clone(), |
666 | 21 | log_callback: config.log_callback.clone(), |
667 | 21 | database, |
668 | 21 | consensus_service: consensus_service.clone(), |
669 | 21 | network_service: (network_service.clone(), network_service_chain_ids[0]), |
670 | 21 | bind_address: config.chain.json_rpc_listen.as_ref().map(|cfg| cfg.address0 ), Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sa_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sa_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sa_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sa_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0sa_0B5_ |
671 | 21 | max_parallel_requests: 32, |
672 | 21 | max_json_rpc_clients: config |
673 | 21 | .chain |
674 | 21 | .json_rpc_listen |
675 | 21 | .map_or(0, |cfg| cfg.max_json_rpc_clients0 ), Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sb_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sb_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sb_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sb_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0sb_0B5_ |
676 | 21 | chain_name: chain_spec.name().to_owned(), |
677 | 21 | chain_type: chain_spec.chain_type().to_owned(), |
678 | 21 | chain_properties_json: chain_spec.properties().to_owned(), |
679 | 21 | chain_is_live: chain_spec.has_live_network(), |
680 | 21 | genesis_block_hash: genesis_chain_information |
681 | 21 | .as_ref() |
682 | 21 | .finalized_block_header |
683 | 21 | .hash(usize::from(chain_spec.block_number_bytes())), |
684 | 21 | }) |
685 | 0 | .await |
686 | 21 | .map_err(StartError::JsonRpcServiceInit)?0 ; |
687 | | |
688 | | // Start the JSON-RPC service of the relay chain. |
689 | | // See remarks above. |
690 | 21 | let relay_chain_json_rpc_service = if let Some(relay_chain_cfg0 ) = config.relay_chain { |
691 | 0 | let relay_chain_spec = relay_chain_spec.as_ref().unwrap(); |
692 | 0 | Some( |
693 | 0 | json_rpc_service::JsonRpcService::new(json_rpc_service::Config { |
694 | 0 | tasks_executor: config.tasks_executor.clone(), |
695 | 0 | log_callback: config.log_callback.clone(), |
696 | 0 | database: relay_chain_database.clone().unwrap(), |
697 | 0 | consensus_service: relay_chain_consensus_service.clone().unwrap(), |
698 | 0 | network_service: (network_service.clone(), network_service_chain_ids[1]), |
699 | 0 | bind_address: relay_chain_cfg |
700 | 0 | .json_rpc_listen |
701 | 0 | .as_ref() |
702 | 0 | .map(|cfg| cfg.address), Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sc_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sc_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sc_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sc_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0sc_0B5_ |
703 | 0 | max_parallel_requests: 32, |
704 | 0 | max_json_rpc_clients: relay_chain_cfg |
705 | 0 | .json_rpc_listen |
706 | 0 | .map_or(0, |cfg| cfg.max_json_rpc_clients), Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sd_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sd_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sd_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0sd_0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0sd_0B5_ |
707 | 0 | chain_name: relay_chain_spec.name().to_owned(), |
708 | 0 | chain_type: relay_chain_spec.chain_type().to_owned(), |
709 | 0 | chain_properties_json: relay_chain_spec.properties().to_owned(), |
710 | 0 | chain_is_live: relay_chain_spec.has_live_network(), |
711 | 0 | genesis_block_hash: relay_genesis_chain_information |
712 | 0 | .as_ref() |
713 | 0 | .unwrap() |
714 | 0 | .as_ref() |
715 | 0 | .finalized_block_header |
716 | 0 | .hash(usize::from(relay_chain_spec.block_number_bytes())), |
717 | 0 | }) |
718 | 0 | .await |
719 | 0 | .map_err(StartError::JsonRpcServiceInit)?, |
720 | | ) |
721 | | } else { |
722 | 21 | None |
723 | | }; |
724 | | |
725 | | // Spawn the task printing the informant. |
726 | | // This is not just a dummy task that just prints on the output, but is actually the main |
727 | | // task that holds everything else alive. Without it, all the services that we have created |
728 | | // above would be cleanly dropped and nothing would happen. |
729 | | // For this reason, it must be spawned even if no informant is started, in which case we simply |
730 | | // inhibit the printing. |
731 | 21 | let network_known_best = Arc::new(Mutex::new(None)); |
732 | 21 | (config.tasks_executor)(Box::pin({ |
733 | 21 | let mut main_network_events_receiver = network_events_receivers.next().unwrap(); |
734 | 21 | let network_service_chain_id = network_service_chain_ids[0]; |
735 | 21 | let network_known_best = network_known_best.clone(); |
736 | 21 | |
737 | 21 | // TODO: shut down this task if the client stops? |
738 | 21 | async move { |
739 | | loop { |
740 | 21 | let network_event0 = main_network_events_receiver.next().await0 .unwrap()0 ; |
741 | 0 | let mut network_known_best = network_known_best.lock().await; |
742 | | |
743 | 0 | match network_event { |
744 | | network_service::Event::BlockAnnounce { |
745 | 0 | chain_id, |
746 | 0 | scale_encoded_header, |
747 | | .. |
748 | 0 | } if chain_id == network_service_chain_id => match ( |
749 | 0 | *network_known_best, |
750 | 0 | header::decode( |
751 | 0 | &scale_encoded_header, |
752 | 0 | usize::from(chain_spec.block_number_bytes()), |
753 | 0 | ), |
754 | | ) { |
755 | 0 | (Some(n), Ok(header)) if n >= header.number => {} |
756 | 0 | (_, Ok(header)) => *network_known_best = Some(header.number), |
757 | 0 | (_, Err(_)) => { |
758 | 0 | // Do nothing if the block is invalid. This is just for the |
759 | 0 | // informant and not for consensus-related purposes. |
760 | 0 | } |
761 | | }, |
762 | | network_service::Event::Connected { |
763 | 0 | chain_id, |
764 | 0 | best_block_number, |
765 | | .. |
766 | 0 | } if chain_id == network_service_chain_id => match *network_known_best { |
767 | 0 | Some(n) if n >= best_block_number => {} |
768 | 0 | _ => *network_known_best = Some(best_block_number), |
769 | | }, |
770 | 0 | _ => {} _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0se_0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 738 | 2 | async move { | 739 | | loop { | 740 | 2 | let network_event0 = main_network_events_receiver.next().await0 .unwrap()0 ; | 741 | 0 | let mut network_known_best = network_known_best.lock().await; | 742 | | | 743 | 0 | match network_event { | 744 | | network_service::Event::BlockAnnounce { | 745 | 0 | chain_id, | 746 | 0 | scale_encoded_header, | 747 | | .. | 748 | 0 | } if chain_id == network_service_chain_id => match ( | 749 | 0 | *network_known_best, | 750 | 0 | header::decode( | 751 | 0 | &scale_encoded_header, | 752 | 0 | usize::from(chain_spec.block_number_bytes()), | 753 | 0 | ), | 754 | | ) { | 755 | 0 | (Some(n), Ok(header)) if n >= header.number => {} | 756 | 0 | (_, Ok(header)) => *network_known_best = Some(header.number), | 757 | 0 | (_, Err(_)) => { | 758 | 0 | // Do nothing if the block is invalid. This is just for the | 759 | 0 | // informant and not for consensus-related purposes. | 760 | 0 | } | 761 | | }, | 762 | | network_service::Event::Connected { | 763 | 0 | chain_id, | 764 | 0 | best_block_number, | 765 | | .. | 766 | 0 | } if chain_id == network_service_chain_id => match *network_known_best { | 767 | 0 | Some(n) if n >= best_block_number => {} | 768 | 0 | _ => *network_known_best = Some(best_block_number), | 769 | | }, | 770 | 0 | _ => {} |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0se_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0se_0CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0se_0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 738 | 19 | async move { | 739 | | loop { | 740 | 19 | let network_event0 = main_network_events_receiver.next().await0 .unwrap()0 ; | 741 | 0 | let mut network_known_best = network_known_best.lock().await; | 742 | | | 743 | 0 | match network_event { | 744 | | network_service::Event::BlockAnnounce { | 745 | 0 | chain_id, | 746 | 0 | scale_encoded_header, | 747 | | .. | 748 | 0 | } if chain_id == network_service_chain_id => match ( | 749 | 0 | *network_known_best, | 750 | 0 | header::decode( | 751 | 0 | &scale_encoded_header, | 752 | 0 | usize::from(chain_spec.block_number_bytes()), | 753 | 0 | ), | 754 | | ) { | 755 | 0 | (Some(n), Ok(header)) if n >= header.number => {} | 756 | 0 | (_, Ok(header)) => *network_known_best = Some(header.number), | 757 | 0 | (_, Err(_)) => { | 758 | 0 | // Do nothing if the block is invalid. This is just for the | 759 | 0 | // informant and not for consensus-related purposes. | 760 | 0 | } | 761 | | }, | 762 | | network_service::Event::Connected { | 763 | 0 | chain_id, | 764 | 0 | best_block_number, | 765 | | .. | 766 | 0 | } if chain_id == network_service_chain_id => match *network_known_best { | 767 | 0 | Some(n) if n >= best_block_number => {} | 768 | 0 | _ => *network_known_best = Some(best_block_number), | 769 | | }, | 770 | 0 | _ => {} |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node5start0se_0B5_ |
771 | | } |
772 | | } |
773 | 21 | } |
774 | 21 | })); |
775 | 21 | |
776 | 21 | config.log_callback.log( |
777 | 21 | LogLevel::Info, |
778 | 21 | format!( |
779 | 21 | "successful-initialization; local_peer_id={}; database_is_new={:?}; \ |
780 | 21 | finalized_block_hash={}; finalized_block_number={}", |
781 | 21 | local_peer_id, |
782 | 21 | !database_existed, |
783 | 21 | HashDisplay(&database_finalized_block_hash), |
784 | 21 | database_finalized_block_number |
785 | 21 | ), |
786 | 21 | ); |
787 | 21 | |
788 | 21 | debug_assert!(network_events_receivers.next().is_none()); |
789 | 21 | Ok(Client { |
790 | 21 | consensus_service, |
791 | 21 | relay_chain_consensus_service, |
792 | 21 | json_rpc_service, |
793 | 21 | relay_chain_json_rpc_service, |
794 | 21 | network_service, |
795 | 21 | network_known_best, |
796 | 21 | }) |
797 | 21 | } _RNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 266 | 2 | pub async fn start(mut config: Config<'_>) -> Result<Client, StartError> { | 267 | 2 | let chain_spec = { | 268 | 2 | chain_spec::ChainSpec::from_json_bytes(&config.chain.chain_spec) | 269 | 2 | .map_err(StartError::ChainSpecParse)?0 | 270 | | }; | 271 | | | 272 | | // TODO: don't just throw away the runtime | 273 | | // TODO: building the genesis chain information is pretty expensive and we throw away most of the information | 274 | 2 | let genesis_chain_information = chain_spec | 275 | 2 | .to_chain_information() | 276 | 2 | .map_err(StartError::InvalidGenesisInformation)?0 | 277 | | .0; | 278 | | | 279 | 2 | let relay_chain_spec = match &config.relay_chain { | 280 | 0 | Some(cfg) => Some( | 281 | 0 | chain_spec::ChainSpec::from_json_bytes(&cfg.chain_spec) | 282 | 0 | .map_err(StartError::RelayChainSpecParse)?, | 283 | | ), | 284 | 2 | None => None, | 285 | | }; | 286 | | | 287 | | // TODO: don't just throw away the runtime | 288 | | // TODO: building the genesis chain information is pretty expensive and we throw away most of the information | 289 | 2 | let relay_genesis_chain_information = match &relay_chain_spec { | 290 | 0 | Some(r) => Some( | 291 | 0 | r.to_chain_information() | 292 | 0 | .map_err(StartError::InvalidRelayGenesisInformation)? | 293 | | .0, | 294 | | ), | 295 | 2 | None => None, | 296 | | }; | 297 | | | 298 | | // The `protocolId` field of chain specifications is deprecated. Print a warning. | 299 | 2 | if chain_spec.protocol_id().is_some() { | 300 | 0 | config.log_callback.log( | 301 | 0 | LogLevel::Warn, | 302 | 0 | format!("chain-spec-has-protocol-id; chain={}", chain_spec.id()), | 303 | 0 | ); | 304 | 2 | } | 305 | 2 | if let Some(relay_chain_spec0 ) = &relay_chain_spec { | 306 | 0 | if relay_chain_spec.protocol_id().is_some() { | 307 | 0 | config.log_callback.log( | 308 | 0 | LogLevel::Warn, | 309 | 0 | format!( | 310 | 0 | "chain-spec-has-protocol-id; chain={}", | 311 | 0 | relay_chain_spec.id() | 312 | 0 | ), | 313 | 0 | ); | 314 | 0 | } | 315 | 2 | } | 316 | | | 317 | | // The `telemetryEndpoints` field of chain specifications isn't supported. | 318 | 2 | if chain_spec.telemetry_endpoints().count() != 0 { | 319 | 0 | config.log_callback.log( | 320 | 0 | LogLevel::Warn, | 321 | 0 | format!( | 322 | 0 | "chain-spec-has-telemetry-endpoints; chain={}", | 323 | 0 | chain_spec.id() | 324 | 0 | ), | 325 | 0 | ); | 326 | 2 | } | 327 | 2 | if let Some(relay_chain_spec0 ) = &relay_chain_spec { | 328 | 0 | if relay_chain_spec.telemetry_endpoints().count() != 0 { | 329 | 0 | config.log_callback.log( | 330 | 0 | LogLevel::Warn, | 331 | 0 | format!( | 332 | 0 | "chain-spec-has-telemetry-endpoints; chain={}", | 333 | 0 | relay_chain_spec.id() | 334 | 0 | ), | 335 | 0 | ); | 336 | 0 | } | 337 | 2 | } | 338 | | | 339 | | // Printing the SQLite version number can be useful for debugging purposes for example in case | 340 | | // a query fails. | 341 | 2 | config.log_callback.log( | 342 | 2 | LogLevel::Debug, | 343 | 2 | format!("sqlite-version; version={}", full_sqlite::sqlite_version()), | 344 | 2 | ); | 345 | | | 346 | 2 | let (database, database_existed) = { | 347 | 2 | let (db, existed) = open_database( | 348 | 2 | &chain_spec, | 349 | 2 | genesis_chain_information.as_ref(), | 350 | 2 | config.chain.sqlite_database_path, | 351 | 2 | config.chain.sqlite_cache_size, | 352 | 2 | ) | 353 | 0 | .await; | 354 | | | 355 | 2 | (Arc::new(database_thread::DatabaseThread::from(db)), existed) | 356 | | }; | 357 | | | 358 | 2 | let relay_chain_database = if let Some(relay_chain0 ) = &config.relay_chain { | 359 | | Some(Arc::new(database_thread::DatabaseThread::from( | 360 | 0 | open_database( | 361 | 0 | relay_chain_spec.as_ref().unwrap(), | 362 | 0 | relay_genesis_chain_information.as_ref().unwrap().as_ref(), | 363 | 0 | relay_chain.sqlite_database_path.clone(), | 364 | 0 | relay_chain.sqlite_cache_size, | 365 | 0 | ) | 366 | 0 | .await | 367 | | .0, | 368 | | ))) | 369 | | } else { | 370 | 2 | None | 371 | | }; | 372 | | | 373 | 2 | let database_finalized_block_hash = database | 374 | 2 | .with_database(|db| db.finalized_block_hash().unwrap()) | 375 | 2 | .await; | 376 | 2 | let database_finalized_block_number = header::decode( | 377 | 2 | &database | 378 | 2 | .with_database(move |db| { | 379 | | db.block_scale_encoded_header(&database_finalized_block_hash) | 380 | | .unwrap() | 381 | | .unwrap() | 382 | 2 | }) | 383 | 2 | .await, | 384 | 2 | chain_spec.block_number_bytes().into(), | 385 | 2 | ) | 386 | 2 | .unwrap() | 387 | 2 | .number; | 388 | 2 | | 389 | 2 | let noise_key = { | 390 | 2 | let mut noise_static_key = zeroize::Zeroizing::new([0u8; 32]); | 391 | 2 | rand::thread_rng().fill_bytes(&mut *noise_static_key); | 392 | 2 | connection::NoiseKey::new(&config.libp2p_key, &noise_static_key) | 393 | 2 | }; | 394 | 2 | zeroize::Zeroize::zeroize(&mut *config.libp2p_key); | 395 | 2 | let local_peer_id = | 396 | 2 | peer_id::PublicKey::Ed25519(*noise_key.libp2p_public_ed25519_key()).into_peer_id(); | 397 | 2 | | 398 | 2 | let genesis_block_hash = genesis_chain_information | 399 | 2 | .as_ref() | 400 | 2 | .finalized_block_header | 401 | 2 | .hash(chain_spec.block_number_bytes().into()); | 402 | | | 403 | 2 | let jaeger_service = jaeger_service::JaegerService::new(jaeger_service::Config { | 404 | 2 | tasks_executor: &mut |task| (config.tasks_executor)(task), | 405 | 2 | service_name: local_peer_id.to_string(), | 406 | 2 | jaeger_agent: config.jaeger_agent, | 407 | 2 | }) | 408 | 0 | .await | 409 | 2 | .map_err(StartError::JaegerInit)?0 ; | 410 | | | 411 | 2 | let (network_service, network_service_chain_ids, network_events_receivers) = | 412 | | network_service::NetworkService::new(network_service::Config { | 413 | 2 | listen_addresses: config.listen_addresses, | 414 | 2 | num_events_receivers: 2 + if relay_chain_database.is_some() { 10 } else { 0 }, | 415 | | chains: iter::once(network_service::ChainConfig { | 416 | 2 | log_name: chain_spec.id().to_owned(), | 417 | 2 | fork_id: chain_spec.fork_id().map(|n| n.to_owned()), | 418 | 2 | block_number_bytes: usize::from(chain_spec.block_number_bytes()), | 419 | 2 | database: database.clone(), | 420 | 0 | grandpa_protocol_finalized_block_height: if matches!( | 421 | 2 | genesis_chain_information.as_ref().finality, | 422 | | chain::chain_information::ChainInformationFinalityRef::Grandpa { .. } | 423 | | ) { | 424 | | Some({ | 425 | 2 | let block_number_bytes = chain_spec.block_number_bytes(); | 426 | 2 | database | 427 | 2 | .with_database(move |database| { | 428 | | let hash = database.finalized_block_hash().unwrap(); | 429 | | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); | 430 | | header::decode(&header, block_number_bytes.into(),).unwrap().number | 431 | 2 | }) | 432 | 2 | .await | 433 | | }) | 434 | | } else { | 435 | 0 | None | 436 | | }, | 437 | 2 | genesis_block_hash, | 438 | 2 | best_block: { | 439 | 2 | let block_number_bytes = chain_spec.block_number_bytes(); | 440 | 2 | database | 441 | 2 | .with_database(move |database| { | 442 | | let hash = database.finalized_block_hash().unwrap(); | 443 | | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); | 444 | | let number = header::decode(&header, block_number_bytes.into(),).unwrap().number; | 445 | | (number, hash) | 446 | 2 | }) | 447 | 2 | .await | 448 | | }, | 449 | | max_in_peers: 25, | 450 | | max_slots: 15, | 451 | | bootstrap_nodes: { | 452 | 2 | let mut list = Vec::with_capacity( | 453 | 2 | chain_spec.boot_nodes().len() + config.chain.additional_bootnodes.len(), | 454 | 2 | ); | 455 | | | 456 | 2 | for node0 in chain_spec.boot_nodes() { | 457 | 0 | match node { | 458 | 0 | chain_spec::Bootnode::UnrecognizedFormat(raw) => { | 459 | 0 | config.log_callback.log( | 460 | 0 | LogLevel::Warn, | 461 | 0 | format!("bootnode-unrecognized-addr; value={:?}", raw), | 462 | 0 | ); | 463 | 0 | } | 464 | 0 | chain_spec::Bootnode::Parsed { multiaddr, peer_id } => { | 465 | 0 | let multiaddr: multiaddr::Multiaddr = match multiaddr.parse() { | 466 | 0 | Ok(a) => a, | 467 | | Err(_) => { | 468 | 0 | config.log_callback.log( | 469 | 0 | LogLevel::Warn, | 470 | 0 | format!("bootnode-unrecognized-addr; value={:?}", multiaddr), | 471 | 0 | ); | 472 | 0 | continue; | 473 | | }, | 474 | | }; | 475 | 0 | let peer_id = PeerId::from_bytes(peer_id.to_vec()).unwrap(); | 476 | 0 | list.push((peer_id, multiaddr)); | 477 | | } | 478 | | } | 479 | | } | 480 | | | 481 | 2 | list.extend(config.chain.additional_bootnodes); | 482 | 2 | list | 483 | | }, | 484 | | }) | 485 | | .chain( | 486 | 2 | if let Some(relay_chains_specs0 ) = &relay_chain_spec { | 487 | | Some(network_service::ChainConfig { | 488 | 0 | log_name: relay_chains_specs.id().to_owned(), | 489 | 0 | fork_id: relay_chains_specs.fork_id().map(|n| n.to_owned()), | 490 | 0 | block_number_bytes: usize::from(relay_chains_specs.block_number_bytes()), | 491 | 0 | database: relay_chain_database.clone().unwrap(), | 492 | 0 | grandpa_protocol_finalized_block_height: if matches!( | 493 | 0 | genesis_chain_information.as_ref().finality, | 494 | | chain::chain_information::ChainInformationFinalityRef::Grandpa { .. } | 495 | | ) { | 496 | 0 | Some(relay_chain_database | 497 | 0 | .as_ref() | 498 | 0 | .unwrap() | 499 | 0 | .with_database({ | 500 | 0 | let block_number_bytes = chain_spec.block_number_bytes(); | 501 | 0 | move |db| { | 502 | | let hash = db.finalized_block_hash().unwrap(); | 503 | | let header = db.block_scale_encoded_header(&hash).unwrap().unwrap(); | 504 | | header::decode(&header, block_number_bytes.into()).unwrap().number | 505 | 0 | } | 506 | 0 | }) | 507 | 0 | .await) | 508 | | } else { | 509 | 0 | None | 510 | | }, | 511 | 0 | genesis_block_hash: relay_genesis_chain_information | 512 | 0 | .as_ref() | 513 | 0 | .unwrap() | 514 | 0 | .as_ref().finalized_block_header | 515 | 0 | .hash(chain_spec.block_number_bytes().into(),), | 516 | 0 | best_block: relay_chain_database | 517 | 0 | .as_ref() | 518 | 0 | .unwrap() | 519 | 0 | .with_database({ | 520 | 0 | let block_number_bytes = chain_spec.block_number_bytes(); | 521 | 0 | move |db| { | 522 | | let hash = db.finalized_block_hash().unwrap(); | 523 | | let header = db.block_scale_encoded_header(&hash).unwrap().unwrap(); | 524 | | let number = header::decode(&header, block_number_bytes.into()).unwrap().number; | 525 | | (number, hash) | 526 | 0 | } | 527 | 0 | }) | 528 | 0 | .await, | 529 | | max_in_peers: 25, | 530 | | max_slots: 15, | 531 | | bootstrap_nodes: { | 532 | 0 | let mut list = | 533 | 0 | Vec::with_capacity(relay_chains_specs.boot_nodes().len()); | 534 | 0 | for node in relay_chains_specs.boot_nodes() { | 535 | 0 | match node { | 536 | 0 | chain_spec::Bootnode::UnrecognizedFormat(raw) => { | 537 | 0 | config.log_callback.log( | 538 | 0 | LogLevel::Warn, | 539 | 0 | format!("relay-chain-bootnode-unrecognized-addr; value={:?}", raw), | 540 | 0 | ); | 541 | 0 | } | 542 | 0 | chain_spec::Bootnode::Parsed { multiaddr, peer_id } => { | 543 | 0 | let multiaddr: multiaddr::Multiaddr = match multiaddr.parse() { | 544 | 0 | Ok(a) => a, | 545 | | Err(_) => { | 546 | 0 | config.log_callback.log( | 547 | 0 | LogLevel::Warn, | 548 | 0 | format!("relay-chain-bootnode-unrecognized-addr; value={:?}", multiaddr), | 549 | 0 | ); | 550 | 0 | continue; | 551 | | } | 552 | | }; | 553 | 0 | let peer_id = PeerId::from_bytes(peer_id.to_vec()).unwrap(); | 554 | 0 | list.push((peer_id, multiaddr)); | 555 | | } | 556 | | } | 557 | | } | 558 | 0 | list | 559 | | }, | 560 | | }) | 561 | | } else { | 562 | 2 | None | 563 | | } | 564 | 2 | .into_iter(), | 565 | 2 | ) | 566 | 2 | .collect(), | 567 | 2 | identify_agent_version: concat!(env!("CARGO_PKG_NAME"), " ", env!("CARGO_PKG_VERSION")).to_owned(), | 568 | 2 | noise_key, | 569 | 2 | tasks_executor: { | 570 | 2 | let executor = config.tasks_executor.clone(); | 571 | 2 | Box::new(move |task| executor(task)) | 572 | 2 | }, | 573 | 2 | log_callback: config.log_callback.clone(), | 574 | 2 | jaeger_service: jaeger_service.clone(), | 575 | | }) | 576 | 0 | .await | 577 | 2 | .map_err(StartError::NetworkInit)?0 ; | 578 | | | 579 | 2 | let mut network_events_receivers = network_events_receivers.into_iter(); | 580 | | | 581 | 2 | let keystore = Arc::new({ | 582 | 2 | let mut keystore = keystore::Keystore::new(config.chain.keystore_path, rand::random()) | 583 | 0 | .await | 584 | 2 | .map_err(StartError::KeystoreInit)?0 ; | 585 | 2 | for mut private_key0 in config.chain.keystore_memory { | 586 | 0 | keystore.insert_sr25519_memory(keystore::KeyNamespace::all(), &private_key); | 587 | 0 | zeroize::Zeroize::zeroize(&mut *private_key); | 588 | 0 | } | 589 | 2 | keystore | 590 | | }); | 591 | | | 592 | 2 | let consensus_service = consensus_service::ConsensusService::new(consensus_service::Config { | 593 | 2 | tasks_executor: { | 594 | 2 | let executor = config.tasks_executor.clone(); | 595 | 2 | Box::new(move |task| executor(task)) | 596 | 2 | }, | 597 | 2 | log_callback: config.log_callback.clone(), | 598 | 2 | genesis_block_hash, | 599 | 2 | network_events_receiver: network_events_receivers.next().unwrap(), | 600 | 2 | network_service: (network_service.clone(), network_service_chain_ids[0]), | 601 | 2 | database: database.clone(), | 602 | 2 | block_number_bytes: usize::from(chain_spec.block_number_bytes()), | 603 | 2 | keystore, | 604 | 2 | jaeger_service: jaeger_service.clone(), | 605 | 2 | slot_duration_author_ratio: 43691_u16, | 606 | 2 | }) | 607 | 2 | .await | 608 | 2 | .map_err(StartError::ConsensusServiceInit)?0 ; | 609 | | | 610 | 2 | let relay_chain_consensus_service = if let Some(relay_chain_database0 ) = &relay_chain_database { | 611 | | Some( | 612 | | consensus_service::ConsensusService::new(consensus_service::Config { | 613 | | tasks_executor: { | 614 | 0 | let executor = config.tasks_executor.clone(); | 615 | 0 | Box::new(move |task| executor(task)) | 616 | 0 | }, | 617 | 0 | log_callback: config.log_callback.clone(), | 618 | 0 | genesis_block_hash: relay_genesis_chain_information | 619 | 0 | .as_ref() | 620 | 0 | .unwrap() | 621 | 0 | .as_ref() | 622 | 0 | .finalized_block_header | 623 | 0 | .hash(usize::from( | 624 | 0 | relay_chain_spec.as_ref().unwrap().block_number_bytes(), | 625 | 0 | )), | 626 | 0 | network_events_receiver: network_events_receivers.next().unwrap(), | 627 | 0 | network_service: (network_service.clone(), network_service_chain_ids[1]), | 628 | 0 | database: relay_chain_database.clone(), | 629 | 0 | block_number_bytes: usize::from( | 630 | 0 | relay_chain_spec.as_ref().unwrap().block_number_bytes(), | 631 | 0 | ), | 632 | | keystore: Arc::new({ | 633 | 0 | let mut keystore = keystore::Keystore::new( | 634 | 0 | config.relay_chain.as_ref().unwrap().keystore_path.clone(), | 635 | 0 | rand::random(), | 636 | 0 | ) | 637 | 0 | .await | 638 | 0 | .map_err(StartError::RelayChainKeystoreInit)?; | 639 | 0 | for mut private_key in | 640 | 0 | mem::take(&mut config.relay_chain.as_mut().unwrap().keystore_memory) | 641 | 0 | { | 642 | 0 | keystore.insert_sr25519_memory(keystore::KeyNamespace::all(), &private_key); | 643 | 0 | zeroize::Zeroize::zeroize(&mut *private_key); | 644 | 0 | } | 645 | 0 | keystore | 646 | 0 | }), | 647 | 0 | jaeger_service, // TODO: consider passing a different jaeger service with a different service name | 648 | | slot_duration_author_ratio: 43691_u16, | 649 | | }) | 650 | 0 | .await | 651 | 0 | .map_err(StartError::RelayChainConsensusServiceInit)?, | 652 | | ) | 653 | | } else { | 654 | 2 | None | 655 | | }; | 656 | | | 657 | | // Start the JSON-RPC service. | 658 | | // It only needs to be kept alive in order to function. | 659 | | // | 660 | | // Note that initialization can fail if, for example, the port is already occupied. It is | 661 | | // preferable to fail to start the node altogether rather than make the user believe that they | 662 | | // are connected to the JSON-RPC endpoint of the node while they are in reality connected to | 663 | | // something else. | 664 | 2 | let json_rpc_service = json_rpc_service::JsonRpcService::new(json_rpc_service::Config { | 665 | 2 | tasks_executor: config.tasks_executor.clone(), | 666 | 2 | log_callback: config.log_callback.clone(), | 667 | 2 | database, | 668 | 2 | consensus_service: consensus_service.clone(), | 669 | 2 | network_service: (network_service.clone(), network_service_chain_ids[0]), | 670 | 2 | bind_address: config.chain.json_rpc_listen.as_ref().map(|cfg| cfg.address), | 671 | 2 | max_parallel_requests: 32, | 672 | 2 | max_json_rpc_clients: config | 673 | 2 | .chain | 674 | 2 | .json_rpc_listen | 675 | 2 | .map_or(0, |cfg| cfg.max_json_rpc_clients), | 676 | 2 | chain_name: chain_spec.name().to_owned(), | 677 | 2 | chain_type: chain_spec.chain_type().to_owned(), | 678 | 2 | chain_properties_json: chain_spec.properties().to_owned(), | 679 | 2 | chain_is_live: chain_spec.has_live_network(), | 680 | 2 | genesis_block_hash: genesis_chain_information | 681 | 2 | .as_ref() | 682 | 2 | .finalized_block_header | 683 | 2 | .hash(usize::from(chain_spec.block_number_bytes())), | 684 | 2 | }) | 685 | 0 | .await | 686 | 2 | .map_err(StartError::JsonRpcServiceInit)?0 ; | 687 | | | 688 | | // Start the JSON-RPC service of the relay chain. | 689 | | // See remarks above. | 690 | 2 | let relay_chain_json_rpc_service = if let Some(relay_chain_cfg0 ) = config.relay_chain { | 691 | 0 | let relay_chain_spec = relay_chain_spec.as_ref().unwrap(); | 692 | 0 | Some( | 693 | 0 | json_rpc_service::JsonRpcService::new(json_rpc_service::Config { | 694 | 0 | tasks_executor: config.tasks_executor.clone(), | 695 | 0 | log_callback: config.log_callback.clone(), | 696 | 0 | database: relay_chain_database.clone().unwrap(), | 697 | 0 | consensus_service: relay_chain_consensus_service.clone().unwrap(), | 698 | 0 | network_service: (network_service.clone(), network_service_chain_ids[1]), | 699 | 0 | bind_address: relay_chain_cfg | 700 | 0 | .json_rpc_listen | 701 | 0 | .as_ref() | 702 | 0 | .map(|cfg| cfg.address), | 703 | 0 | max_parallel_requests: 32, | 704 | 0 | max_json_rpc_clients: relay_chain_cfg | 705 | 0 | .json_rpc_listen | 706 | 0 | .map_or(0, |cfg| cfg.max_json_rpc_clients), | 707 | 0 | chain_name: relay_chain_spec.name().to_owned(), | 708 | 0 | chain_type: relay_chain_spec.chain_type().to_owned(), | 709 | 0 | chain_properties_json: relay_chain_spec.properties().to_owned(), | 710 | 0 | chain_is_live: relay_chain_spec.has_live_network(), | 711 | 0 | genesis_block_hash: relay_genesis_chain_information | 712 | 0 | .as_ref() | 713 | 0 | .unwrap() | 714 | 0 | .as_ref() | 715 | 0 | .finalized_block_header | 716 | 0 | .hash(usize::from(relay_chain_spec.block_number_bytes())), | 717 | 0 | }) | 718 | 0 | .await | 719 | 0 | .map_err(StartError::JsonRpcServiceInit)?, | 720 | | ) | 721 | | } else { | 722 | 2 | None | 723 | | }; | 724 | | | 725 | | // Spawn the task printing the informant. | 726 | | // This is not just a dummy task that just prints on the output, but is actually the main | 727 | | // task that holds everything else alive. Without it, all the services that we have created | 728 | | // above would be cleanly dropped and nothing would happen. | 729 | | // For this reason, it must be spawned even if no informant is started, in which case we simply | 730 | | // inhibit the printing. | 731 | 2 | let network_known_best = Arc::new(Mutex::new(None)); | 732 | 2 | (config.tasks_executor)(Box::pin({ | 733 | 2 | let mut main_network_events_receiver = network_events_receivers.next().unwrap(); | 734 | 2 | let network_service_chain_id = network_service_chain_ids[0]; | 735 | 2 | let network_known_best = network_known_best.clone(); | 736 | 2 | | 737 | 2 | // TODO: shut down this task if the client stops? | 738 | 2 | async move { | 739 | | loop { | 740 | | let network_event = main_network_events_receiver.next().await.unwrap(); | 741 | | let mut network_known_best = network_known_best.lock().await; | 742 | | | 743 | | match network_event { | 744 | | network_service::Event::BlockAnnounce { | 745 | | chain_id, | 746 | | scale_encoded_header, | 747 | | .. | 748 | | } if chain_id == network_service_chain_id => match ( | 749 | | *network_known_best, | 750 | | header::decode( | 751 | | &scale_encoded_header, | 752 | | usize::from(chain_spec.block_number_bytes()), | 753 | | ), | 754 | | ) { | 755 | | (Some(n), Ok(header)) if n >= header.number => {} | 756 | | (_, Ok(header)) => *network_known_best = Some(header.number), | 757 | | (_, Err(_)) => { | 758 | | // Do nothing if the block is invalid. This is just for the | 759 | | // informant and not for consensus-related purposes. | 760 | | } | 761 | | }, | 762 | | network_service::Event::Connected { | 763 | | chain_id, | 764 | | best_block_number, | 765 | | .. | 766 | | } if chain_id == network_service_chain_id => match *network_known_best { | 767 | | Some(n) if n >= best_block_number => {} | 768 | | _ => *network_known_best = Some(best_block_number), | 769 | | }, | 770 | | _ => {} | 771 | | } | 772 | | } | 773 | 2 | } | 774 | 2 | })); | 775 | 2 | | 776 | 2 | config.log_callback.log( | 777 | 2 | LogLevel::Info, | 778 | 2 | format!( | 779 | 2 | "successful-initialization; local_peer_id={}; database_is_new={:?}; \ | 780 | 2 | finalized_block_hash={}; finalized_block_number={}", | 781 | 2 | local_peer_id, | 782 | 2 | !database_existed, | 783 | 2 | HashDisplay(&database_finalized_block_hash), | 784 | 2 | database_finalized_block_number | 785 | 2 | ), | 786 | 2 | ); | 787 | 2 | | 788 | 2 | debug_assert!(network_events_receivers.next().is_none()); | 789 | 2 | Ok(Client { | 790 | 2 | consensus_service, | 791 | 2 | relay_chain_consensus_service, | 792 | 2 | json_rpc_service, | 793 | 2 | relay_chain_json_rpc_service, | 794 | 2 | network_service, | 795 | 2 | network_known_best, | 796 | 2 | }) | 797 | 2 | } |
Unexecuted instantiation: _RNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0B3_ Unexecuted instantiation: _RNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0CscDgN54JpMGG_6author _RNCNvCsiUjFBJteJ7x_17smoldot_full_node5start0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 266 | 19 | pub async fn start(mut config: Config<'_>) -> Result<Client, StartError> { | 267 | 19 | let chain_spec = { | 268 | 19 | chain_spec::ChainSpec::from_json_bytes(&config.chain.chain_spec) | 269 | 19 | .map_err(StartError::ChainSpecParse)?0 | 270 | | }; | 271 | | | 272 | | // TODO: don't just throw away the runtime | 273 | | // TODO: building the genesis chain information is pretty expensive and we throw away most of the information | 274 | 19 | let genesis_chain_information = chain_spec | 275 | 19 | .to_chain_information() | 276 | 19 | .map_err(StartError::InvalidGenesisInformation)?0 | 277 | | .0; | 278 | | | 279 | 19 | let relay_chain_spec = match &config.relay_chain { | 280 | 0 | Some(cfg) => Some( | 281 | 0 | chain_spec::ChainSpec::from_json_bytes(&cfg.chain_spec) | 282 | 0 | .map_err(StartError::RelayChainSpecParse)?, | 283 | | ), | 284 | 19 | None => None, | 285 | | }; | 286 | | | 287 | | // TODO: don't just throw away the runtime | 288 | | // TODO: building the genesis chain information is pretty expensive and we throw away most of the information | 289 | 19 | let relay_genesis_chain_information = match &relay_chain_spec { | 290 | 0 | Some(r) => Some( | 291 | 0 | r.to_chain_information() | 292 | 0 | .map_err(StartError::InvalidRelayGenesisInformation)? | 293 | | .0, | 294 | | ), | 295 | 19 | None => None, | 296 | | }; | 297 | | | 298 | | // The `protocolId` field of chain specifications is deprecated. Print a warning. | 299 | 19 | if chain_spec.protocol_id().is_some() { | 300 | 0 | config.log_callback.log( | 301 | 0 | LogLevel::Warn, | 302 | 0 | format!("chain-spec-has-protocol-id; chain={}", chain_spec.id()), | 303 | 0 | ); | 304 | 19 | } | 305 | 19 | if let Some(relay_chain_spec0 ) = &relay_chain_spec { | 306 | 0 | if relay_chain_spec.protocol_id().is_some() { | 307 | 0 | config.log_callback.log( | 308 | 0 | LogLevel::Warn, | 309 | 0 | format!( | 310 | 0 | "chain-spec-has-protocol-id; chain={}", | 311 | 0 | relay_chain_spec.id() | 312 | 0 | ), | 313 | 0 | ); | 314 | 0 | } | 315 | 19 | } | 316 | | | 317 | | // The `telemetryEndpoints` field of chain specifications isn't supported. | 318 | 19 | if chain_spec.telemetry_endpoints().count() != 0 { | 319 | 0 | config.log_callback.log( | 320 | 0 | LogLevel::Warn, | 321 | 0 | format!( | 322 | 0 | "chain-spec-has-telemetry-endpoints; chain={}", | 323 | 0 | chain_spec.id() | 324 | 0 | ), | 325 | 0 | ); | 326 | 19 | } | 327 | 19 | if let Some(relay_chain_spec0 ) = &relay_chain_spec { | 328 | 0 | if relay_chain_spec.telemetry_endpoints().count() != 0 { | 329 | 0 | config.log_callback.log( | 330 | 0 | LogLevel::Warn, | 331 | 0 | format!( | 332 | 0 | "chain-spec-has-telemetry-endpoints; chain={}", | 333 | 0 | relay_chain_spec.id() | 334 | 0 | ), | 335 | 0 | ); | 336 | 0 | } | 337 | 19 | } | 338 | | | 339 | | // Printing the SQLite version number can be useful for debugging purposes for example in case | 340 | | // a query fails. | 341 | 19 | config.log_callback.log( | 342 | 19 | LogLevel::Debug, | 343 | 19 | format!("sqlite-version; version={}", full_sqlite::sqlite_version()), | 344 | 19 | ); | 345 | | | 346 | 19 | let (database, database_existed) = { | 347 | 19 | let (db, existed) = open_database( | 348 | 19 | &chain_spec, | 349 | 19 | genesis_chain_information.as_ref(), | 350 | 19 | config.chain.sqlite_database_path, | 351 | 19 | config.chain.sqlite_cache_size, | 352 | 19 | ) | 353 | 0 | .await; | 354 | | | 355 | 19 | (Arc::new(database_thread::DatabaseThread::from(db)), existed) | 356 | | }; | 357 | | | 358 | 19 | let relay_chain_database = if let Some(relay_chain0 ) = &config.relay_chain { | 359 | | Some(Arc::new(database_thread::DatabaseThread::from( | 360 | 0 | open_database( | 361 | 0 | relay_chain_spec.as_ref().unwrap(), | 362 | 0 | relay_genesis_chain_information.as_ref().unwrap().as_ref(), | 363 | 0 | relay_chain.sqlite_database_path.clone(), | 364 | 0 | relay_chain.sqlite_cache_size, | 365 | 0 | ) | 366 | 0 | .await | 367 | | .0, | 368 | | ))) | 369 | | } else { | 370 | 19 | None | 371 | | }; | 372 | | | 373 | 19 | let database_finalized_block_hash = database | 374 | 19 | .with_database(|db| db.finalized_block_hash().unwrap()) | 375 | 19 | .await; | 376 | 19 | let database_finalized_block_number = header::decode( | 377 | 19 | &database | 378 | 19 | .with_database(move |db| { | 379 | | db.block_scale_encoded_header(&database_finalized_block_hash) | 380 | | .unwrap() | 381 | | .unwrap() | 382 | 19 | }) | 383 | 19 | .await, | 384 | 19 | chain_spec.block_number_bytes().into(), | 385 | 19 | ) | 386 | 19 | .unwrap() | 387 | 19 | .number; | 388 | 19 | | 389 | 19 | let noise_key = { | 390 | 19 | let mut noise_static_key = zeroize::Zeroizing::new([0u8; 32]); | 391 | 19 | rand::thread_rng().fill_bytes(&mut *noise_static_key); | 392 | 19 | connection::NoiseKey::new(&config.libp2p_key, &noise_static_key) | 393 | 19 | }; | 394 | 19 | zeroize::Zeroize::zeroize(&mut *config.libp2p_key); | 395 | 19 | let local_peer_id = | 396 | 19 | peer_id::PublicKey::Ed25519(*noise_key.libp2p_public_ed25519_key()).into_peer_id(); | 397 | 19 | | 398 | 19 | let genesis_block_hash = genesis_chain_information | 399 | 19 | .as_ref() | 400 | 19 | .finalized_block_header | 401 | 19 | .hash(chain_spec.block_number_bytes().into()); | 402 | | | 403 | 19 | let jaeger_service = jaeger_service::JaegerService::new(jaeger_service::Config { | 404 | 19 | tasks_executor: &mut |task| (config.tasks_executor)(task), | 405 | 19 | service_name: local_peer_id.to_string(), | 406 | 19 | jaeger_agent: config.jaeger_agent, | 407 | 19 | }) | 408 | 0 | .await | 409 | 19 | .map_err(StartError::JaegerInit)?0 ; | 410 | | | 411 | 19 | let (network_service, network_service_chain_ids, network_events_receivers) = | 412 | | network_service::NetworkService::new(network_service::Config { | 413 | 19 | listen_addresses: config.listen_addresses, | 414 | 19 | num_events_receivers: 2 + if relay_chain_database.is_some() { 10 } else { 0 }, | 415 | | chains: iter::once(network_service::ChainConfig { | 416 | 19 | log_name: chain_spec.id().to_owned(), | 417 | 19 | fork_id: chain_spec.fork_id().map(|n| n.to_owned()), | 418 | 19 | block_number_bytes: usize::from(chain_spec.block_number_bytes()), | 419 | 19 | database: database.clone(), | 420 | 0 | grandpa_protocol_finalized_block_height: if matches!( | 421 | 19 | genesis_chain_information.as_ref().finality, | 422 | | chain::chain_information::ChainInformationFinalityRef::Grandpa { .. } | 423 | | ) { | 424 | | Some({ | 425 | 19 | let block_number_bytes = chain_spec.block_number_bytes(); | 426 | 19 | database | 427 | 19 | .with_database(move |database| { | 428 | | let hash = database.finalized_block_hash().unwrap(); | 429 | | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); | 430 | | header::decode(&header, block_number_bytes.into(),).unwrap().number | 431 | 19 | }) | 432 | 19 | .await | 433 | | }) | 434 | | } else { | 435 | 0 | None | 436 | | }, | 437 | 19 | genesis_block_hash, | 438 | 19 | best_block: { | 439 | 19 | let block_number_bytes = chain_spec.block_number_bytes(); | 440 | 19 | database | 441 | 19 | .with_database(move |database| { | 442 | | let hash = database.finalized_block_hash().unwrap(); | 443 | | let header = database.block_scale_encoded_header(&hash).unwrap().unwrap(); | 444 | | let number = header::decode(&header, block_number_bytes.into(),).unwrap().number; | 445 | | (number, hash) | 446 | 19 | }) | 447 | 19 | .await | 448 | | }, | 449 | | max_in_peers: 25, | 450 | | max_slots: 15, | 451 | | bootstrap_nodes: { | 452 | 19 | let mut list = Vec::with_capacity( | 453 | 19 | chain_spec.boot_nodes().len() + config.chain.additional_bootnodes.len(), | 454 | 19 | ); | 455 | | | 456 | 19 | for node0 in chain_spec.boot_nodes() { | 457 | 0 | match node { | 458 | 0 | chain_spec::Bootnode::UnrecognizedFormat(raw) => { | 459 | 0 | config.log_callback.log( | 460 | 0 | LogLevel::Warn, | 461 | 0 | format!("bootnode-unrecognized-addr; value={:?}", raw), | 462 | 0 | ); | 463 | 0 | } | 464 | 0 | chain_spec::Bootnode::Parsed { multiaddr, peer_id } => { | 465 | 0 | let multiaddr: multiaddr::Multiaddr = match multiaddr.parse() { | 466 | 0 | Ok(a) => a, | 467 | | Err(_) => { | 468 | 0 | config.log_callback.log( | 469 | 0 | LogLevel::Warn, | 470 | 0 | format!("bootnode-unrecognized-addr; value={:?}", multiaddr), | 471 | 0 | ); | 472 | 0 | continue; | 473 | | }, | 474 | | }; | 475 | 0 | let peer_id = PeerId::from_bytes(peer_id.to_vec()).unwrap(); | 476 | 0 | list.push((peer_id, multiaddr)); | 477 | | } | 478 | | } | 479 | | } | 480 | | | 481 | 19 | list.extend(config.chain.additional_bootnodes); | 482 | 19 | list | 483 | | }, | 484 | | }) | 485 | | .chain( | 486 | 19 | if let Some(relay_chains_specs0 ) = &relay_chain_spec { | 487 | | Some(network_service::ChainConfig { | 488 | 0 | log_name: relay_chains_specs.id().to_owned(), | 489 | 0 | fork_id: relay_chains_specs.fork_id().map(|n| n.to_owned()), | 490 | 0 | block_number_bytes: usize::from(relay_chains_specs.block_number_bytes()), | 491 | 0 | database: relay_chain_database.clone().unwrap(), | 492 | 0 | grandpa_protocol_finalized_block_height: if matches!( | 493 | 0 | genesis_chain_information.as_ref().finality, | 494 | | chain::chain_information::ChainInformationFinalityRef::Grandpa { .. } | 495 | | ) { | 496 | 0 | Some(relay_chain_database | 497 | 0 | .as_ref() | 498 | 0 | .unwrap() | 499 | 0 | .with_database({ | 500 | 0 | let block_number_bytes = chain_spec.block_number_bytes(); | 501 | 0 | move |db| { | 502 | | let hash = db.finalized_block_hash().unwrap(); | 503 | | let header = db.block_scale_encoded_header(&hash).unwrap().unwrap(); | 504 | | header::decode(&header, block_number_bytes.into()).unwrap().number | 505 | 0 | } | 506 | 0 | }) | 507 | 0 | .await) | 508 | | } else { | 509 | 0 | None | 510 | | }, | 511 | 0 | genesis_block_hash: relay_genesis_chain_information | 512 | 0 | .as_ref() | 513 | 0 | .unwrap() | 514 | 0 | .as_ref().finalized_block_header | 515 | 0 | .hash(chain_spec.block_number_bytes().into(),), | 516 | 0 | best_block: relay_chain_database | 517 | 0 | .as_ref() | 518 | 0 | .unwrap() | 519 | 0 | .with_database({ | 520 | 0 | let block_number_bytes = chain_spec.block_number_bytes(); | 521 | 0 | move |db| { | 522 | | let hash = db.finalized_block_hash().unwrap(); | 523 | | let header = db.block_scale_encoded_header(&hash).unwrap().unwrap(); | 524 | | let number = header::decode(&header, block_number_bytes.into()).unwrap().number; | 525 | | (number, hash) | 526 | 0 | } | 527 | 0 | }) | 528 | 0 | .await, | 529 | | max_in_peers: 25, | 530 | | max_slots: 15, | 531 | | bootstrap_nodes: { | 532 | 0 | let mut list = | 533 | 0 | Vec::with_capacity(relay_chains_specs.boot_nodes().len()); | 534 | 0 | for node in relay_chains_specs.boot_nodes() { | 535 | 0 | match node { | 536 | 0 | chain_spec::Bootnode::UnrecognizedFormat(raw) => { | 537 | 0 | config.log_callback.log( | 538 | 0 | LogLevel::Warn, | 539 | 0 | format!("relay-chain-bootnode-unrecognized-addr; value={:?}", raw), | 540 | 0 | ); | 541 | 0 | } | 542 | 0 | chain_spec::Bootnode::Parsed { multiaddr, peer_id } => { | 543 | 0 | let multiaddr: multiaddr::Multiaddr = match multiaddr.parse() { | 544 | 0 | Ok(a) => a, | 545 | | Err(_) => { | 546 | 0 | config.log_callback.log( | 547 | 0 | LogLevel::Warn, | 548 | 0 | format!("relay-chain-bootnode-unrecognized-addr; value={:?}", multiaddr), | 549 | 0 | ); | 550 | 0 | continue; | 551 | | } | 552 | | }; | 553 | 0 | let peer_id = PeerId::from_bytes(peer_id.to_vec()).unwrap(); | 554 | 0 | list.push((peer_id, multiaddr)); | 555 | | } | 556 | | } | 557 | | } | 558 | 0 | list | 559 | | }, | 560 | | }) | 561 | | } else { | 562 | 19 | None | 563 | | } | 564 | 19 | .into_iter(), | 565 | 19 | ) | 566 | 19 | .collect(), | 567 | 19 | identify_agent_version: concat!(env!("CARGO_PKG_NAME"), " ", env!("CARGO_PKG_VERSION")).to_owned(), | 568 | 19 | noise_key, | 569 | 19 | tasks_executor: { | 570 | 19 | let executor = config.tasks_executor.clone(); | 571 | 19 | Box::new(move |task| executor(task)) | 572 | 19 | }, | 573 | 19 | log_callback: config.log_callback.clone(), | 574 | 19 | jaeger_service: jaeger_service.clone(), | 575 | | }) | 576 | 0 | .await | 577 | 19 | .map_err(StartError::NetworkInit)?0 ; | 578 | | | 579 | 19 | let mut network_events_receivers = network_events_receivers.into_iter(); | 580 | | | 581 | 19 | let keystore = Arc::new({ | 582 | 19 | let mut keystore = keystore::Keystore::new(config.chain.keystore_path, rand::random()) | 583 | 0 | .await | 584 | 19 | .map_err(StartError::KeystoreInit)?0 ; | 585 | 19 | for mut private_key0 in config.chain.keystore_memory { | 586 | 0 | keystore.insert_sr25519_memory(keystore::KeyNamespace::all(), &private_key); | 587 | 0 | zeroize::Zeroize::zeroize(&mut *private_key); | 588 | 0 | } | 589 | 19 | keystore | 590 | | }); | 591 | | | 592 | 19 | let consensus_service = consensus_service::ConsensusService::new(consensus_service::Config { | 593 | 19 | tasks_executor: { | 594 | 19 | let executor = config.tasks_executor.clone(); | 595 | 19 | Box::new(move |task| executor(task)) | 596 | 19 | }, | 597 | 19 | log_callback: config.log_callback.clone(), | 598 | 19 | genesis_block_hash, | 599 | 19 | network_events_receiver: network_events_receivers.next().unwrap(), | 600 | 19 | network_service: (network_service.clone(), network_service_chain_ids[0]), | 601 | 19 | database: database.clone(), | 602 | 19 | block_number_bytes: usize::from(chain_spec.block_number_bytes()), | 603 | 19 | keystore, | 604 | 19 | jaeger_service: jaeger_service.clone(), | 605 | 19 | slot_duration_author_ratio: 43691_u16, | 606 | 19 | }) | 607 | 19 | .await | 608 | 19 | .map_err(StartError::ConsensusServiceInit)?0 ; | 609 | | | 610 | 19 | let relay_chain_consensus_service = if let Some(relay_chain_database0 ) = &relay_chain_database { | 611 | | Some( | 612 | | consensus_service::ConsensusService::new(consensus_service::Config { | 613 | | tasks_executor: { | 614 | 0 | let executor = config.tasks_executor.clone(); | 615 | 0 | Box::new(move |task| executor(task)) | 616 | 0 | }, | 617 | 0 | log_callback: config.log_callback.clone(), | 618 | 0 | genesis_block_hash: relay_genesis_chain_information | 619 | 0 | .as_ref() | 620 | 0 | .unwrap() | 621 | 0 | .as_ref() | 622 | 0 | .finalized_block_header | 623 | 0 | .hash(usize::from( | 624 | 0 | relay_chain_spec.as_ref().unwrap().block_number_bytes(), | 625 | 0 | )), | 626 | 0 | network_events_receiver: network_events_receivers.next().unwrap(), | 627 | 0 | network_service: (network_service.clone(), network_service_chain_ids[1]), | 628 | 0 | database: relay_chain_database.clone(), | 629 | 0 | block_number_bytes: usize::from( | 630 | 0 | relay_chain_spec.as_ref().unwrap().block_number_bytes(), | 631 | 0 | ), | 632 | | keystore: Arc::new({ | 633 | 0 | let mut keystore = keystore::Keystore::new( | 634 | 0 | config.relay_chain.as_ref().unwrap().keystore_path.clone(), | 635 | 0 | rand::random(), | 636 | 0 | ) | 637 | 0 | .await | 638 | 0 | .map_err(StartError::RelayChainKeystoreInit)?; | 639 | 0 | for mut private_key in | 640 | 0 | mem::take(&mut config.relay_chain.as_mut().unwrap().keystore_memory) | 641 | 0 | { | 642 | 0 | keystore.insert_sr25519_memory(keystore::KeyNamespace::all(), &private_key); | 643 | 0 | zeroize::Zeroize::zeroize(&mut *private_key); | 644 | 0 | } | 645 | 0 | keystore | 646 | 0 | }), | 647 | 0 | jaeger_service, // TODO: consider passing a different jaeger service with a different service name | 648 | | slot_duration_author_ratio: 43691_u16, | 649 | | }) | 650 | 0 | .await | 651 | 0 | .map_err(StartError::RelayChainConsensusServiceInit)?, | 652 | | ) | 653 | | } else { | 654 | 19 | None | 655 | | }; | 656 | | | 657 | | // Start the JSON-RPC service. | 658 | | // It only needs to be kept alive in order to function. | 659 | | // | 660 | | // Note that initialization can fail if, for example, the port is already occupied. It is | 661 | | // preferable to fail to start the node altogether rather than make the user believe that they | 662 | | // are connected to the JSON-RPC endpoint of the node while they are in reality connected to | 663 | | // something else. | 664 | 19 | let json_rpc_service = json_rpc_service::JsonRpcService::new(json_rpc_service::Config { | 665 | 19 | tasks_executor: config.tasks_executor.clone(), | 666 | 19 | log_callback: config.log_callback.clone(), | 667 | 19 | database, | 668 | 19 | consensus_service: consensus_service.clone(), | 669 | 19 | network_service: (network_service.clone(), network_service_chain_ids[0]), | 670 | 19 | bind_address: config.chain.json_rpc_listen.as_ref().map(|cfg| cfg.address), | 671 | 19 | max_parallel_requests: 32, | 672 | 19 | max_json_rpc_clients: config | 673 | 19 | .chain | 674 | 19 | .json_rpc_listen | 675 | 19 | .map_or(0, |cfg| cfg.max_json_rpc_clients), | 676 | 19 | chain_name: chain_spec.name().to_owned(), | 677 | 19 | chain_type: chain_spec.chain_type().to_owned(), | 678 | 19 | chain_properties_json: chain_spec.properties().to_owned(), | 679 | 19 | chain_is_live: chain_spec.has_live_network(), | 680 | 19 | genesis_block_hash: genesis_chain_information | 681 | 19 | .as_ref() | 682 | 19 | .finalized_block_header | 683 | 19 | .hash(usize::from(chain_spec.block_number_bytes())), | 684 | 19 | }) | 685 | 0 | .await | 686 | 19 | .map_err(StartError::JsonRpcServiceInit)?0 ; | 687 | | | 688 | | // Start the JSON-RPC service of the relay chain. | 689 | | // See remarks above. | 690 | 19 | let relay_chain_json_rpc_service = if let Some(relay_chain_cfg0 ) = config.relay_chain { | 691 | 0 | let relay_chain_spec = relay_chain_spec.as_ref().unwrap(); | 692 | 0 | Some( | 693 | 0 | json_rpc_service::JsonRpcService::new(json_rpc_service::Config { | 694 | 0 | tasks_executor: config.tasks_executor.clone(), | 695 | 0 | log_callback: config.log_callback.clone(), | 696 | 0 | database: relay_chain_database.clone().unwrap(), | 697 | 0 | consensus_service: relay_chain_consensus_service.clone().unwrap(), | 698 | 0 | network_service: (network_service.clone(), network_service_chain_ids[1]), | 699 | 0 | bind_address: relay_chain_cfg | 700 | 0 | .json_rpc_listen | 701 | 0 | .as_ref() | 702 | 0 | .map(|cfg| cfg.address), | 703 | 0 | max_parallel_requests: 32, | 704 | 0 | max_json_rpc_clients: relay_chain_cfg | 705 | 0 | .json_rpc_listen | 706 | 0 | .map_or(0, |cfg| cfg.max_json_rpc_clients), | 707 | 0 | chain_name: relay_chain_spec.name().to_owned(), | 708 | 0 | chain_type: relay_chain_spec.chain_type().to_owned(), | 709 | 0 | chain_properties_json: relay_chain_spec.properties().to_owned(), | 710 | 0 | chain_is_live: relay_chain_spec.has_live_network(), | 711 | 0 | genesis_block_hash: relay_genesis_chain_information | 712 | 0 | .as_ref() | 713 | 0 | .unwrap() | 714 | 0 | .as_ref() | 715 | 0 | .finalized_block_header | 716 | 0 | .hash(usize::from(relay_chain_spec.block_number_bytes())), | 717 | 0 | }) | 718 | 0 | .await | 719 | 0 | .map_err(StartError::JsonRpcServiceInit)?, | 720 | | ) | 721 | | } else { | 722 | 19 | None | 723 | | }; | 724 | | | 725 | | // Spawn the task printing the informant. | 726 | | // This is not just a dummy task that just prints on the output, but is actually the main | 727 | | // task that holds everything else alive. Without it, all the services that we have created | 728 | | // above would be cleanly dropped and nothing would happen. | 729 | | // For this reason, it must be spawned even if no informant is started, in which case we simply | 730 | | // inhibit the printing. | 731 | 19 | let network_known_best = Arc::new(Mutex::new(None)); | 732 | 19 | (config.tasks_executor)(Box::pin({ | 733 | 19 | let mut main_network_events_receiver = network_events_receivers.next().unwrap(); | 734 | 19 | let network_service_chain_id = network_service_chain_ids[0]; | 735 | 19 | let network_known_best = network_known_best.clone(); | 736 | 19 | | 737 | 19 | // TODO: shut down this task if the client stops? | 738 | 19 | async move { | 739 | | loop { | 740 | | let network_event = main_network_events_receiver.next().await.unwrap(); | 741 | | let mut network_known_best = network_known_best.lock().await; | 742 | | | 743 | | match network_event { | 744 | | network_service::Event::BlockAnnounce { | 745 | | chain_id, | 746 | | scale_encoded_header, | 747 | | .. | 748 | | } if chain_id == network_service_chain_id => match ( | 749 | | *network_known_best, | 750 | | header::decode( | 751 | | &scale_encoded_header, | 752 | | usize::from(chain_spec.block_number_bytes()), | 753 | | ), | 754 | | ) { | 755 | | (Some(n), Ok(header)) if n >= header.number => {} | 756 | | (_, Ok(header)) => *network_known_best = Some(header.number), | 757 | | (_, Err(_)) => { | 758 | | // Do nothing if the block is invalid. This is just for the | 759 | | // informant and not for consensus-related purposes. | 760 | | } | 761 | | }, | 762 | | network_service::Event::Connected { | 763 | | chain_id, | 764 | | best_block_number, | 765 | | .. | 766 | | } if chain_id == network_service_chain_id => match *network_known_best { | 767 | | Some(n) if n >= best_block_number => {} | 768 | | _ => *network_known_best = Some(best_block_number), | 769 | | }, | 770 | | _ => {} | 771 | | } | 772 | | } | 773 | 19 | } | 774 | 19 | })); | 775 | 19 | | 776 | 19 | config.log_callback.log( | 777 | 19 | LogLevel::Info, | 778 | 19 | format!( | 779 | 19 | "successful-initialization; local_peer_id={}; database_is_new={:?}; \ | 780 | 19 | finalized_block_hash={}; finalized_block_number={}", | 781 | 19 | local_peer_id, | 782 | 19 | !database_existed, | 783 | 19 | HashDisplay(&database_finalized_block_hash), | 784 | 19 | database_finalized_block_number | 785 | 19 | ), | 786 | 19 | ); | 787 | 19 | | 788 | 19 | debug_assert!(network_events_receivers.next().is_none()); | 789 | 19 | Ok(Client { | 790 | 19 | consensus_service, | 791 | 19 | relay_chain_consensus_service, | 792 | 19 | json_rpc_service, | 793 | 19 | relay_chain_json_rpc_service, | 794 | 19 | network_service, | 795 | 19 | network_known_best, | 796 | 19 | }) | 797 | 19 | } |
Unexecuted instantiation: _RNCNvCshBwayKnNXDT_17smoldot_full_node5start0B3_ |
798 | | |
799 | | /// Opens the database from the file system, or create a new database if none is found. |
800 | | /// |
801 | | /// If `db_path` is `None`, open the database in memory instead. |
802 | | /// |
803 | | /// The returned boolean is `true` if the database existed before. |
804 | | /// |
805 | | /// # Panic |
806 | | /// |
807 | | /// Panics if the database can't be open. This function is expected to be called from the `main` |
808 | | /// function. |
809 | | /// |
810 | 21 | async fn open_database( |
811 | 21 | chain_spec: &chain_spec::ChainSpec, |
812 | 21 | genesis_chain_information: chain::chain_information::ChainInformationRef<'_>, |
813 | 21 | db_path: Option<PathBuf>, |
814 | 21 | sqlite_cache_size: usize, |
815 | 21 | ) -> (full_sqlite::SqliteFullDatabase, bool) { _RNvCsiUjFBJteJ7x_17smoldot_full_node13open_database Line | Count | Source | 810 | 21 | async fn open_database( | 811 | 21 | chain_spec: &chain_spec::ChainSpec, | 812 | 21 | genesis_chain_information: chain::chain_information::ChainInformationRef<'_>, | 813 | 21 | db_path: Option<PathBuf>, | 814 | 21 | sqlite_cache_size: usize, | 815 | 21 | ) -> (full_sqlite::SqliteFullDatabase, bool) { |
Unexecuted instantiation: _RNvCshBwayKnNXDT_17smoldot_full_node13open_database |
816 | 21 | // The `unwrap()` here can panic for example in case of access denied. |
817 | 21 | match full_sqlite::open(full_sqlite::Config { |
818 | 21 | block_number_bytes: chain_spec.block_number_bytes().into(), |
819 | 21 | cache_size: sqlite_cache_size, |
820 | 21 | ty: if let Some(path0 ) = &db_path { |
821 | 0 | full_sqlite::ConfigTy::Disk { |
822 | 0 | path, |
823 | 0 | memory_map_size: 1000000000, // TODO: make configurable |
824 | 0 | } |
825 | | } else { |
826 | 21 | full_sqlite::ConfigTy::Memory |
827 | | }, |
828 | | }) |
829 | 21 | .unwrap() |
830 | | { |
831 | | // Database already exists and contains data. |
832 | 0 | full_sqlite::DatabaseOpen::Open(database) => { |
833 | 0 | if database.block_hash_by_number(0).unwrap().next().unwrap() |
834 | 0 | != genesis_chain_information |
835 | 0 | .finalized_block_header |
836 | 0 | .hash(chain_spec.block_number_bytes().into()) |
837 | | { |
838 | 0 | panic!("Mismatch between database and chain specification. Shutting down node."); |
839 | 0 | } |
840 | 0 |
|
841 | 0 | (database, true) |
842 | | } |
843 | | |
844 | | // The database doesn't exist or is empty. |
845 | 21 | full_sqlite::DatabaseOpen::Empty(empty) => { |
846 | 21 | let genesis_storage = chain_spec.genesis_storage().into_genesis_items().unwrap(); // TODO: return error instead |
847 | 21 | |
848 | 21 | // In order to determine the state_version of the genesis block, we need to compile |
849 | 21 | // the runtime. |
850 | 21 | // TODO: return errors instead of panicking |
851 | 21 | // TODO: consider not throwing away the runtime |
852 | 21 | let state_version = executor::host::HostVmPrototype::new(executor::host::Config { |
853 | 21 | module: genesis_storage.value(b":code").unwrap(), |
854 | 21 | heap_pages: executor::storage_heap_pages_to_value( |
855 | 21 | genesis_storage.value(b":heappages"), |
856 | 21 | ) |
857 | 21 | .unwrap(), |
858 | 21 | exec_hint: executor::vm::ExecHint::ValidateAndExecuteOnce, |
859 | 21 | allow_unresolved_imports: true, |
860 | 21 | }) |
861 | 21 | .unwrap() |
862 | 21 | .runtime_version() |
863 | 21 | .decode() |
864 | 21 | .state_version |
865 | 21 | .map(u8::from) |
866 | 21 | .unwrap_or(0); |
867 | | |
868 | | // The chain specification only contains trie nodes that have a storage value attached |
869 | | // to them, while the database needs to know all trie nodes (including branch nodes). |
870 | | // The good news is that we can determine the latter from the former, which we do |
871 | | // here. |
872 | | // TODO: consider moving this block to the chain spec module |
873 | | // TODO: poorly optimized |
874 | 21 | let mut trie_structure = { |
875 | 21 | let mut trie_structure = trie::trie_structure::TrieStructure::new(); |
876 | 735 | for (key, value) in genesis_storage.iter()21 { |
877 | 735 | match trie_structure.node(trie::bytes_to_nibbles(key.iter().copied())) { |
878 | 735 | trie::trie_structure::Entry::Vacant(e) => { |
879 | 735 | e.insert_storage_value().insert( |
880 | 735 | (Some(value), None::<trie::trie_node::MerkleValueOutput>), |
881 | 735 | (None, None), |
882 | 735 | ); |
883 | 735 | } |
884 | | trie::trie_structure::Entry::Occupied( |
885 | 0 | trie::trie_structure::NodeAccess::Branch(mut e), |
886 | 0 | ) => { |
887 | 0 | *e.user_data() = (Some(value), None); |
888 | 0 | e.insert_storage_value(); |
889 | 0 | } |
890 | | trie::trie_structure::Entry::Occupied( |
891 | | trie::trie_structure::NodeAccess::Storage(_), |
892 | | ) => { |
893 | | // Duplicate entry. |
894 | 0 | panic!() // TODO: don't panic? |
895 | | } |
896 | | } |
897 | | } |
898 | | |
899 | | // Calculate the Merkle values of the nodes. |
900 | 1.00k | for node_index in trie_structure |
901 | 21 | .iter_ordered() |
902 | 21 | .collect::<Vec<_>>() |
903 | 21 | .into_iter() |
904 | 21 | .rev() |
905 | | { |
906 | 1.00k | let mut node_access = trie_structure.node_by_index(node_index).unwrap(); |
907 | 1.00k | |
908 | 16.1k | let children = core::array::from_fn::<_, 16, _>(|n| { |
909 | 16.1k | node_access |
910 | 16.1k | .child(trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap()) |
911 | 16.1k | .map(|mut child| child.user_data().1.as_ref().unwrap().clone()987 ) _RNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database000CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 911 | 94 | .map(|mut child| child.user_data().1.as_ref().unwrap().clone()) |
Unexecuted instantiation: _RNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database000B7_ Unexecuted instantiation: _RNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database000CscDgN54JpMGG_6author _RNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database000CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 911 | 893 | .map(|mut child| child.user_data().1.as_ref().unwrap().clone()) |
Unexecuted instantiation: _RNCNCNCNvCshBwayKnNXDT_17smoldot_full_node13open_database000B7_ |
912 | 16.1k | }); _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database00CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 908 | 1.53k | let children = core::array::from_fn::<_, 16, _>(|n| { | 909 | 1.53k | node_access | 910 | 1.53k | .child(trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap()) | 911 | 1.53k | .map(|mut child| child.user_data().1.as_ref().unwrap().clone()) | 912 | 1.53k | }); |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database00B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database00CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database00CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 908 | 14.5k | let children = core::array::from_fn::<_, 16, _>(|n| { | 909 | 14.5k | node_access | 910 | 14.5k | .child(trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap()) | 911 | 14.5k | .map(|mut child| child.user_data().1.as_ref().unwrap().clone()) | 912 | 14.5k | }); |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node13open_database00B5_ |
913 | 1.00k | |
914 | 1.00k | let is_root_node = node_access.is_root_node(); |
915 | 1.00k | let partial_key = node_access.partial_key().collect::<Vec<_>>().into_iter(); |
916 | | |
917 | | // We have to hash the storage value ahead of time if necessary due to borrow |
918 | | // checking difficulties. |
919 | 1.00k | let storage_value_hashed = |
920 | 1.00k | match (node_access.user_data().0.as_ref(), state_version) { |
921 | 0 | (Some(v), 1) => { |
922 | 0 | if v.len() >= 33 { |
923 | 0 | Some(blake2_rfc::blake2b::blake2b(32, &[], v)) |
924 | | } else { |
925 | 0 | None |
926 | | } |
927 | | } |
928 | 1.00k | _ => None, |
929 | | }; |
930 | 1.00k | let storage_value = match ( |
931 | 1.00k | node_access.user_data().0.as_ref(), |
932 | 1.00k | storage_value_hashed.as_ref(), |
933 | | ) { |
934 | 0 | (_, Some(storage_value_hashed)) => trie::trie_node::StorageValue::Hashed( |
935 | 0 | <&[u8; 32]>::try_from(storage_value_hashed.as_bytes()).unwrap(), |
936 | 0 | ), |
937 | 735 | (Some(v), None) => trie::trie_node::StorageValue::Unhashed(&v[..]), |
938 | 273 | (None, _) => trie::trie_node::StorageValue::None, |
939 | | }; |
940 | | |
941 | 1.00k | let merkle_value = trie::trie_node::calculate_merkle_value( |
942 | 1.00k | trie::trie_node::Decoded { |
943 | 1.00k | children, |
944 | 1.00k | partial_key, |
945 | 1.00k | storage_value, |
946 | 1.00k | }, |
947 | 1.00k | trie::HashFunction::Blake2, |
948 | 1.00k | is_root_node, |
949 | 1.00k | ) |
950 | 1.00k | .unwrap(); |
951 | 1.00k | |
952 | 1.00k | node_access.into_user_data().1 = Some(merkle_value); |
953 | | } |
954 | | |
955 | 21 | trie_structure |
956 | 21 | }; |
957 | 21 | |
958 | 21 | // Build the iterator of trie nodes. |
959 | 21 | let genesis_storage_full_trie = trie_structure |
960 | 21 | .iter_unordered() |
961 | 21 | .collect::<Vec<_>>() |
962 | 21 | .into_iter() |
963 | 1.00k | .map(|node_index| { |
964 | 1.00k | let (storage_value, Some(merkle_value)) = &trie_structure[node_index] else { |
965 | 0 | unreachable!() |
966 | | }; |
967 | | // Cloning to solve borrow checker restriction. // TODO: optimize? |
968 | 1.00k | let storage_value = if let Some(storage_value735 ) = storage_value { |
969 | | // TODO: child tries support? |
970 | 735 | full_sqlite::InsertTrieNodeStorageValue::Value { |
971 | 735 | value: Cow::Owned(storage_value.to_vec()), |
972 | 735 | references_merkle_value: false, |
973 | 735 | } |
974 | | } else { |
975 | 273 | full_sqlite::InsertTrieNodeStorageValue::NoValue |
976 | | }; |
977 | 1.00k | let merkle_value = merkle_value.as_ref().to_owned(); |
978 | 1.00k | let mut node_access = trie_structure.node_by_index(node_index).unwrap(); |
979 | 1.00k | |
980 | 1.00k | full_sqlite::InsertTrieNode { |
981 | 1.00k | storage_value, |
982 | 1.00k | merkle_value: Cow::Owned(merkle_value), |
983 | 16.1k | children_merkle_values: array::from_fn::<_, 16, _>(|n| { |
984 | 16.1k | let child_index = |
985 | 16.1k | trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap(); |
986 | 16.1k | node_access.child(child_index).map(|mut child| { |
987 | 987 | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) |
988 | 16.1k | }) _RNCNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_000CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 986 | 94 | node_access.child(child_index).map(|mut child| { | 987 | 94 | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) | 988 | 94 | }) |
Unexecuted instantiation: _RNCNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_000B9_ Unexecuted instantiation: _RNCNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_000CscDgN54JpMGG_6author _RNCNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_000CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 986 | 893 | node_access.child(child_index).map(|mut child| { | 987 | 893 | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) | 988 | 893 | }) |
Unexecuted instantiation: _RNCNCNCNCNvCshBwayKnNXDT_17smoldot_full_node13open_database0s_000B9_ |
989 | 16.1k | }), _RNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_00CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 983 | 1.53k | children_merkle_values: array::from_fn::<_, 16, _>(|n| { | 984 | 1.53k | let child_index = | 985 | 1.53k | trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap(); | 986 | 1.53k | node_access.child(child_index).map(|mut child| { | 987 | | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) | 988 | 1.53k | }) | 989 | 1.53k | }), |
Unexecuted instantiation: _RNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_00B7_ Unexecuted instantiation: _RNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_00CscDgN54JpMGG_6author _RNCNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_00CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 983 | 14.5k | children_merkle_values: array::from_fn::<_, 16, _>(|n| { | 984 | 14.5k | let child_index = | 985 | 14.5k | trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap(); | 986 | 14.5k | node_access.child(child_index).map(|mut child| { | 987 | | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) | 988 | 14.5k | }) | 989 | 14.5k | }), |
Unexecuted instantiation: _RNCNCNCNvCshBwayKnNXDT_17smoldot_full_node13open_database0s_00B7_ |
990 | 1.00k | partial_key_nibbles: Cow::Owned( |
991 | 1.00k | node_access.partial_key().map(u8::from).collect::<Vec<_>>(), |
992 | 1.00k | ), |
993 | 1.00k | } |
994 | 1.00k | }); _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 963 | 96 | .map(|node_index| { | 964 | 96 | let (storage_value, Some(merkle_value)) = &trie_structure[node_index] else { | 965 | 0 | unreachable!() | 966 | | }; | 967 | | // Cloning to solve borrow checker restriction. // TODO: optimize? | 968 | 96 | let storage_value = if let Some(storage_value70 ) = storage_value { | 969 | | // TODO: child tries support? | 970 | 70 | full_sqlite::InsertTrieNodeStorageValue::Value { | 971 | 70 | value: Cow::Owned(storage_value.to_vec()), | 972 | 70 | references_merkle_value: false, | 973 | 70 | } | 974 | | } else { | 975 | 26 | full_sqlite::InsertTrieNodeStorageValue::NoValue | 976 | | }; | 977 | 96 | let merkle_value = merkle_value.as_ref().to_owned(); | 978 | 96 | let mut node_access = trie_structure.node_by_index(node_index).unwrap(); | 979 | 96 | | 980 | 96 | full_sqlite::InsertTrieNode { | 981 | 96 | storage_value, | 982 | 96 | merkle_value: Cow::Owned(merkle_value), | 983 | 96 | children_merkle_values: array::from_fn::<_, 16, _>(|n| { | 984 | | let child_index = | 985 | | trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap(); | 986 | | node_access.child(child_index).map(|mut child| { | 987 | | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) | 988 | | }) | 989 | 96 | }), | 990 | 96 | partial_key_nibbles: Cow::Owned( | 991 | 96 | node_access.partial_key().map(u8::from).collect::<Vec<_>>(), | 992 | 96 | ), | 993 | 96 | } | 994 | 96 | }); |
Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0B5_ Unexecuted instantiation: _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0CscDgN54JpMGG_6author _RNCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 963 | 912 | .map(|node_index| { | 964 | 912 | let (storage_value, Some(merkle_value)) = &trie_structure[node_index] else { | 965 | 0 | unreachable!() | 966 | | }; | 967 | | // Cloning to solve borrow checker restriction. // TODO: optimize? | 968 | 912 | let storage_value = if let Some(storage_value665 ) = storage_value { | 969 | | // TODO: child tries support? | 970 | 665 | full_sqlite::InsertTrieNodeStorageValue::Value { | 971 | 665 | value: Cow::Owned(storage_value.to_vec()), | 972 | 665 | references_merkle_value: false, | 973 | 665 | } | 974 | | } else { | 975 | 247 | full_sqlite::InsertTrieNodeStorageValue::NoValue | 976 | | }; | 977 | 912 | let merkle_value = merkle_value.as_ref().to_owned(); | 978 | 912 | let mut node_access = trie_structure.node_by_index(node_index).unwrap(); | 979 | 912 | | 980 | 912 | full_sqlite::InsertTrieNode { | 981 | 912 | storage_value, | 982 | 912 | merkle_value: Cow::Owned(merkle_value), | 983 | 912 | children_merkle_values: array::from_fn::<_, 16, _>(|n| { | 984 | | let child_index = | 985 | | trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap(); | 986 | | node_access.child(child_index).map(|mut child| { | 987 | | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) | 988 | | }) | 989 | 912 | }), | 990 | 912 | partial_key_nibbles: Cow::Owned( | 991 | 912 | node_access.partial_key().map(u8::from).collect::<Vec<_>>(), | 992 | 912 | ), | 993 | 912 | } | 994 | 912 | }); |
Unexecuted instantiation: _RNCNCNvCshBwayKnNXDT_17smoldot_full_node13open_database0s_0B5_ |
995 | 21 | |
996 | 21 | // The finalized block is the genesis block. As such, it has an empty body and |
997 | 21 | // no justification. |
998 | 21 | let database = empty |
999 | 21 | .initialize( |
1000 | 21 | &genesis_chain_information |
1001 | 21 | .finalized_block_header |
1002 | 21 | .scale_encoding_vec(chain_spec.block_number_bytes().into()), |
1003 | 21 | iter::empty(), |
1004 | 21 | None, |
1005 | 21 | ) |
1006 | 21 | .unwrap(); |
1007 | 21 | database |
1008 | 21 | .insert_trie_nodes(genesis_storage_full_trie, state_version) |
1009 | 21 | .unwrap(); |
1010 | 21 | (database, false) |
1011 | | } |
1012 | | } |
1013 | 21 | } _RNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 815 | 2 | ) -> (full_sqlite::SqliteFullDatabase, bool) { | 816 | 2 | // The `unwrap()` here can panic for example in case of access denied. | 817 | 2 | match full_sqlite::open(full_sqlite::Config { | 818 | 2 | block_number_bytes: chain_spec.block_number_bytes().into(), | 819 | 2 | cache_size: sqlite_cache_size, | 820 | 2 | ty: if let Some(path0 ) = &db_path { | 821 | 0 | full_sqlite::ConfigTy::Disk { | 822 | 0 | path, | 823 | 0 | memory_map_size: 1000000000, // TODO: make configurable | 824 | 0 | } | 825 | | } else { | 826 | 2 | full_sqlite::ConfigTy::Memory | 827 | | }, | 828 | | }) | 829 | 2 | .unwrap() | 830 | | { | 831 | | // Database already exists and contains data. | 832 | 0 | full_sqlite::DatabaseOpen::Open(database) => { | 833 | 0 | if database.block_hash_by_number(0).unwrap().next().unwrap() | 834 | 0 | != genesis_chain_information | 835 | 0 | .finalized_block_header | 836 | 0 | .hash(chain_spec.block_number_bytes().into()) | 837 | | { | 838 | 0 | panic!("Mismatch between database and chain specification. Shutting down node."); | 839 | 0 | } | 840 | 0 |
| 841 | 0 | (database, true) | 842 | | } | 843 | | | 844 | | // The database doesn't exist or is empty. | 845 | 2 | full_sqlite::DatabaseOpen::Empty(empty) => { | 846 | 2 | let genesis_storage = chain_spec.genesis_storage().into_genesis_items().unwrap(); // TODO: return error instead | 847 | 2 | | 848 | 2 | // In order to determine the state_version of the genesis block, we need to compile | 849 | 2 | // the runtime. | 850 | 2 | // TODO: return errors instead of panicking | 851 | 2 | // TODO: consider not throwing away the runtime | 852 | 2 | let state_version = executor::host::HostVmPrototype::new(executor::host::Config { | 853 | 2 | module: genesis_storage.value(b":code").unwrap(), | 854 | 2 | heap_pages: executor::storage_heap_pages_to_value( | 855 | 2 | genesis_storage.value(b":heappages"), | 856 | 2 | ) | 857 | 2 | .unwrap(), | 858 | 2 | exec_hint: executor::vm::ExecHint::ValidateAndExecuteOnce, | 859 | 2 | allow_unresolved_imports: true, | 860 | 2 | }) | 861 | 2 | .unwrap() | 862 | 2 | .runtime_version() | 863 | 2 | .decode() | 864 | 2 | .state_version | 865 | 2 | .map(u8::from) | 866 | 2 | .unwrap_or(0); | 867 | | | 868 | | // The chain specification only contains trie nodes that have a storage value attached | 869 | | // to them, while the database needs to know all trie nodes (including branch nodes). | 870 | | // The good news is that we can determine the latter from the former, which we do | 871 | | // here. | 872 | | // TODO: consider moving this block to the chain spec module | 873 | | // TODO: poorly optimized | 874 | 2 | let mut trie_structure = { | 875 | 2 | let mut trie_structure = trie::trie_structure::TrieStructure::new(); | 876 | 70 | for (key, value) in genesis_storage.iter()2 { | 877 | 70 | match trie_structure.node(trie::bytes_to_nibbles(key.iter().copied())) { | 878 | 70 | trie::trie_structure::Entry::Vacant(e) => { | 879 | 70 | e.insert_storage_value().insert( | 880 | 70 | (Some(value), None::<trie::trie_node::MerkleValueOutput>), | 881 | 70 | (None, None), | 882 | 70 | ); | 883 | 70 | } | 884 | | trie::trie_structure::Entry::Occupied( | 885 | 0 | trie::trie_structure::NodeAccess::Branch(mut e), | 886 | 0 | ) => { | 887 | 0 | *e.user_data() = (Some(value), None); | 888 | 0 | e.insert_storage_value(); | 889 | 0 | } | 890 | | trie::trie_structure::Entry::Occupied( | 891 | | trie::trie_structure::NodeAccess::Storage(_), | 892 | | ) => { | 893 | | // Duplicate entry. | 894 | 0 | panic!() // TODO: don't panic? | 895 | | } | 896 | | } | 897 | | } | 898 | | | 899 | | // Calculate the Merkle values of the nodes. | 900 | 96 | for node_index in trie_structure | 901 | 2 | .iter_ordered() | 902 | 2 | .collect::<Vec<_>>() | 903 | 2 | .into_iter() | 904 | 2 | .rev() | 905 | | { | 906 | 96 | let mut node_access = trie_structure.node_by_index(node_index).unwrap(); | 907 | 96 | | 908 | 96 | let children = core::array::from_fn::<_, 16, _>(|n| { | 909 | | node_access | 910 | | .child(trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap()) | 911 | | .map(|mut child| child.user_data().1.as_ref().unwrap().clone()) | 912 | 96 | }); | 913 | 96 | | 914 | 96 | let is_root_node = node_access.is_root_node(); | 915 | 96 | let partial_key = node_access.partial_key().collect::<Vec<_>>().into_iter(); | 916 | | | 917 | | // We have to hash the storage value ahead of time if necessary due to borrow | 918 | | // checking difficulties. | 919 | 96 | let storage_value_hashed = | 920 | 96 | match (node_access.user_data().0.as_ref(), state_version) { | 921 | 0 | (Some(v), 1) => { | 922 | 0 | if v.len() >= 33 { | 923 | 0 | Some(blake2_rfc::blake2b::blake2b(32, &[], v)) | 924 | | } else { | 925 | 0 | None | 926 | | } | 927 | | } | 928 | 96 | _ => None, | 929 | | }; | 930 | 96 | let storage_value = match ( | 931 | 96 | node_access.user_data().0.as_ref(), | 932 | 96 | storage_value_hashed.as_ref(), | 933 | | ) { | 934 | 0 | (_, Some(storage_value_hashed)) => trie::trie_node::StorageValue::Hashed( | 935 | 0 | <&[u8; 32]>::try_from(storage_value_hashed.as_bytes()).unwrap(), | 936 | 0 | ), | 937 | 70 | (Some(v), None) => trie::trie_node::StorageValue::Unhashed(&v[..]), | 938 | 26 | (None, _) => trie::trie_node::StorageValue::None, | 939 | | }; | 940 | | | 941 | 96 | let merkle_value = trie::trie_node::calculate_merkle_value( | 942 | 96 | trie::trie_node::Decoded { | 943 | 96 | children, | 944 | 96 | partial_key, | 945 | 96 | storage_value, | 946 | 96 | }, | 947 | 96 | trie::HashFunction::Blake2, | 948 | 96 | is_root_node, | 949 | 96 | ) | 950 | 96 | .unwrap(); | 951 | 96 | | 952 | 96 | node_access.into_user_data().1 = Some(merkle_value); | 953 | | } | 954 | | | 955 | 2 | trie_structure | 956 | 2 | }; | 957 | 2 | | 958 | 2 | // Build the iterator of trie nodes. | 959 | 2 | let genesis_storage_full_trie = trie_structure | 960 | 2 | .iter_unordered() | 961 | 2 | .collect::<Vec<_>>() | 962 | 2 | .into_iter() | 963 | 2 | .map(|node_index| { | 964 | | let (storage_value, Some(merkle_value)) = &trie_structure[node_index] else { | 965 | | unreachable!() | 966 | | }; | 967 | | // Cloning to solve borrow checker restriction. // TODO: optimize? | 968 | | let storage_value = if let Some(storage_value) = storage_value { | 969 | | // TODO: child tries support? | 970 | | full_sqlite::InsertTrieNodeStorageValue::Value { | 971 | | value: Cow::Owned(storage_value.to_vec()), | 972 | | references_merkle_value: false, | 973 | | } | 974 | | } else { | 975 | | full_sqlite::InsertTrieNodeStorageValue::NoValue | 976 | | }; | 977 | | let merkle_value = merkle_value.as_ref().to_owned(); | 978 | | let mut node_access = trie_structure.node_by_index(node_index).unwrap(); | 979 | | | 980 | | full_sqlite::InsertTrieNode { | 981 | | storage_value, | 982 | | merkle_value: Cow::Owned(merkle_value), | 983 | | children_merkle_values: array::from_fn::<_, 16, _>(|n| { | 984 | | let child_index = | 985 | | trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap(); | 986 | | node_access.child(child_index).map(|mut child| { | 987 | | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) | 988 | | }) | 989 | | }), | 990 | | partial_key_nibbles: Cow::Owned( | 991 | | node_access.partial_key().map(u8::from).collect::<Vec<_>>(), | 992 | | ), | 993 | | } | 994 | 2 | }); | 995 | 2 | | 996 | 2 | // The finalized block is the genesis block. As such, it has an empty body and | 997 | 2 | // no justification. | 998 | 2 | let database = empty | 999 | 2 | .initialize( | 1000 | 2 | &genesis_chain_information | 1001 | 2 | .finalized_block_header | 1002 | 2 | .scale_encoding_vec(chain_spec.block_number_bytes().into()), | 1003 | 2 | iter::empty(), | 1004 | 2 | None, | 1005 | 2 | ) | 1006 | 2 | .unwrap(); | 1007 | 2 | database | 1008 | 2 | .insert_trie_nodes(genesis_storage_full_trie, state_version) | 1009 | 2 | .unwrap(); | 1010 | 2 | (database, false) | 1011 | | } | 1012 | | } | 1013 | 2 | } |
Unexecuted instantiation: _RNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0B3_ Unexecuted instantiation: _RNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0CscDgN54JpMGG_6author _RNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 815 | 19 | ) -> (full_sqlite::SqliteFullDatabase, bool) { | 816 | 19 | // The `unwrap()` here can panic for example in case of access denied. | 817 | 19 | match full_sqlite::open(full_sqlite::Config { | 818 | 19 | block_number_bytes: chain_spec.block_number_bytes().into(), | 819 | 19 | cache_size: sqlite_cache_size, | 820 | 19 | ty: if let Some(path0 ) = &db_path { | 821 | 0 | full_sqlite::ConfigTy::Disk { | 822 | 0 | path, | 823 | 0 | memory_map_size: 1000000000, // TODO: make configurable | 824 | 0 | } | 825 | | } else { | 826 | 19 | full_sqlite::ConfigTy::Memory | 827 | | }, | 828 | | }) | 829 | 19 | .unwrap() | 830 | | { | 831 | | // Database already exists and contains data. | 832 | 0 | full_sqlite::DatabaseOpen::Open(database) => { | 833 | 0 | if database.block_hash_by_number(0).unwrap().next().unwrap() | 834 | 0 | != genesis_chain_information | 835 | 0 | .finalized_block_header | 836 | 0 | .hash(chain_spec.block_number_bytes().into()) | 837 | | { | 838 | 0 | panic!("Mismatch between database and chain specification. Shutting down node."); | 839 | 0 | } | 840 | 0 |
| 841 | 0 | (database, true) | 842 | | } | 843 | | | 844 | | // The database doesn't exist or is empty. | 845 | 19 | full_sqlite::DatabaseOpen::Empty(empty) => { | 846 | 19 | let genesis_storage = chain_spec.genesis_storage().into_genesis_items().unwrap(); // TODO: return error instead | 847 | 19 | | 848 | 19 | // In order to determine the state_version of the genesis block, we need to compile | 849 | 19 | // the runtime. | 850 | 19 | // TODO: return errors instead of panicking | 851 | 19 | // TODO: consider not throwing away the runtime | 852 | 19 | let state_version = executor::host::HostVmPrototype::new(executor::host::Config { | 853 | 19 | module: genesis_storage.value(b":code").unwrap(), | 854 | 19 | heap_pages: executor::storage_heap_pages_to_value( | 855 | 19 | genesis_storage.value(b":heappages"), | 856 | 19 | ) | 857 | 19 | .unwrap(), | 858 | 19 | exec_hint: executor::vm::ExecHint::ValidateAndExecuteOnce, | 859 | 19 | allow_unresolved_imports: true, | 860 | 19 | }) | 861 | 19 | .unwrap() | 862 | 19 | .runtime_version() | 863 | 19 | .decode() | 864 | 19 | .state_version | 865 | 19 | .map(u8::from) | 866 | 19 | .unwrap_or(0); | 867 | | | 868 | | // The chain specification only contains trie nodes that have a storage value attached | 869 | | // to them, while the database needs to know all trie nodes (including branch nodes). | 870 | | // The good news is that we can determine the latter from the former, which we do | 871 | | // here. | 872 | | // TODO: consider moving this block to the chain spec module | 873 | | // TODO: poorly optimized | 874 | 19 | let mut trie_structure = { | 875 | 19 | let mut trie_structure = trie::trie_structure::TrieStructure::new(); | 876 | 665 | for (key, value) in genesis_storage.iter()19 { | 877 | 665 | match trie_structure.node(trie::bytes_to_nibbles(key.iter().copied())) { | 878 | 665 | trie::trie_structure::Entry::Vacant(e) => { | 879 | 665 | e.insert_storage_value().insert( | 880 | 665 | (Some(value), None::<trie::trie_node::MerkleValueOutput>), | 881 | 665 | (None, None), | 882 | 665 | ); | 883 | 665 | } | 884 | | trie::trie_structure::Entry::Occupied( | 885 | 0 | trie::trie_structure::NodeAccess::Branch(mut e), | 886 | 0 | ) => { | 887 | 0 | *e.user_data() = (Some(value), None); | 888 | 0 | e.insert_storage_value(); | 889 | 0 | } | 890 | | trie::trie_structure::Entry::Occupied( | 891 | | trie::trie_structure::NodeAccess::Storage(_), | 892 | | ) => { | 893 | | // Duplicate entry. | 894 | 0 | panic!() // TODO: don't panic? | 895 | | } | 896 | | } | 897 | | } | 898 | | | 899 | | // Calculate the Merkle values of the nodes. | 900 | 912 | for node_index in trie_structure | 901 | 19 | .iter_ordered() | 902 | 19 | .collect::<Vec<_>>() | 903 | 19 | .into_iter() | 904 | 19 | .rev() | 905 | | { | 906 | 912 | let mut node_access = trie_structure.node_by_index(node_index).unwrap(); | 907 | 912 | | 908 | 912 | let children = core::array::from_fn::<_, 16, _>(|n| { | 909 | | node_access | 910 | | .child(trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap()) | 911 | | .map(|mut child| child.user_data().1.as_ref().unwrap().clone()) | 912 | 912 | }); | 913 | 912 | | 914 | 912 | let is_root_node = node_access.is_root_node(); | 915 | 912 | let partial_key = node_access.partial_key().collect::<Vec<_>>().into_iter(); | 916 | | | 917 | | // We have to hash the storage value ahead of time if necessary due to borrow | 918 | | // checking difficulties. | 919 | 912 | let storage_value_hashed = | 920 | 912 | match (node_access.user_data().0.as_ref(), state_version) { | 921 | 0 | (Some(v), 1) => { | 922 | 0 | if v.len() >= 33 { | 923 | 0 | Some(blake2_rfc::blake2b::blake2b(32, &[], v)) | 924 | | } else { | 925 | 0 | None | 926 | | } | 927 | | } | 928 | 912 | _ => None, | 929 | | }; | 930 | 912 | let storage_value = match ( | 931 | 912 | node_access.user_data().0.as_ref(), | 932 | 912 | storage_value_hashed.as_ref(), | 933 | | ) { | 934 | 0 | (_, Some(storage_value_hashed)) => trie::trie_node::StorageValue::Hashed( | 935 | 0 | <&[u8; 32]>::try_from(storage_value_hashed.as_bytes()).unwrap(), | 936 | 0 | ), | 937 | 665 | (Some(v), None) => trie::trie_node::StorageValue::Unhashed(&v[..]), | 938 | 247 | (None, _) => trie::trie_node::StorageValue::None, | 939 | | }; | 940 | | | 941 | 912 | let merkle_value = trie::trie_node::calculate_merkle_value( | 942 | 912 | trie::trie_node::Decoded { | 943 | 912 | children, | 944 | 912 | partial_key, | 945 | 912 | storage_value, | 946 | 912 | }, | 947 | 912 | trie::HashFunction::Blake2, | 948 | 912 | is_root_node, | 949 | 912 | ) | 950 | 912 | .unwrap(); | 951 | 912 | | 952 | 912 | node_access.into_user_data().1 = Some(merkle_value); | 953 | | } | 954 | | | 955 | 19 | trie_structure | 956 | 19 | }; | 957 | 19 | | 958 | 19 | // Build the iterator of trie nodes. | 959 | 19 | let genesis_storage_full_trie = trie_structure | 960 | 19 | .iter_unordered() | 961 | 19 | .collect::<Vec<_>>() | 962 | 19 | .into_iter() | 963 | 19 | .map(|node_index| { | 964 | | let (storage_value, Some(merkle_value)) = &trie_structure[node_index] else { | 965 | | unreachable!() | 966 | | }; | 967 | | // Cloning to solve borrow checker restriction. // TODO: optimize? | 968 | | let storage_value = if let Some(storage_value) = storage_value { | 969 | | // TODO: child tries support? | 970 | | full_sqlite::InsertTrieNodeStorageValue::Value { | 971 | | value: Cow::Owned(storage_value.to_vec()), | 972 | | references_merkle_value: false, | 973 | | } | 974 | | } else { | 975 | | full_sqlite::InsertTrieNodeStorageValue::NoValue | 976 | | }; | 977 | | let merkle_value = merkle_value.as_ref().to_owned(); | 978 | | let mut node_access = trie_structure.node_by_index(node_index).unwrap(); | 979 | | | 980 | | full_sqlite::InsertTrieNode { | 981 | | storage_value, | 982 | | merkle_value: Cow::Owned(merkle_value), | 983 | | children_merkle_values: array::from_fn::<_, 16, _>(|n| { | 984 | | let child_index = | 985 | | trie::Nibble::try_from(u8::try_from(n).unwrap()).unwrap(); | 986 | | node_access.child(child_index).map(|mut child| { | 987 | | Cow::Owned(child.user_data().1.as_ref().unwrap().as_ref().to_vec()) | 988 | | }) | 989 | | }), | 990 | | partial_key_nibbles: Cow::Owned( | 991 | | node_access.partial_key().map(u8::from).collect::<Vec<_>>(), | 992 | | ), | 993 | | } | 994 | 19 | }); | 995 | 19 | | 996 | 19 | // The finalized block is the genesis block. As such, it has an empty body and | 997 | 19 | // no justification. | 998 | 19 | let database = empty | 999 | 19 | .initialize( | 1000 | 19 | &genesis_chain_information | 1001 | 19 | .finalized_block_header | 1002 | 19 | .scale_encoding_vec(chain_spec.block_number_bytes().into()), | 1003 | 19 | iter::empty(), | 1004 | 19 | None, | 1005 | 19 | ) | 1006 | 19 | .unwrap(); | 1007 | 19 | database | 1008 | 19 | .insert_trie_nodes(genesis_storage_full_trie, state_version) | 1009 | 19 | .unwrap(); | 1010 | 19 | (database, false) | 1011 | | } | 1012 | | } | 1013 | 19 | } |
Unexecuted instantiation: _RNCNvCshBwayKnNXDT_17smoldot_full_node13open_database0B3_ |