Coverage Report

Created: 2024-05-16 12:16

/__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
}