/__w/smoldot/smoldot/repo/lib/src/chain_spec.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 | | //! Substrate chain configuration. |
19 | | //! |
20 | | //! A **chain spec** (short for *chain specification*) is the description of everything that is |
21 | | //! required for the client to successfully interact with a certain blockchain. |
22 | | //! For example, the Polkadot chain spec contains all the constants that are needed in order to |
23 | | //! successfully interact with Polkadot. |
24 | | //! |
25 | | //! Chain specs contain, notably: |
26 | | //! |
27 | | //! - The state of the genesis block. In other words, the initial content of the database. This |
28 | | //! includes the Wasm runtime code of the genesis block. |
29 | | //! - The list of bootstrap nodes. These are the IP addresses of the machines we need to connect |
30 | | //! to. |
31 | | //! - The default telemetry endpoints, to which we should send telemetry information to. |
32 | | //! - The name of the network protocol, in order to avoid accidentally connecting to a different |
33 | | //! network. |
34 | | //! - Multiple other miscellaneous information. |
35 | | //! |
36 | | |
37 | | use crate::{ |
38 | | chain::chain_information::{ |
39 | | build, BabeEpochInformation, ChainInformation, ChainInformationConsensus, |
40 | | ChainInformationFinality, ValidChainInformation, ValidityError, |
41 | | }, |
42 | | executor, libp2p, trie, |
43 | | }; |
44 | | |
45 | | use alloc::{ |
46 | | boxed::Box, |
47 | | string::{String, ToString as _}, |
48 | | vec::Vec, |
49 | | }; |
50 | | use core::{iter, num::NonZeroU64, ops::Bound}; |
51 | | |
52 | | mod light_sync_state; |
53 | | mod structs; |
54 | | mod tests; |
55 | | |
56 | | /// A configuration of a chain. Can be used to build a genesis block. |
57 | | #[derive(Clone)] |
58 | | pub struct ChainSpec { |
59 | | client_spec: structs::ClientSpec, |
60 | | } |
61 | | |
62 | | impl ChainSpec { |
63 | | /// Parse JSON content into a [`ChainSpec`]. |
64 | 29 | pub fn from_json_bytes(json: impl AsRef<[u8]>) -> Result<Self, ParseError> { |
65 | 29 | let client_spec: structs::ClientSpec = serde_json::from_slice(json.as_ref()) |
66 | 29 | .map_err(ParseErrorInner::Serde) |
67 | 29 | .map_err(ParseError)?0 ; |
68 | | |
69 | | // TODO: we don't support child tries in the genesis block |
70 | 29 | assert!(match &client_spec.genesis { |
71 | 29 | structs::Genesis::Raw(genesis) => genesis.children_default.is_empty(), |
72 | 0 | structs::Genesis::StateRootHash(_) => true, |
73 | | }); |
74 | | |
75 | 29 | if client_spec.relay_chain.is_some() != client_spec.para_id.is_some() { |
76 | 2 | return Err(ParseError(ParseErrorInner::Other)); |
77 | 27 | } |
78 | | |
79 | | // Make sure that the light sync state can be successfully decoded. |
80 | 27 | if let Some(light_sync_state1 ) = &client_spec.light_sync_state { |
81 | | // TODO: this "4" constant is repeated |
82 | 1 | light_sync_state.decode(client_spec.block_number_bytes.unwrap_or(4).into())?0 ; |
83 | 26 | } |
84 | | |
85 | 27 | Ok(ChainSpec { client_spec }) |
86 | 29 | } _RINvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB3_9ChainSpec15from_json_bytesRAhj2dcafd_EB5_ Line | Count | Source | 64 | 1 | pub fn from_json_bytes(json: impl AsRef<[u8]>) -> Result<Self, ParseError> { | 65 | 1 | let client_spec: structs::ClientSpec = serde_json::from_slice(json.as_ref()) | 66 | 1 | .map_err(ParseErrorInner::Serde) | 67 | 1 | .map_err(ParseError)?0 ; | 68 | | | 69 | | // TODO: we don't support child tries in the genesis block | 70 | 1 | assert!(match &client_spec.genesis { | 71 | 1 | structs::Genesis::Raw(genesis) => genesis.children_default.is_empty(), | 72 | 0 | structs::Genesis::StateRootHash(_) => true, | 73 | | }); | 74 | | | 75 | 1 | if client_spec.relay_chain.is_some() != client_spec.para_id.is_some() { | 76 | 0 | return Err(ParseError(ParseErrorInner::Other)); | 77 | 1 | } | 78 | | | 79 | | // Make sure that the light sync state can be successfully decoded. | 80 | 1 | if let Some(light_sync_state) = &client_spec.light_sync_state { | 81 | | // TODO: this "4" constant is repeated | 82 | 1 | light_sync_state.decode(client_spec.block_number_bytes.unwrap_or(4).into())?0 ; | 83 | 0 | } | 84 | | | 85 | 1 | Ok(ChainSpec { client_spec }) | 86 | 1 | } |
_RINvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB3_9ChainSpec15from_json_bytesRShEB5_ Line | Count | Source | 64 | 2 | pub fn from_json_bytes(json: impl AsRef<[u8]>) -> Result<Self, ParseError> { | 65 | 2 | let client_spec: structs::ClientSpec = serde_json::from_slice(json.as_ref()) | 66 | 2 | .map_err(ParseErrorInner::Serde) | 67 | 2 | .map_err(ParseError)?0 ; | 68 | | | 69 | | // TODO: we don't support child tries in the genesis block | 70 | 2 | assert!(match &client_spec.genesis { | 71 | 2 | structs::Genesis::Raw(genesis) => genesis.children_default.is_empty(), | 72 | 0 | structs::Genesis::StateRootHash(_) => true, | 73 | | }); | 74 | | | 75 | 2 | if client_spec.relay_chain.is_some() != client_spec.para_id.is_some() { | 76 | 0 | return Err(ParseError(ParseErrorInner::Other)); | 77 | 2 | } | 78 | | | 79 | | // Make sure that the light sync state can be successfully decoded. | 80 | 2 | if let Some(light_sync_state0 ) = &client_spec.light_sync_state { | 81 | | // TODO: this "4" constant is repeated | 82 | 0 | light_sync_state.decode(client_spec.block_number_bytes.unwrap_or(4).into())?; | 83 | 2 | } | 84 | | | 85 | 2 | Ok(ChainSpec { client_spec }) | 86 | 2 | } |
_RINvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB3_9ChainSpec15from_json_bytesReEB5_ Line | Count | Source | 64 | 5 | pub fn from_json_bytes(json: impl AsRef<[u8]>) -> Result<Self, ParseError> { | 65 | 5 | let client_spec: structs::ClientSpec = serde_json::from_slice(json.as_ref()) | 66 | 5 | .map_err(ParseErrorInner::Serde) | 67 | 5 | .map_err(ParseError)?0 ; | 68 | | | 69 | | // TODO: we don't support child tries in the genesis block | 70 | 5 | assert!(match &client_spec.genesis { | 71 | 5 | structs::Genesis::Raw(genesis) => genesis.children_default.is_empty(), | 72 | 0 | structs::Genesis::StateRootHash(_) => true, | 73 | | }); | 74 | | | 75 | 5 | if client_spec.relay_chain.is_some() != client_spec.para_id.is_some() { | 76 | 2 | return Err(ParseError(ParseErrorInner::Other)); | 77 | 3 | } | 78 | | | 79 | | // Make sure that the light sync state can be successfully decoded. | 80 | 3 | if let Some(light_sync_state0 ) = &client_spec.light_sync_state { | 81 | | // TODO: this "4" constant is repeated | 82 | 0 | light_sync_state.decode(client_spec.block_number_bytes.unwrap_or(4).into())?; | 83 | 3 | } | 84 | | | 85 | 3 | Ok(ChainSpec { client_spec }) | 86 | 5 | } |
Unexecuted instantiation: _RINvMNtCseuYC0Zibziv_7smoldot10chain_specNtB3_9ChainSpec15from_json_bytesReECsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RINvMNtCseuYC0Zibziv_7smoldot10chain_specNtB3_9ChainSpec15from_json_bytespEB5_ _RINvMNtCseuYC0Zibziv_7smoldot10chain_specNtB3_9ChainSpec15from_json_bytesRINtNtCsdZExvAaxgia_5alloc6borrow3CowShEECsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 64 | 2 | pub fn from_json_bytes(json: impl AsRef<[u8]>) -> Result<Self, ParseError> { | 65 | 2 | let client_spec: structs::ClientSpec = serde_json::from_slice(json.as_ref()) | 66 | 2 | .map_err(ParseErrorInner::Serde) | 67 | 2 | .map_err(ParseError)?0 ; | 68 | | | 69 | | // TODO: we don't support child tries in the genesis block | 70 | 2 | assert!(match &client_spec.genesis { | 71 | 2 | structs::Genesis::Raw(genesis) => genesis.children_default.is_empty(), | 72 | 0 | structs::Genesis::StateRootHash(_) => true, | 73 | | }); | 74 | | | 75 | 2 | if client_spec.relay_chain.is_some() != client_spec.para_id.is_some() { | 76 | 0 | return Err(ParseError(ParseErrorInner::Other)); | 77 | 2 | } | 78 | | | 79 | | // Make sure that the light sync state can be successfully decoded. | 80 | 2 | if let Some(light_sync_state0 ) = &client_spec.light_sync_state { | 81 | | // TODO: this "4" constant is repeated | 82 | 0 | light_sync_state.decode(client_spec.block_number_bytes.unwrap_or(4).into())?; | 83 | 2 | } | 84 | | | 85 | 2 | Ok(ChainSpec { client_spec }) | 86 | 2 | } |
Unexecuted instantiation: _RINvMNtCseuYC0Zibziv_7smoldot10chain_specNtB3_9ChainSpec15from_json_bytesRINtNtCsdZExvAaxgia_5alloc6borrow3CowShEECscDgN54JpMGG_6author _RINvMNtCseuYC0Zibziv_7smoldot10chain_specNtB3_9ChainSpec15from_json_bytesRINtNtCsdZExvAaxgia_5alloc6borrow3CowShEECsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 64 | 19 | pub fn from_json_bytes(json: impl AsRef<[u8]>) -> Result<Self, ParseError> { | 65 | 19 | let client_spec: structs::ClientSpec = serde_json::from_slice(json.as_ref()) | 66 | 19 | .map_err(ParseErrorInner::Serde) | 67 | 19 | .map_err(ParseError)?0 ; | 68 | | | 69 | | // TODO: we don't support child tries in the genesis block | 70 | 19 | assert!(match &client_spec.genesis { | 71 | 19 | structs::Genesis::Raw(genesis) => genesis.children_default.is_empty(), | 72 | 0 | structs::Genesis::StateRootHash(_) => true, | 73 | | }); | 74 | | | 75 | 19 | if client_spec.relay_chain.is_some() != client_spec.para_id.is_some() { | 76 | 0 | return Err(ParseError(ParseErrorInner::Other)); | 77 | 19 | } | 78 | | | 79 | | // Make sure that the light sync state can be successfully decoded. | 80 | 19 | if let Some(light_sync_state0 ) = &client_spec.light_sync_state { | 81 | | // TODO: this "4" constant is repeated | 82 | 0 | light_sync_state.decode(client_spec.block_number_bytes.unwrap_or(4).into())?; | 83 | 19 | } | 84 | | | 85 | 19 | Ok(ChainSpec { client_spec }) | 86 | 19 | } |
|
87 | | |
88 | | /// Turns this chain specification into a JSON document representing it. |
89 | 0 | pub fn serialize(&self) -> String { |
90 | 0 | // Can only panic in case of a bug in this module. |
91 | 0 | serde_json::to_string_pretty(&self.client_spec).unwrap() |
92 | 0 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec9serialize Unexecuted instantiation: _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec9serialize |
93 | | |
94 | | /// Builds the [`ChainInformation`] corresponding to the genesis block contained in this chain |
95 | | /// spec. |
96 | | /// |
97 | | /// In addition to the information, also returns the virtual machine of the runtime of the |
98 | | /// genesis block. |
99 | 22 | pub fn to_chain_information( |
100 | 22 | &self, |
101 | 22 | ) -> Result<(ValidChainInformation, executor::host::HostVmPrototype), FromGenesisStorageError> |
102 | 22 | { |
103 | 22 | let genesis_storage = match self.genesis_storage() { |
104 | 22 | GenesisStorage::Items(items) => items, |
105 | | GenesisStorage::TrieRootHash(_) => { |
106 | 0 | return Err(FromGenesisStorageError::UnknownStorageItems) |
107 | | } |
108 | | }; |
109 | | |
110 | 22 | let wasm_code = genesis_storage |
111 | 22 | .value(b":code") |
112 | 22 | .ok_or(FromGenesisStorageError::RuntimeNotFound)?0 ; |
113 | 22 | let heap_pages = |
114 | 22 | executor::storage_heap_pages_to_value(genesis_storage.value(b":heappages")) |
115 | 22 | .map_err(FromGenesisStorageError::HeapPagesDecode)?0 ; |
116 | 22 | let vm_prototype = executor::host::HostVmPrototype::new(executor::host::Config { |
117 | 22 | module: &wasm_code, |
118 | 22 | heap_pages, |
119 | 22 | exec_hint: executor::vm::ExecHint::ValidateAndExecuteOnce, |
120 | 22 | allow_unresolved_imports: true, |
121 | 22 | }) |
122 | 22 | .map_err(FromGenesisStorageError::VmInitialization)?0 ; |
123 | | |
124 | 22 | let state_version = vm_prototype |
125 | 22 | .runtime_version() |
126 | 22 | .decode() |
127 | 22 | .state_version |
128 | 22 | .unwrap_or(trie::TrieEntryVersion::V0); |
129 | | |
130 | 22 | let mut chain_information_build = build::ChainInformationBuild::new(build::Config { |
131 | | finalized_block_header: build::ConfigFinalizedBlockHeader::Genesis { |
132 | | state_trie_root_hash: { |
133 | 22 | match self.genesis_storage() { |
134 | 0 | GenesisStorage::TrieRootHash(hash) => *hash, |
135 | 22 | GenesisStorage::Items(genesis_storage) => { |
136 | 22 | let mut calculation = |
137 | 22 | trie::calculate_root::root_merkle_value(trie::HashFunction::Blake2); |
138 | | |
139 | 20.5k | loop { |
140 | 20.5k | match calculation { |
141 | | trie::calculate_root::RootMerkleValueCalculation::Finished { |
142 | 22 | hash, |
143 | 22 | .. |
144 | 22 | } => break hash, |
145 | 19.4k | trie::calculate_root::RootMerkleValueCalculation::NextKey(next_key) => { |
146 | 19.4k | // TODO: borrowchecker erroneously thinks that `outcome` borrows `next_key` |
147 | 19.4k | let outcome = genesis_storage.next_key(next_key.key_before(), next_key.or_equal(), next_key.prefix()).map(|k| k.collect::<Vec<_>>().into_iter()3.21k ); _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec20to_chain_information0B6_ Line | Count | Source | 147 | 354 | let outcome = genesis_storage.next_key(next_key.key_before(), next_key.or_equal(), next_key.prefix()).map(|k| k.collect::<Vec<_>>().into_iter()); |
_RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec20to_chain_information0B6_ Line | Count | Source | 147 | 2.85k | let outcome = genesis_storage.next_key(next_key.key_before(), next_key.or_equal(), next_key.prefix()).map(|k| k.collect::<Vec<_>>().into_iter()); |
|
148 | 19.4k | calculation = next_key.inject_key(outcome); |
149 | 19.4k | } |
150 | | trie::calculate_root::RootMerkleValueCalculation::StorageValue( |
151 | 986 | val, |
152 | 986 | ) => { |
153 | 986 | let key: alloc::vec::Vec<u8> = val.key().collect(); |
154 | 986 | let value = genesis_storage.value(&key[..]); |
155 | 986 | calculation = val.inject(value.map(move |v| (v, state_version)823 )); _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec20to_chain_informations_0B6_ Line | Count | Source | 155 | 88 | calculation = val.inject(value.map(move |v| (v, state_version))); |
_RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec20to_chain_informations_0B6_ Line | Count | Source | 155 | 735 | calculation = val.inject(value.map(move |v| (v, state_version))); |
|
156 | 986 | } |
157 | | } |
158 | | } |
159 | | } |
160 | | } |
161 | | }, |
162 | | }, |
163 | 22 | block_number_bytes: usize::from(self.block_number_bytes()), |
164 | 22 | runtime: vm_prototype, |
165 | | }); |
166 | | |
167 | 22 | let (chain_info, vm_prototype) = loop { |
168 | 67 | match chain_information_build { |
169 | 45 | build::ChainInformationBuild::InProgress(build::InProgress::StorageGet(get)) => { |
170 | 45 | // TODO: child tries not supported |
171 | 45 | let value = genesis_storage.value(get.key().as_ref()); |
172 | 45 | chain_information_build = |
173 | 45 | get.inject_value(value.map(|v| (iter::once(v), state_version)44 )); _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec20to_chain_informations0_0B6_ Line | Count | Source | 173 | 2 | get.inject_value(value.map(|v| (iter::once(v), state_version))); |
_RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec20to_chain_informations0_0B6_ Line | Count | Source | 173 | 42 | get.inject_value(value.map(|v| (iter::once(v), state_version))); |
|
174 | 45 | } |
175 | 0 | build::ChainInformationBuild::InProgress(build::InProgress::NextKey(_nk)) => { |
176 | 0 | todo!() // TODO: |
177 | | } |
178 | | build::ChainInformationBuild::InProgress( |
179 | 0 | build::InProgress::ClosestDescendantMerkleValue(_mv), |
180 | 0 | ) => { |
181 | 0 | todo!() // TODO: |
182 | | } |
183 | | build::ChainInformationBuild::Finished { |
184 | 0 | result: Err(err), .. |
185 | 0 | } => { |
186 | 0 | return Err(FromGenesisStorageError::BuildChainInformation(err)); |
187 | | } |
188 | | build::ChainInformationBuild::Finished { |
189 | 22 | result: Ok(chain_info), |
190 | 22 | virtual_machine, |
191 | 22 | } => { |
192 | 22 | break (chain_info, virtual_machine); |
193 | 22 | } |
194 | 22 | } |
195 | 22 | }; |
196 | 22 | |
197 | 22 | Ok((chain_info, vm_prototype)) |
198 | 22 | } _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec20to_chain_information Line | Count | Source | 99 | 1 | pub fn to_chain_information( | 100 | 1 | &self, | 101 | 1 | ) -> Result<(ValidChainInformation, executor::host::HostVmPrototype), FromGenesisStorageError> | 102 | 1 | { | 103 | 1 | let genesis_storage = match self.genesis_storage() { | 104 | 1 | GenesisStorage::Items(items) => items, | 105 | | GenesisStorage::TrieRootHash(_) => { | 106 | 0 | return Err(FromGenesisStorageError::UnknownStorageItems) | 107 | | } | 108 | | }; | 109 | | | 110 | 1 | let wasm_code = genesis_storage | 111 | 1 | .value(b":code") | 112 | 1 | .ok_or(FromGenesisStorageError::RuntimeNotFound)?0 ; | 113 | 1 | let heap_pages = | 114 | 1 | executor::storage_heap_pages_to_value(genesis_storage.value(b":heappages")) | 115 | 1 | .map_err(FromGenesisStorageError::HeapPagesDecode)?0 ; | 116 | 1 | let vm_prototype = executor::host::HostVmPrototype::new(executor::host::Config { | 117 | 1 | module: &wasm_code, | 118 | 1 | heap_pages, | 119 | 1 | exec_hint: executor::vm::ExecHint::ValidateAndExecuteOnce, | 120 | 1 | allow_unresolved_imports: true, | 121 | 1 | }) | 122 | 1 | .map_err(FromGenesisStorageError::VmInitialization)?0 ; | 123 | | | 124 | 1 | let state_version = vm_prototype | 125 | 1 | .runtime_version() | 126 | 1 | .decode() | 127 | 1 | .state_version | 128 | 1 | .unwrap_or(trie::TrieEntryVersion::V0); | 129 | | | 130 | 1 | let mut chain_information_build = build::ChainInformationBuild::new(build::Config { | 131 | | finalized_block_header: build::ConfigFinalizedBlockHeader::Genesis { | 132 | | state_trie_root_hash: { | 133 | 1 | match self.genesis_storage() { | 134 | 0 | GenesisStorage::TrieRootHash(hash) => *hash, | 135 | 1 | GenesisStorage::Items(genesis_storage) => { | 136 | 1 | let mut calculation = | 137 | 1 | trie::calculate_root::root_merkle_value(trie::HashFunction::Blake2); | 138 | | | 139 | 2.14k | loop { | 140 | 2.14k | match calculation { | 141 | | trie::calculate_root::RootMerkleValueCalculation::Finished { | 142 | 1 | hash, | 143 | 1 | .. | 144 | 1 | } => break hash, | 145 | 2.04k | trie::calculate_root::RootMerkleValueCalculation::NextKey(next_key) => { | 146 | 2.04k | // TODO: borrowchecker erroneously thinks that `outcome` borrows `next_key` | 147 | 2.04k | let outcome = genesis_storage.next_key(next_key.key_before(), next_key.or_equal(), next_key.prefix()).map(|k| k.collect::<Vec<_>>().into_iter()); | 148 | 2.04k | calculation = next_key.inject_key(outcome); | 149 | 2.04k | } | 150 | | trie::calculate_root::RootMerkleValueCalculation::StorageValue( | 151 | 104 | val, | 152 | 104 | ) => { | 153 | 104 | let key: alloc::vec::Vec<u8> = val.key().collect(); | 154 | 104 | let value = genesis_storage.value(&key[..]); | 155 | 104 | calculation = val.inject(value.map(move |v| (v, state_version))); | 156 | 104 | } | 157 | | } | 158 | | } | 159 | | } | 160 | | } | 161 | | }, | 162 | | }, | 163 | 1 | block_number_bytes: usize::from(self.block_number_bytes()), | 164 | 1 | runtime: vm_prototype, | 165 | | }); | 166 | | | 167 | 1 | let (chain_info, vm_prototype) = loop { | 168 | 4 | match chain_information_build { | 169 | 3 | build::ChainInformationBuild::InProgress(build::InProgress::StorageGet(get)) => { | 170 | 3 | // TODO: child tries not supported | 171 | 3 | let value = genesis_storage.value(get.key().as_ref()); | 172 | 3 | chain_information_build = | 173 | 3 | get.inject_value(value.map(|v| (iter::once(v), state_version))); | 174 | 3 | } | 175 | 0 | build::ChainInformationBuild::InProgress(build::InProgress::NextKey(_nk)) => { | 176 | 0 | todo!() // TODO: | 177 | | } | 178 | | build::ChainInformationBuild::InProgress( | 179 | 0 | build::InProgress::ClosestDescendantMerkleValue(_mv), | 180 | 0 | ) => { | 181 | 0 | todo!() // TODO: | 182 | | } | 183 | | build::ChainInformationBuild::Finished { | 184 | 0 | result: Err(err), .. | 185 | 0 | } => { | 186 | 0 | return Err(FromGenesisStorageError::BuildChainInformation(err)); | 187 | | } | 188 | | build::ChainInformationBuild::Finished { | 189 | 1 | result: Ok(chain_info), | 190 | 1 | virtual_machine, | 191 | 1 | } => { | 192 | 1 | break (chain_info, virtual_machine); | 193 | 1 | } | 194 | 1 | } | 195 | 1 | }; | 196 | 1 | | 197 | 1 | Ok((chain_info, vm_prototype)) | 198 | 1 | } |
_RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec20to_chain_information Line | Count | Source | 99 | 21 | pub fn to_chain_information( | 100 | 21 | &self, | 101 | 21 | ) -> Result<(ValidChainInformation, executor::host::HostVmPrototype), FromGenesisStorageError> | 102 | 21 | { | 103 | 21 | let genesis_storage = match self.genesis_storage() { | 104 | 21 | GenesisStorage::Items(items) => items, | 105 | | GenesisStorage::TrieRootHash(_) => { | 106 | 0 | return Err(FromGenesisStorageError::UnknownStorageItems) | 107 | | } | 108 | | }; | 109 | | | 110 | 21 | let wasm_code = genesis_storage | 111 | 21 | .value(b":code") | 112 | 21 | .ok_or(FromGenesisStorageError::RuntimeNotFound)?0 ; | 113 | 21 | let heap_pages = | 114 | 21 | executor::storage_heap_pages_to_value(genesis_storage.value(b":heappages")) | 115 | 21 | .map_err(FromGenesisStorageError::HeapPagesDecode)?0 ; | 116 | 21 | let vm_prototype = executor::host::HostVmPrototype::new(executor::host::Config { | 117 | 21 | module: &wasm_code, | 118 | 21 | heap_pages, | 119 | 21 | exec_hint: executor::vm::ExecHint::ValidateAndExecuteOnce, | 120 | 21 | allow_unresolved_imports: true, | 121 | 21 | }) | 122 | 21 | .map_err(FromGenesisStorageError::VmInitialization)?0 ; | 123 | | | 124 | 21 | let state_version = vm_prototype | 125 | 21 | .runtime_version() | 126 | 21 | .decode() | 127 | 21 | .state_version | 128 | 21 | .unwrap_or(trie::TrieEntryVersion::V0); | 129 | | | 130 | 21 | let mut chain_information_build = build::ChainInformationBuild::new(build::Config { | 131 | | finalized_block_header: build::ConfigFinalizedBlockHeader::Genesis { | 132 | | state_trie_root_hash: { | 133 | 21 | match self.genesis_storage() { | 134 | 0 | GenesisStorage::TrieRootHash(hash) => *hash, | 135 | 21 | GenesisStorage::Items(genesis_storage) => { | 136 | 21 | let mut calculation = | 137 | 21 | trie::calculate_root::root_merkle_value(trie::HashFunction::Blake2); | 138 | | | 139 | 18.3k | loop { | 140 | 18.3k | match calculation { | 141 | | trie::calculate_root::RootMerkleValueCalculation::Finished { | 142 | 21 | hash, | 143 | 21 | .. | 144 | 21 | } => break hash, | 145 | 17.4k | trie::calculate_root::RootMerkleValueCalculation::NextKey(next_key) => { | 146 | 17.4k | // TODO: borrowchecker erroneously thinks that `outcome` borrows `next_key` | 147 | 17.4k | let outcome = genesis_storage.next_key(next_key.key_before(), next_key.or_equal(), next_key.prefix()).map(|k| k.collect::<Vec<_>>().into_iter()); | 148 | 17.4k | calculation = next_key.inject_key(outcome); | 149 | 17.4k | } | 150 | | trie::calculate_root::RootMerkleValueCalculation::StorageValue( | 151 | 882 | val, | 152 | 882 | ) => { | 153 | 882 | let key: alloc::vec::Vec<u8> = val.key().collect(); | 154 | 882 | let value = genesis_storage.value(&key[..]); | 155 | 882 | calculation = val.inject(value.map(move |v| (v, state_version))); | 156 | 882 | } | 157 | | } | 158 | | } | 159 | | } | 160 | | } | 161 | | }, | 162 | | }, | 163 | 21 | block_number_bytes: usize::from(self.block_number_bytes()), | 164 | 21 | runtime: vm_prototype, | 165 | | }); | 166 | | | 167 | 21 | let (chain_info, vm_prototype) = loop { | 168 | 63 | match chain_information_build { | 169 | 42 | build::ChainInformationBuild::InProgress(build::InProgress::StorageGet(get)) => { | 170 | 42 | // TODO: child tries not supported | 171 | 42 | let value = genesis_storage.value(get.key().as_ref()); | 172 | 42 | chain_information_build = | 173 | 42 | get.inject_value(value.map(|v| (iter::once(v), state_version))); | 174 | 42 | } | 175 | 0 | build::ChainInformationBuild::InProgress(build::InProgress::NextKey(_nk)) => { | 176 | 0 | todo!() // TODO: | 177 | | } | 178 | | build::ChainInformationBuild::InProgress( | 179 | 0 | build::InProgress::ClosestDescendantMerkleValue(_mv), | 180 | 0 | ) => { | 181 | 0 | todo!() // TODO: | 182 | | } | 183 | | build::ChainInformationBuild::Finished { | 184 | 0 | result: Err(err), .. | 185 | 0 | } => { | 186 | 0 | return Err(FromGenesisStorageError::BuildChainInformation(err)); | 187 | | } | 188 | | build::ChainInformationBuild::Finished { | 189 | 21 | result: Ok(chain_info), | 190 | 21 | virtual_machine, | 191 | 21 | } => { | 192 | 21 | break (chain_info, virtual_machine); | 193 | 21 | } | 194 | 21 | } | 195 | 21 | }; | 196 | 21 | | 197 | 21 | Ok((chain_info, vm_prototype)) | 198 | 21 | } |
|
199 | | |
200 | | /// Returns the name of the chain. Meant to be displayed to the user. |
201 | 21 | pub fn name(&self) -> &str { |
202 | 21 | &self.client_spec.name |
203 | 21 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec4name _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec4name Line | Count | Source | 201 | 21 | pub fn name(&self) -> &str { | 202 | 21 | &self.client_spec.name | 203 | 21 | } |
|
204 | | |
205 | | /// Returns the identifier of the chain. Similar to the name, but a bit more "system-looking". |
206 | | /// For example, if the name is "Flaming Fir 7", then the id could be `flamingfir7`. To be |
207 | | /// used for example in file system paths. |
208 | 22 | pub fn id(&self) -> &str { |
209 | 22 | &self.client_spec.id |
210 | 22 | } _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec2id Line | Count | Source | 208 | 1 | pub fn id(&self) -> &str { | 209 | 1 | &self.client_spec.id | 210 | 1 | } |
_RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec2id Line | Count | Source | 208 | 21 | pub fn id(&self) -> &str { | 209 | 21 | &self.client_spec.id | 210 | 21 | } |
|
211 | | |
212 | | /// Returns a string indicating the type of chain. |
213 | | /// |
214 | | /// This value doesn't have any meaning in the absolute and is only meant to be shown to |
215 | | /// the user. |
216 | 21 | pub fn chain_type(&self) -> &str { |
217 | 21 | match &self.client_spec.chain_type { |
218 | 0 | structs::ChainType::Development => "Development", |
219 | 21 | structs::ChainType::Local => "Local", |
220 | 0 | structs::ChainType::Live => "Live", |
221 | 0 | structs::ChainType::Custom(ty) => ty, |
222 | | } |
223 | 21 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec10chain_type _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec10chain_type Line | Count | Source | 216 | 21 | pub fn chain_type(&self) -> &str { | 217 | 21 | match &self.client_spec.chain_type { | 218 | 0 | structs::ChainType::Development => "Development", | 219 | 21 | structs::ChainType::Local => "Local", | 220 | 0 | structs::ChainType::Live => "Live", | 221 | 0 | structs::ChainType::Custom(ty) => ty, | 222 | | } | 223 | 21 | } |
|
224 | | |
225 | | /// Returns the number of bytes that the "block number" field of various data structures uses. |
226 | 212 | pub fn block_number_bytes(&self) -> u8 { |
227 | 212 | self.client_spec.block_number_bytes.unwrap_or(4) |
228 | 212 | } _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec18block_number_bytes Line | Count | Source | 226 | 2 | pub fn block_number_bytes(&self) -> u8 { | 227 | 2 | self.client_spec.block_number_bytes.unwrap_or(4) | 228 | 2 | } |
_RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec18block_number_bytes Line | Count | Source | 226 | 210 | pub fn block_number_bytes(&self) -> u8 { | 227 | 210 | self.client_spec.block_number_bytes.unwrap_or(4) | 228 | 210 | } |
|
229 | | |
230 | | /// Returns true if the chain is of a type for which a live network is expected. |
231 | 21 | pub fn has_live_network(&self) -> bool { |
232 | 21 | match &self.client_spec.chain_type { |
233 | 0 | structs::ChainType::Development | structs::ChainType::Custom(_) => false, |
234 | 21 | structs::ChainType::Local | structs::ChainType::Live => true, |
235 | | } |
236 | 21 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec16has_live_network _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec16has_live_network Line | Count | Source | 231 | 21 | pub fn has_live_network(&self) -> bool { | 232 | 21 | match &self.client_spec.chain_type { | 233 | 0 | structs::ChainType::Development | structs::ChainType::Custom(_) => false, | 234 | 21 | structs::ChainType::Local | structs::ChainType::Live => true, | 235 | | } | 236 | 21 | } |
|
237 | | |
238 | | /// Returns a list of hashes of block headers that should always be considered as invalid. |
239 | 0 | pub fn bad_blocks_hashes(&'_ self) -> impl Iterator<Item = &'_ [u8; 32]> + '_ { |
240 | 0 | self.client_spec |
241 | 0 | .bad_blocks |
242 | 0 | .as_ref() |
243 | 0 | .into_iter() |
244 | 0 | .flat_map(|l| l.iter()) Unexecuted instantiation: _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec17bad_blocks_hashes0B6_ Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec17bad_blocks_hashes0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec17bad_blocks_hashes0B6_ |
245 | 0 | .map(|h| &h.0) Unexecuted instantiation: _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec17bad_blocks_hashess_0B6_ Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec17bad_blocks_hashess_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec17bad_blocks_hashess_0B6_ |
246 | 0 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec17bad_blocks_hashes Unexecuted instantiation: _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec17bad_blocks_hashes |
247 | | |
248 | | /// Returns the list of bootnode addresses found in the chain spec. |
249 | | /// |
250 | | /// Bootnode addresses that have failed to be parsed are returned as well in the form of |
251 | | /// a [`Bootnode::UnrecognizedFormat`]. |
252 | 43 | pub fn boot_nodes(&'_ self) -> impl ExactSizeIterator<Item = Bootnode<'_>> + '_ { |
253 | 43 | // Note that we intentionally don't expose types found in the `libp2p` module in order to |
254 | 43 | // not tie the code that parses chain specifications to the libp2p code. |
255 | 43 | self.client_spec.boot_nodes.iter().map(|unparsed| {3 |
256 | 3 | if let Ok(mut addr2 ) = unparsed.parse::<libp2p::Multiaddr>() { |
257 | 2 | if let Some(libp2p::multiaddr::Protocol::P2p(peer_id)) = addr.iter().last() { |
258 | 2 | if let Ok(peer_id) = |
259 | 2 | libp2p::peer_id::PeerId::from_bytes(peer_id.into_bytes().to_vec()) |
260 | | { |
261 | 2 | addr.pop(); |
262 | 2 | return Bootnode::Parsed { |
263 | 2 | multiaddr: addr.to_string(), |
264 | 2 | peer_id: peer_id.into_bytes(), |
265 | 2 | }; |
266 | 0 | } |
267 | 0 | } |
268 | 1 | } |
269 | | |
270 | 1 | Bootnode::UnrecognizedFormat(unparsed) |
271 | 43 | }3 ) _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec10boot_nodes0B6_ Line | Count | Source | 255 | 3 | self.client_spec.boot_nodes.iter().map(|unparsed| { | 256 | 3 | if let Ok(mut addr2 ) = unparsed.parse::<libp2p::Multiaddr>() { | 257 | 2 | if let Some(libp2p::multiaddr::Protocol::P2p(peer_id)) = addr.iter().last() { | 258 | 2 | if let Ok(peer_id) = | 259 | 2 | libp2p::peer_id::PeerId::from_bytes(peer_id.into_bytes().to_vec()) | 260 | | { | 261 | 2 | addr.pop(); | 262 | 2 | return Bootnode::Parsed { | 263 | 2 | multiaddr: addr.to_string(), | 264 | 2 | peer_id: peer_id.into_bytes(), | 265 | 2 | }; | 266 | 0 | } | 267 | 0 | } | 268 | 1 | } | 269 | | | 270 | 1 | Bootnode::UnrecognizedFormat(unparsed) | 271 | 3 | }) |
Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec10boot_nodes0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec10boot_nodes0B6_ Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec10boot_nodes0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec10boot_nodes0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec10boot_nodes0CsibGXYHQB8Ea_25json_rpc_general_requests |
272 | 43 | } _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec10boot_nodes Line | Count | Source | 252 | 1 | pub fn boot_nodes(&'_ self) -> impl ExactSizeIterator<Item = Bootnode<'_>> + '_ { | 253 | 1 | // Note that we intentionally don't expose types found in the `libp2p` module in order to | 254 | 1 | // not tie the code that parses chain specifications to the libp2p code. | 255 | 1 | self.client_spec.boot_nodes.iter().map(|unparsed| { | 256 | | if let Ok(mut addr) = unparsed.parse::<libp2p::Multiaddr>() { | 257 | | if let Some(libp2p::multiaddr::Protocol::P2p(peer_id)) = addr.iter().last() { | 258 | | if let Ok(peer_id) = | 259 | | libp2p::peer_id::PeerId::from_bytes(peer_id.into_bytes().to_vec()) | 260 | | { | 261 | | addr.pop(); | 262 | | return Bootnode::Parsed { | 263 | | multiaddr: addr.to_string(), | 264 | | peer_id: peer_id.into_bytes(), | 265 | | }; | 266 | | } | 267 | | } | 268 | | } | 269 | | | 270 | | Bootnode::UnrecognizedFormat(unparsed) | 271 | 1 | }) | 272 | 1 | } |
_RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec10boot_nodes Line | Count | Source | 252 | 42 | pub fn boot_nodes(&'_ self) -> impl ExactSizeIterator<Item = Bootnode<'_>> + '_ { | 253 | 42 | // Note that we intentionally don't expose types found in the `libp2p` module in order to | 254 | 42 | // not tie the code that parses chain specifications to the libp2p code. | 255 | 42 | self.client_spec.boot_nodes.iter().map(|unparsed| { | 256 | | if let Ok(mut addr) = unparsed.parse::<libp2p::Multiaddr>() { | 257 | | if let Some(libp2p::multiaddr::Protocol::P2p(peer_id)) = addr.iter().last() { | 258 | | if let Ok(peer_id) = | 259 | | libp2p::peer_id::PeerId::from_bytes(peer_id.into_bytes().to_vec()) | 260 | | { | 261 | | addr.pop(); | 262 | | return Bootnode::Parsed { | 263 | | multiaddr: addr.to_string(), | 264 | | peer_id: peer_id.into_bytes(), | 265 | | }; | 266 | | } | 267 | | } | 268 | | } | 269 | | | 270 | | Bootnode::UnrecognizedFormat(unparsed) | 271 | 42 | }) | 272 | 42 | } |
|
273 | | |
274 | | /// Returns the list of libp2p multiaddresses of the default telemetry servers of the chain. |
275 | | // TODO: more strongly typed? |
276 | 21 | pub fn telemetry_endpoints(&'_ self) -> impl Iterator<Item = impl AsRef<str> + '_> + '_ { |
277 | 21 | self.client_spec |
278 | 21 | .telemetry_endpoints |
279 | 21 | .as_ref() |
280 | 21 | .into_iter() |
281 | 21 | .flat_map(|ep| ep.iter().map(0 |e| &e.00 )0 ) Unexecuted instantiation: _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec19telemetry_endpoints0B6_ Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec19telemetry_endpoints0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec19telemetry_endpoints0B6_ Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec19telemetry_endpoints0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec19telemetry_endpoints0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec19telemetry_endpoints0CsibGXYHQB8Ea_25json_rpc_general_requests Unexecuted instantiation: _RNCNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB6_9ChainSpec19telemetry_endpoints00B8_ Unexecuted instantiation: _RNCNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB6_9ChainSpec19telemetry_endpoints00CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB6_9ChainSpec19telemetry_endpoints00B8_ Unexecuted instantiation: _RNCNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB6_9ChainSpec19telemetry_endpoints00CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB6_9ChainSpec19telemetry_endpoints00CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB6_9ChainSpec19telemetry_endpoints00CsibGXYHQB8Ea_25json_rpc_general_requests |
282 | 21 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec19telemetry_endpoints _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec19telemetry_endpoints Line | Count | Source | 276 | 21 | pub fn telemetry_endpoints(&'_ self) -> impl Iterator<Item = impl AsRef<str> + '_> + '_ { | 277 | 21 | self.client_spec | 278 | 21 | .telemetry_endpoints | 279 | 21 | .as_ref() | 280 | 21 | .into_iter() | 281 | 21 | .flat_map(|ep| ep.iter().map(|e| &e.0)) | 282 | 21 | } |
|
283 | | |
284 | | /// Returns the network protocol id that uniquely identifies a chain. Used to prevent nodes |
285 | | /// from different blockchain networks from accidentally connecting to each other. |
286 | | /// |
287 | | /// It is possible for the JSON chain specs to not specify any protocol id, in which case a |
288 | | /// default value is returned. |
289 | | /// |
290 | | /// > **Note**: This mechanism is legacy and no longer used. |
291 | 21 | pub fn protocol_id(&self) -> Option<&str> { |
292 | 21 | self.client_spec.protocol_id.as_deref() |
293 | 21 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec11protocol_id _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec11protocol_id Line | Count | Source | 291 | 21 | pub fn protocol_id(&self) -> Option<&str> { | 292 | 21 | self.client_spec.protocol_id.as_deref() | 293 | 21 | } |
|
294 | | |
295 | | /// Returns the "fork id" of the chain. This is arbitrary string that can be used in order to |
296 | | /// segregate nodes in case when multiple chains have the same genesis hash. Nodes should only |
297 | | /// synchronize with nodes that have the same "fork id". |
298 | 21 | pub fn fork_id(&self) -> Option<&str> { |
299 | 21 | self.client_spec.fork_id.as_deref() |
300 | 21 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec7fork_id _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec7fork_id Line | Count | Source | 298 | 21 | pub fn fork_id(&self) -> Option<&str> { | 299 | 21 | self.client_spec.fork_id.as_deref() | 300 | 21 | } |
|
301 | | |
302 | | // TODO: this API is probably unstable, as the meaning of the string is unclear |
303 | 0 | pub fn relay_chain(&self) -> Option<(&str, u32)> { |
304 | 0 | match ( |
305 | 0 | self.client_spec.relay_chain.as_ref(), |
306 | 0 | self.client_spec.para_id.as_ref(), |
307 | | ) { |
308 | 0 | (Some(r), Some(p)) => Some((r.as_str(), *p)), |
309 | 0 | _ => None, |
310 | | } |
311 | 0 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec11relay_chain Unexecuted instantiation: _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec11relay_chain |
312 | | |
313 | | /// Gives access to what is known about the storage of the genesis block of the chain. |
314 | 66 | pub fn genesis_storage(&self) -> GenesisStorage { |
315 | 66 | match &self.client_spec.genesis { |
316 | 66 | structs::Genesis::Raw(raw) => GenesisStorage::Items(GenesisStorageItems { raw }), |
317 | 0 | structs::Genesis::StateRootHash(hash) => GenesisStorage::TrieRootHash(&hash.0), |
318 | | } |
319 | 66 | } _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec15genesis_storage Line | Count | Source | 314 | 3 | pub fn genesis_storage(&self) -> GenesisStorage { | 315 | 3 | match &self.client_spec.genesis { | 316 | 3 | structs::Genesis::Raw(raw) => GenesisStorage::Items(GenesisStorageItems { raw }), | 317 | 0 | structs::Genesis::StateRootHash(hash) => GenesisStorage::TrieRootHash(&hash.0), | 318 | | } | 319 | 3 | } |
_RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec15genesis_storage Line | Count | Source | 314 | 63 | pub fn genesis_storage(&self) -> GenesisStorage { | 315 | 63 | match &self.client_spec.genesis { | 316 | 63 | structs::Genesis::Raw(raw) => GenesisStorage::Items(GenesisStorageItems { raw }), | 317 | 0 | structs::Genesis::StateRootHash(hash) => GenesisStorage::TrieRootHash(&hash.0), | 318 | | } | 319 | 63 | } |
|
320 | | |
321 | | /// Returns a list of arbitrary properties contained in the chain specs, such as the name of |
322 | | /// the token or the number of decimals. |
323 | | /// |
324 | | /// The value of these properties is never interpreted by the local node, but can be served |
325 | | /// to a UI. |
326 | | /// |
327 | | /// The returned value is a JSON-formatted map, for example `{"foo":"bar"}`. |
328 | 21 | pub fn properties(&self) -> &str { |
329 | 21 | self.client_spec |
330 | 21 | .properties |
331 | 21 | .as_ref() |
332 | 21 | .map_or("{}", |p| p.get()) Unexecuted instantiation: _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec10properties0B6_ _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec10properties0B6_ Line | Count | Source | 332 | 21 | .map_or("{}", |p| p.get()) |
|
333 | 21 | } Unexecuted instantiation: _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec10properties _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec10properties Line | Count | Source | 328 | 21 | pub fn properties(&self) -> &str { | 329 | 21 | self.client_spec | 330 | 21 | .properties | 331 | 21 | .as_ref() | 332 | 21 | .map_or("{}", |p| p.get()) | 333 | 21 | } |
|
334 | | |
335 | 1 | pub fn light_sync_state(&self) -> Option<LightSyncState> { |
336 | 1 | self.client_spec |
337 | 1 | .light_sync_state |
338 | 1 | .as_ref() |
339 | 1 | .map(|state| LightSyncState { |
340 | 1 | // We made sure at initialization that the decoding succeeds. |
341 | 1 | inner: state.decode(self.block_number_bytes().into()).unwrap(), |
342 | 1 | }) _RNCNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB4_9ChainSpec16light_sync_state0B6_ Line | Count | Source | 339 | 1 | .map(|state| LightSyncState { | 340 | 1 | // We made sure at initialization that the decoding succeeds. | 341 | 1 | inner: state.decode(self.block_number_bytes().into()).unwrap(), | 342 | 1 | }) |
Unexecuted instantiation: _RNCNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB4_9ChainSpec16light_sync_state0B6_ |
343 | 1 | } _RNvMNtCsN16ciHI6Qf_7smoldot10chain_specNtB2_9ChainSpec16light_sync_state Line | Count | Source | 335 | 1 | pub fn light_sync_state(&self) -> Option<LightSyncState> { | 336 | 1 | self.client_spec | 337 | 1 | .light_sync_state | 338 | 1 | .as_ref() | 339 | 1 | .map(|state| LightSyncState { | 340 | | // We made sure at initialization that the decoding succeeds. | 341 | | inner: state.decode(self.block_number_bytes().into()).unwrap(), | 342 | 1 | }) | 343 | 1 | } |
Unexecuted instantiation: _RNvMNtCseuYC0Zibziv_7smoldot10chain_specNtB2_9ChainSpec16light_sync_state |
344 | | } |
345 | | |
346 | | /// See [`ChainSpec::boot_nodes`]. |
347 | | #[derive(Debug, Clone, PartialEq, Eq)] |
348 | | pub enum Bootnode<'a> { |
349 | | /// The address of the bootnode is valid. |
350 | | Parsed { |
351 | | /// String representation of the multiaddress that can be used to reach the bootnode. |
352 | | /// |
353 | | /// Does *not* contain the trailing `/p2p/...`. |
354 | | multiaddr: String, |
355 | | |
356 | | /// Bytes representation of the libp2p peer id of the bootnode. |
357 | | /// |
358 | | /// The format can be found in the libp2p specification: |
359 | | /// <https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md> |
360 | | peer_id: Vec<u8>, |
361 | | }, |
362 | | |
363 | | /// The address of the bootnode couldn't be parsed. |
364 | | /// |
365 | | /// This could be due to the format being invalid, or to smoldot not supporting one of the |
366 | | /// multiaddress components that is being used. |
367 | | UnrecognizedFormat(&'a str), |
368 | | } |
369 | | |
370 | | /// See [`ChainSpec::genesis_storage`]. |
371 | | pub enum GenesisStorage<'a> { |
372 | | /// The items of the genesis storage are known. |
373 | | Items(GenesisStorageItems<'a>), |
374 | | /// The items of the genesis storage are unknown, but we know the hash of the root node |
375 | | /// of the trie. |
376 | | TrieRootHash(&'a [u8; 32]), |
377 | | } |
378 | | |
379 | | impl<'a> GenesisStorage<'a> { |
380 | | /// Returns `Some` for [`GenesisStorage::Items`], and `None` otherwise. |
381 | 1 | pub fn into_genesis_items(self) -> Option<GenesisStorageItems<'a>> { |
382 | 1 | match self { |
383 | 1 | GenesisStorage::Items(items) => Some(items), |
384 | 0 | GenesisStorage::TrieRootHash(_) => None, |
385 | | } |
386 | 1 | } _RNvMs_NtCsN16ciHI6Qf_7smoldot10chain_specNtB4_14GenesisStorage18into_genesis_items Line | Count | Source | 381 | 1 | pub fn into_genesis_items(self) -> Option<GenesisStorageItems<'a>> { | 382 | 1 | match self { | 383 | 1 | GenesisStorage::Items(items) => Some(items), | 384 | 0 | GenesisStorage::TrieRootHash(_) => None, | 385 | | } | 386 | 1 | } |
Unexecuted instantiation: _RNvMs_NtCseuYC0Zibziv_7smoldot10chain_specNtB4_14GenesisStorage18into_genesis_items |
387 | | |
388 | | /// Returns `Some` for [`GenesisStorage::TrieRootHash`], and `None` otherwise. |
389 | 0 | pub fn into_trie_root_hash(self) -> Option<&'a [u8; 32]> { |
390 | 0 | match self { |
391 | 0 | GenesisStorage::Items(_) => None, |
392 | 0 | GenesisStorage::TrieRootHash(hash) => Some(hash), |
393 | | } |
394 | 0 | } Unexecuted instantiation: _RNvMs_NtCsN16ciHI6Qf_7smoldot10chain_specNtB4_14GenesisStorage19into_trie_root_hash Unexecuted instantiation: _RNvMs_NtCseuYC0Zibziv_7smoldot10chain_specNtB4_14GenesisStorage19into_trie_root_hash |
395 | | } |
396 | | |
397 | | /// See [`GenesisStorage`]. |
398 | | pub struct GenesisStorageItems<'a> { |
399 | | raw: &'a structs::RawGenesis, |
400 | | } |
401 | | |
402 | | impl<'a> GenesisStorageItems<'a> { |
403 | | /// Returns the list of storage keys and values of the genesis block. |
404 | 2.50k | pub fn iter(&self) -> impl ExactSizeIterator<Item = (&[u8], &[u8])> + Clone { |
405 | 216k | self.raw.top.iter().map(|(k, v)| (&k.0[..], &v.0[..])) _RNCNvMs0_NtCsN16ciHI6Qf_7smoldot10chain_specNtB7_19GenesisStorageItems4iter0B9_ Line | Count | Source | 405 | 215k | self.raw.top.iter().map(|(k, v)| (&k.0[..], &v.0[..])) |
Unexecuted instantiation: _RNCNvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_19GenesisStorageItems4iter0B9_ _RNCNvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_19GenesisStorageItems4iter0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 405 | 70 | self.raw.top.iter().map(|(k, v)| (&k.0[..], &v.0[..])) |
Unexecuted instantiation: _RNCNvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_19GenesisStorageItems4iter0CscDgN54JpMGG_6author _RNCNvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_19GenesisStorageItems4iter0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 405 | 665 | self.raw.top.iter().map(|(k, v)| (&k.0[..], &v.0[..])) |
|
406 | 2.50k | } _RNvMs0_NtCsN16ciHI6Qf_7smoldot10chain_specNtB5_19GenesisStorageItems4iter Line | Count | Source | 404 | 2.50k | pub fn iter(&self) -> impl ExactSizeIterator<Item = (&[u8], &[u8])> + Clone { | 405 | 2.50k | self.raw.top.iter().map(|(k, v)| (&k.0[..], &v.0[..])) | 406 | 2.50k | } |
Unexecuted instantiation: _RNvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB5_19GenesisStorageItems4iter |
407 | | |
408 | | /// Find the storage key that immediately follows `key_before` in the list of storage items. |
409 | | /// |
410 | | /// If `or_equal` is `true`, then `key_before` is returned if it corresponds to a key in the |
411 | | /// storage. |
412 | | /// |
413 | | /// Returns `None` if no next key could be found, or if the next key doesn't start with the |
414 | | /// given prefix. |
415 | 19.4k | pub fn next_key( |
416 | 19.4k | &self, |
417 | 19.4k | key_before: impl Iterator<Item = u8>, |
418 | 19.4k | or_equal: bool, |
419 | 19.4k | prefix: impl Iterator<Item = u8>, |
420 | 19.4k | ) -> Option<impl Iterator<Item = u8> + 'a> { |
421 | 19.4k | let lower_bound = if or_equal { |
422 | 19.4k | Bound::Included(structs::HexString(key_before.collect::<Vec<_>>())) |
423 | | } else { |
424 | 0 | Bound::Excluded(structs::HexString(key_before.collect::<Vec<_>>())) |
425 | | }; |
426 | | |
427 | 19.4k | self.raw |
428 | 19.4k | .top |
429 | 19.4k | .range((lower_bound, Bound::Unbounded)) |
430 | 19.4k | .next() |
431 | 303k | .filter(|(k, _)| k.0.iter().copied().zip(prefix).all(19.1k |(a, b)| a == b)19.1k ) _RNCINvMs0_NtCsN16ciHI6Qf_7smoldot10chain_specNtB8_19GenesisStorageItems8next_keyINtNvNtNtBa_4trie6nibble30nibbles_to_bytes_suffix_extend4IterINtCs1qmLyiTSqYF_6either6EitherINtNtNtNtCsaYZPK01V26L_4core4iter8adapters6copied6CopiedINtNtNtB2T_5slice4iter4IterNtB1l_6NibbleEEINtNtB2P_5chain5ChainIB2L_INtNtB2P_4take4TakeB3E_EEINtNtNtB2R_7sources4once4OnceB45_EEEEINtNvB1l_25nibbles_to_bytes_truncate4IterB2K_EE0Ba_ Line | Count | Source | 431 | 2.02k | .filter(|(k, _)| k.0.iter().copied().zip(prefix).all(|(a, b)| a == b)) |
_RNCINvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB8_19GenesisStorageItems8next_keyINtNvNtNtBa_4trie6nibble30nibbles_to_bytes_suffix_extend4IterINtCs1qmLyiTSqYF_6either6EitherINtNtNtNtCsaYZPK01V26L_4core4iter8adapters6copied6CopiedINtNtNtB2U_5slice4iter4IterNtB1m_6NibbleEEINtNtB2Q_5chain5ChainIB2M_INtNtB2Q_4take4TakeB3F_EEINtNtNtB2S_7sources4once4OnceB46_EEEEINtNvB1m_25nibbles_to_bytes_truncate4IterB2L_EE0Ba_ Line | Count | Source | 431 | 17.0k | .filter(|(k, _)| k.0.iter().copied().zip(prefix).all(|(a, b)| a == b)) |
_RNCNCINvMs0_NtCsN16ciHI6Qf_7smoldot10chain_specNtBa_19GenesisStorageItems8next_keyINtNvNtNtBc_4trie6nibble30nibbles_to_bytes_suffix_extend4IterINtCs1qmLyiTSqYF_6either6EitherINtNtNtNtCsaYZPK01V26L_4core4iter8adapters6copied6CopiedINtNtNtB2V_5slice4iter4IterNtB1n_6NibbleEEINtNtB2R_5chain5ChainIB2N_INtNtB2R_4take4TakeB3G_EEINtNtNtB2T_7sources4once4OnceB47_EEEEINtNvB1n_25nibbles_to_bytes_truncate4IterB2M_EE00Bc_ Line | Count | Source | 431 | 35.7k | .filter(|(k, _)| k.0.iter().copied().zip(prefix).all(|(a, b)| a == b)) |
_RNCNCINvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtBa_19GenesisStorageItems8next_keyINtNvNtNtBc_4trie6nibble30nibbles_to_bytes_suffix_extend4IterINtCs1qmLyiTSqYF_6either6EitherINtNtNtNtCsaYZPK01V26L_4core4iter8adapters6copied6CopiedINtNtNtB2W_5slice4iter4IterNtB1o_6NibbleEEINtNtB2S_5chain5ChainIB2O_INtNtB2S_4take4TakeB3H_EEINtNtNtB2U_7sources4once4OnceB48_EEEEINtNvB1o_25nibbles_to_bytes_truncate4IterB2N_EE00Bc_ Line | Count | Source | 431 | 267k | .filter(|(k, _)| k.0.iter().copied().zip(prefix).all(|(a, b)| a == b)) |
|
432 | 19.4k | .map(|(k, _)| k.0.iter().copied()3.21k ) _RNCINvMs0_NtCsN16ciHI6Qf_7smoldot10chain_specNtB8_19GenesisStorageItems8next_keyINtNvNtNtBa_4trie6nibble30nibbles_to_bytes_suffix_extend4IterINtCs1qmLyiTSqYF_6either6EitherINtNtNtNtCsaYZPK01V26L_4core4iter8adapters6copied6CopiedINtNtNtB2T_5slice4iter4IterNtB1l_6NibbleEEINtNtB2P_5chain5ChainIB2L_INtNtB2P_4take4TakeB3E_EEINtNtNtB2R_7sources4once4OnceB45_EEEEINtNvB1l_25nibbles_to_bytes_truncate4IterB2K_EEs_0Ba_ Line | Count | Source | 432 | 354 | .map(|(k, _)| k.0.iter().copied()) |
_RNCINvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB8_19GenesisStorageItems8next_keyINtNvNtNtBa_4trie6nibble30nibbles_to_bytes_suffix_extend4IterINtCs1qmLyiTSqYF_6either6EitherINtNtNtNtCsaYZPK01V26L_4core4iter8adapters6copied6CopiedINtNtNtB2U_5slice4iter4IterNtB1m_6NibbleEEINtNtB2Q_5chain5ChainIB2M_INtNtB2Q_4take4TakeB3F_EEINtNtNtB2S_7sources4once4OnceB46_EEEEINtNvB1m_25nibbles_to_bytes_truncate4IterB2L_EEs_0Ba_ Line | Count | Source | 432 | 2.85k | .map(|(k, _)| k.0.iter().copied()) |
|
433 | 19.4k | } _RINvMs0_NtCsN16ciHI6Qf_7smoldot10chain_specNtB6_19GenesisStorageItems8next_keyINtNvNtNtB8_4trie6nibble30nibbles_to_bytes_suffix_extend4IterINtCs1qmLyiTSqYF_6either6EitherINtNtNtNtCsaYZPK01V26L_4core4iter8adapters6copied6CopiedINtNtNtB2R_5slice4iter4IterNtB1j_6NibbleEEINtNtB2N_5chain5ChainIB2J_INtNtB2N_4take4TakeB3C_EEINtNtNtB2P_7sources4once4OnceB43_EEEEINtNvB1j_25nibbles_to_bytes_truncate4IterB2I_EEB8_ Line | Count | Source | 415 | 2.04k | pub fn next_key( | 416 | 2.04k | &self, | 417 | 2.04k | key_before: impl Iterator<Item = u8>, | 418 | 2.04k | or_equal: bool, | 419 | 2.04k | prefix: impl Iterator<Item = u8>, | 420 | 2.04k | ) -> Option<impl Iterator<Item = u8> + 'a> { | 421 | 2.04k | let lower_bound = if or_equal { | 422 | 2.04k | Bound::Included(structs::HexString(key_before.collect::<Vec<_>>())) | 423 | | } else { | 424 | 0 | Bound::Excluded(structs::HexString(key_before.collect::<Vec<_>>())) | 425 | | }; | 426 | | | 427 | 2.04k | self.raw | 428 | 2.04k | .top | 429 | 2.04k | .range((lower_bound, Bound::Unbounded)) | 430 | 2.04k | .next() | 431 | 2.04k | .filter(|(k, _)| k.0.iter().copied().zip(prefix).all(|(a, b)| a == b)) | 432 | 2.04k | .map(|(k, _)| k.0.iter().copied()) | 433 | 2.04k | } |
_RINvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB6_19GenesisStorageItems8next_keyINtNvNtNtB8_4trie6nibble30nibbles_to_bytes_suffix_extend4IterINtCs1qmLyiTSqYF_6either6EitherINtNtNtNtCsaYZPK01V26L_4core4iter8adapters6copied6CopiedINtNtNtB2S_5slice4iter4IterNtB1k_6NibbleEEINtNtB2O_5chain5ChainIB2K_INtNtB2O_4take4TakeB3D_EEINtNtNtB2Q_7sources4once4OnceB44_EEEEINtNvB1k_25nibbles_to_bytes_truncate4IterB2J_EEB8_ Line | Count | Source | 415 | 17.4k | pub fn next_key( | 416 | 17.4k | &self, | 417 | 17.4k | key_before: impl Iterator<Item = u8>, | 418 | 17.4k | or_equal: bool, | 419 | 17.4k | prefix: impl Iterator<Item = u8>, | 420 | 17.4k | ) -> Option<impl Iterator<Item = u8> + 'a> { | 421 | 17.4k | let lower_bound = if or_equal { | 422 | 17.4k | Bound::Included(structs::HexString(key_before.collect::<Vec<_>>())) | 423 | | } else { | 424 | 0 | Bound::Excluded(structs::HexString(key_before.collect::<Vec<_>>())) | 425 | | }; | 426 | | | 427 | 17.4k | self.raw | 428 | 17.4k | .top | 429 | 17.4k | .range((lower_bound, Bound::Unbounded)) | 430 | 17.4k | .next() | 431 | 17.4k | .filter(|(k, _)| k.0.iter().copied().zip(prefix).all(|(a, b)| a == b)) | 432 | 17.4k | .map(|(k, _)| k.0.iter().copied()) | 433 | 17.4k | } |
|
434 | | |
435 | | /// Returns the genesis storage value for a specific key. |
436 | | /// |
437 | | /// Returns `None` if there is no value corresponding to that key. |
438 | 1.11k | pub fn value(&self, key: &[u8]) -> Option<&[u8]> { |
439 | 1.11k | self.raw.top.get(key).map(|value| &value.0[..]910 ) _RNCNvMs0_NtCsN16ciHI6Qf_7smoldot10chain_specNtB7_19GenesisStorageItems5value0B9_ Line | Count | Source | 439 | 91 | self.raw.top.get(key).map(|value| &value.0[..]) |
_RNCNvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_19GenesisStorageItems5value0B9_ Line | Count | Source | 439 | 819 | self.raw.top.get(key).map(|value| &value.0[..]) |
|
440 | 1.11k | } _RNvMs0_NtCsN16ciHI6Qf_7smoldot10chain_specNtB5_19GenesisStorageItems5value Line | Count | Source | 438 | 109 | pub fn value(&self, key: &[u8]) -> Option<&[u8]> { | 439 | 109 | self.raw.top.get(key).map(|value| &value.0[..]) | 440 | 109 | } |
_RNvMs0_NtCseuYC0Zibziv_7smoldot10chain_specNtB5_19GenesisStorageItems5value Line | Count | Source | 438 | 1.00k | pub fn value(&self, key: &[u8]) -> Option<&[u8]> { | 439 | 1.00k | self.raw.top.get(key).map(|value| &value.0[..]) | 440 | 1.00k | } |
|
441 | | } |
442 | | |
443 | | pub struct LightSyncState { |
444 | | inner: light_sync_state::DecodedLightSyncState, |
445 | | } |
446 | | |
447 | 0 | fn convert_epoch(epoch: &light_sync_state::BabeEpoch) -> Box<BabeEpochInformation> { |
448 | 0 | let epoch_authorities: Vec<_> = epoch |
449 | 0 | .authorities |
450 | 0 | .iter() |
451 | 0 | .map(|authority| crate::header::BabeAuthority { |
452 | 0 | public_key: authority.public_key, |
453 | 0 | weight: authority.weight, |
454 | 0 | }) Unexecuted instantiation: _RNCNvNtCsN16ciHI6Qf_7smoldot10chain_spec13convert_epoch0B5_ Unexecuted instantiation: _RNCNvNtCseuYC0Zibziv_7smoldot10chain_spec13convert_epoch0B5_ |
455 | 0 | .collect(); |
456 | 0 |
|
457 | 0 | Box::new(BabeEpochInformation { |
458 | 0 | epoch_index: epoch.epoch_index, |
459 | 0 | start_slot_number: Some(epoch.slot_number), |
460 | 0 | authorities: epoch_authorities, |
461 | 0 | randomness: epoch.randomness, |
462 | 0 | c: epoch.config.c, |
463 | 0 | allowed_slots: epoch.config.allowed_slots, |
464 | 0 | }) |
465 | 0 | } Unexecuted instantiation: _RNvNtCsN16ciHI6Qf_7smoldot10chain_spec13convert_epoch Unexecuted instantiation: _RNvNtCseuYC0Zibziv_7smoldot10chain_spec13convert_epoch |
466 | | |
467 | | impl LightSyncState { |
468 | 1 | pub fn to_chain_information( |
469 | 1 | &self, |
470 | 1 | ) -> Result<ValidChainInformation, CheckpointToChainInformationError> { |
471 | 1 | // TODO: this code is a bit of a shitshow when it comes to corner cases and should be cleaned up after https://github.com/paritytech/substrate/issues/11184 |
472 | 1 | |
473 | 1 | if self.inner.finalized_block_header.number == 0 { |
474 | 0 | return Err(CheckpointToChainInformationError::GenesisBlockCheckpoint); |
475 | 1 | } |
476 | 1 | |
477 | 1 | // Create a sorted list of all regular epochs that haven't been pruned from the sync state. |
478 | 1 | let mut epochs: Vec<_> = self |
479 | 1 | .inner |
480 | 1 | .babe_epoch_changes |
481 | 1 | .epochs |
482 | 1 | .iter() |
483 | 1 | .filter(|((_, block_num), _)| { |
484 | 1 | u64::from(*block_num) <= self.inner.finalized_block_header.number |
485 | 1 | }) _RNCNvMs1_NtCsN16ciHI6Qf_7smoldot10chain_specNtB7_14LightSyncState20to_chain_information0B9_ Line | Count | Source | 483 | 1 | .filter(|((_, block_num), _)| { | 484 | 1 | u64::from(*block_num) <= self.inner.finalized_block_header.number | 485 | 1 | }) |
Unexecuted instantiation: _RNCNvMs1_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_14LightSyncState20to_chain_information0B9_ |
486 | 1 | .filter_map(|((_, block_num), epoch)| match epoch { |
487 | 0 | light_sync_state::PersistedEpoch::Regular(epoch) => Some((block_num, epoch)), |
488 | 1 | _ => None, |
489 | 1 | }) _RNCNvMs1_NtCsN16ciHI6Qf_7smoldot10chain_specNtB7_14LightSyncState20to_chain_informations_0B9_ Line | Count | Source | 486 | 1 | .filter_map(|((_, block_num), epoch)| match epoch { | 487 | 0 | light_sync_state::PersistedEpoch::Regular(epoch) => Some((block_num, epoch)), | 488 | 1 | _ => None, | 489 | 1 | }) |
Unexecuted instantiation: _RNCNvMs1_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_14LightSyncState20to_chain_informations_0B9_ |
490 | 1 | .collect(); |
491 | 1 | |
492 | 1 | epochs.sort_unstable_by_key(|(&block_num, _)| block_num0 ); Unexecuted instantiation: _RNCNvMs1_NtCsN16ciHI6Qf_7smoldot10chain_specNtB7_14LightSyncState20to_chain_informations0_0B9_ Unexecuted instantiation: _RNCNvMs1_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_14LightSyncState20to_chain_informations0_0B9_ |
493 | 1 | |
494 | 1 | // TODO: it seems that multiple identical epochs can be found in the list ; figure out why Substrate does that and fix it |
495 | 1 | epochs.dedup_by_key(|(_, epoch)| epoch.epoch_index0 ); Unexecuted instantiation: _RNCNvMs1_NtCsN16ciHI6Qf_7smoldot10chain_specNtB7_14LightSyncState20to_chain_informations1_0B9_ Unexecuted instantiation: _RNCNvMs1_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_14LightSyncState20to_chain_informations1_0B9_ |
496 | 1 | |
497 | 1 | // Get the latest two epochs. |
498 | 1 | if epochs.len() < 2 { |
499 | 1 | return Err(CheckpointToChainInformationError::GenesisBlockCheckpoint); |
500 | 0 | } |
501 | 0 | let current_epoch = epochs[epochs.len() - 2].1; |
502 | 0 | let next_epoch = epochs[epochs.len() - 1].1; |
503 | 0 |
|
504 | 0 | ChainInformation { |
505 | 0 | finalized_block_header: Box::new(self.inner.finalized_block_header.clone()), |
506 | 0 | consensus: ChainInformationConsensus::Babe { |
507 | 0 | slots_per_epoch: NonZeroU64::new(next_epoch.duration) |
508 | 0 | .ok_or(CheckpointToChainInformationError::InvalidBabeSlotsPerEpoch)?, |
509 | 0 | finalized_block_epoch_information: Some(convert_epoch(current_epoch)), |
510 | 0 | finalized_next_epoch_transition: convert_epoch(next_epoch), |
511 | 0 | }, |
512 | 0 | finality: ChainInformationFinality::Grandpa { |
513 | 0 | after_finalized_block_authorities_set_id: self.inner.grandpa_authority_set.set_id, |
514 | 0 | finalized_triggered_authorities: { |
515 | 0 | self.inner |
516 | 0 | .grandpa_authority_set |
517 | 0 | .current_authorities |
518 | 0 | .iter() |
519 | 0 | .map(|authority| { |
520 | 0 | Ok(crate::header::GrandpaAuthority { |
521 | 0 | public_key: authority.public_key, |
522 | 0 | weight: NonZeroU64::new(authority.weight) |
523 | 0 | .ok_or(CheckpointToChainInformationError::InvalidGrandpaAuthorityWeight)?, |
524 | | }) |
525 | 0 | }) Unexecuted instantiation: _RNCNvMs1_NtCsN16ciHI6Qf_7smoldot10chain_specNtB7_14LightSyncState20to_chain_informations2_0B9_ Unexecuted instantiation: _RNCNvMs1_NtCseuYC0Zibziv_7smoldot10chain_specNtB7_14LightSyncState20to_chain_informations2_0B9_ |
526 | 0 | .collect::<Result<_, _>>()? |
527 | | }, |
528 | 0 | finalized_scheduled_change: None, // TODO: unimplemented |
529 | 0 | }, |
530 | 0 | } |
531 | 0 | .try_into() |
532 | 0 | .map_err(CheckpointToChainInformationError::InvalidData) |
533 | 1 | } _RNvMs1_NtCsN16ciHI6Qf_7smoldot10chain_specNtB5_14LightSyncState20to_chain_information Line | Count | Source | 468 | 1 | pub fn to_chain_information( | 469 | 1 | &self, | 470 | 1 | ) -> Result<ValidChainInformation, CheckpointToChainInformationError> { | 471 | 1 | // TODO: this code is a bit of a shitshow when it comes to corner cases and should be cleaned up after https://github.com/paritytech/substrate/issues/11184 | 472 | 1 | | 473 | 1 | if self.inner.finalized_block_header.number == 0 { | 474 | 0 | return Err(CheckpointToChainInformationError::GenesisBlockCheckpoint); | 475 | 1 | } | 476 | 1 | | 477 | 1 | // Create a sorted list of all regular epochs that haven't been pruned from the sync state. | 478 | 1 | let mut epochs: Vec<_> = self | 479 | 1 | .inner | 480 | 1 | .babe_epoch_changes | 481 | 1 | .epochs | 482 | 1 | .iter() | 483 | 1 | .filter(|((_, block_num), _)| { | 484 | | u64::from(*block_num) <= self.inner.finalized_block_header.number | 485 | 1 | }) | 486 | 1 | .filter_map(|((_, block_num), epoch)| match epoch { | 487 | | light_sync_state::PersistedEpoch::Regular(epoch) => Some((block_num, epoch)), | 488 | | _ => None, | 489 | 1 | }) | 490 | 1 | .collect(); | 491 | 1 | | 492 | 1 | epochs.sort_unstable_by_key(|(&block_num, _)| block_num); | 493 | 1 | | 494 | 1 | // TODO: it seems that multiple identical epochs can be found in the list ; figure out why Substrate does that and fix it | 495 | 1 | epochs.dedup_by_key(|(_, epoch)| epoch.epoch_index); | 496 | 1 | | 497 | 1 | // Get the latest two epochs. | 498 | 1 | if epochs.len() < 2 { | 499 | 1 | return Err(CheckpointToChainInformationError::GenesisBlockCheckpoint); | 500 | 0 | } | 501 | 0 | let current_epoch = epochs[epochs.len() - 2].1; | 502 | 0 | let next_epoch = epochs[epochs.len() - 1].1; | 503 | 0 |
| 504 | 0 | ChainInformation { | 505 | 0 | finalized_block_header: Box::new(self.inner.finalized_block_header.clone()), | 506 | 0 | consensus: ChainInformationConsensus::Babe { | 507 | 0 | slots_per_epoch: NonZeroU64::new(next_epoch.duration) | 508 | 0 | .ok_or(CheckpointToChainInformationError::InvalidBabeSlotsPerEpoch)?, | 509 | 0 | finalized_block_epoch_information: Some(convert_epoch(current_epoch)), | 510 | 0 | finalized_next_epoch_transition: convert_epoch(next_epoch), | 511 | 0 | }, | 512 | 0 | finality: ChainInformationFinality::Grandpa { | 513 | 0 | after_finalized_block_authorities_set_id: self.inner.grandpa_authority_set.set_id, | 514 | 0 | finalized_triggered_authorities: { | 515 | 0 | self.inner | 516 | 0 | .grandpa_authority_set | 517 | 0 | .current_authorities | 518 | 0 | .iter() | 519 | 0 | .map(|authority| { | 520 | | Ok(crate::header::GrandpaAuthority { | 521 | | public_key: authority.public_key, | 522 | | weight: NonZeroU64::new(authority.weight) | 523 | | .ok_or(CheckpointToChainInformationError::InvalidGrandpaAuthorityWeight)?, | 524 | | }) | 525 | 0 | }) | 526 | 0 | .collect::<Result<_, _>>()? | 527 | | }, | 528 | 0 | finalized_scheduled_change: None, // TODO: unimplemented | 529 | 0 | }, | 530 | 0 | } | 531 | 0 | .try_into() | 532 | 0 | .map_err(CheckpointToChainInformationError::InvalidData) | 533 | 1 | } |
Unexecuted instantiation: _RNvMs1_NtCseuYC0Zibziv_7smoldot10chain_specNtB5_14LightSyncState20to_chain_information |
534 | | } |
535 | | |
536 | | /// Error that can happen when parsing a chain spec JSON. |
537 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs9_NtCsN16ciHI6Qf_7smoldot10chain_specNtB5_10ParseErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs9_NtCseuYC0Zibziv_7smoldot10chain_specNtB5_10ParseErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
538 | | #[display(fmt = "Failed to parse chain spec")] |
539 | | pub struct ParseError(ParseErrorInner); |
540 | | |
541 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXsb_NtCsN16ciHI6Qf_7smoldot10chain_specNtB5_15ParseErrorInnerNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsb_NtCseuYC0Zibziv_7smoldot10chain_specNtB5_15ParseErrorInnerNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
542 | | enum ParseErrorInner { |
543 | | Serde(serde_json::Error), |
544 | | Other, |
545 | | } |
546 | | |
547 | | /// Error when building the chain information from the genesis storage. |
548 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXsd_NtCsN16ciHI6Qf_7smoldot10chain_specNtB5_23FromGenesisStorageErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsd_NtCseuYC0Zibziv_7smoldot10chain_specNtB5_23FromGenesisStorageErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
549 | | pub enum FromGenesisStorageError { |
550 | | /// Runtime couldn't be found in the storage. |
551 | | RuntimeNotFound, |
552 | | /// Error while building the chain information. |
553 | | #[display(fmt = "{_0}")] |
554 | | BuildChainInformation(build::Error), |
555 | | /// Failed to decode heap pages from the storage. |
556 | | #[display(fmt = "Failed to decode heap pages from the storage: {_0}")] |
557 | | HeapPagesDecode(executor::InvalidHeapPagesError), |
558 | | /// Error when initializing the virtual machine. |
559 | | #[display(fmt = "Error when initializing the virtual machine: {_0}")] |
560 | | VmInitialization(executor::host::NewErr), |
561 | | /// Chain specification doesn't contain the list of storage items. |
562 | | UnknownStorageItems, |
563 | | } |
564 | | |
565 | | /// Error when building the chain information corresponding to a checkpoint. |
566 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXsf_NtCsN16ciHI6Qf_7smoldot10chain_specNtB5_33CheckpointToChainInformationErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsf_NtCseuYC0Zibziv_7smoldot10chain_specNtB5_33CheckpointToChainInformationErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
567 | | pub enum CheckpointToChainInformationError { |
568 | | /// The checkpoint corresponds to the genesis block. |
569 | | GenesisBlockCheckpoint, |
570 | | /// Found a value of 0 for the number of Babe slots per epoch. |
571 | | InvalidBabeSlotsPerEpoch, |
572 | | /// Found a Grandpa authority with a weight of 0. |
573 | | InvalidGrandpaAuthorityWeight, |
574 | | /// Information found in the checkpoint is invalid. |
575 | | #[display(fmt = "{_0}")] |
576 | | InvalidData(ValidityError), |
577 | | } |