8 #include <boost/property_tree/json_parser.hpp> 10 #include <libp2p/multi/multiaddress.hpp> 11 #include <system_error> 19 case E::MISSING_ENTRY:
20 return "A required entry is missing in the config file";
21 case E::MISSING_PEER_ID:
22 return "Peer id is missing in a multiaddress provided in the config file";
24 return "Internal parser error";
25 case E::NOT_IMPLEMENTED:
26 return "Known entry name, but parsing not implemented";
28 return "Unknown error in ChainSpecImpl";
33 namespace pt = boost::property_tree;
36 const std::string &path) {
38 std::shared_ptr<ChainSpecImpl> config_storage{
new ChainSpecImpl};
40 std::make_shared<primitives::CodeSubstituteBlockIds>();
41 OUTCOME_TRY(config_storage->loadFromJson(path));
43 return config_storage;
47 const std::string &file_path) {
51 pt::read_json(file_path, tree);
52 }
catch (pt::json_parser_error &e) {
54 "Parser error: {}, line {}: {}", e.filename(), e.line(), e.message());
62 return outcome::success();
66 const boost::property_tree::ptree &tree) {
67 OUTCOME_TRY(
name,
ensure(
"name", tree.get_child_optional(
"name")));
70 OUTCOME_TRY(
id,
ensure(
"id", tree.get_child_optional(
"id")));
71 id_ =
id.get<std::string>(
"");
74 if (
auto entry = tree.get_child_optional(
"chainType"); entry.has_value()) {
78 "Field 'chainType' was not specified in the chain spec. 'Live' by " 83 auto telemetry_endpoints_opt =
84 tree.get_child_optional(
"telemetryEndpoints");
85 if (telemetry_endpoints_opt.has_value()
86 && telemetry_endpoints_opt.value().get<std::string>(
"") !=
"null") {
87 for (
auto &[_, endpoint] : telemetry_endpoints_opt.value()) {
88 if (
auto it = endpoint.begin(); endpoint.size() >= 2) {
89 auto &uri = it->second;
90 auto &priority = (++it)->second;
92 priority.get<
size_t>(
""));
97 auto protocol_id_opt = tree.get_child_optional(
"protocolId");
98 if (protocol_id_opt.has_value()) {
99 auto protocol_id = protocol_id_opt.value().get<std::string>(
"");
100 if (protocol_id !=
"null") {
105 auto properties_opt = tree.get_child_optional(
"properties");
106 if (properties_opt.has_value()
107 && properties_opt.value().get<std::string>(
"") !=
"null") {
108 for (
auto &[propertyName, propertyValue] : properties_opt.value()) {
109 properties_.emplace(propertyName, propertyValue.get<std::string>(
""));
113 auto fork_blocks_opt = tree.get_child_optional(
"forkBlocks");
114 if (fork_blocks_opt.has_value()
115 && fork_blocks_opt.value().get<std::string>(
"") !=
"null") {
126 "A non-empty set of 'forkBlocks' encountered! They might not be " 127 "taken into account!");
128 for (
auto &[_, fork_block] : fork_blocks_opt.value()) {
131 fork_block.get<std::string>(
"")));
136 auto bad_blocks_opt = tree.get_child_optional(
"badBlocks");
137 if (bad_blocks_opt.has_value()
138 && bad_blocks_opt.value().get<std::string>(
"") !=
"null") {
149 "A non-empty set of 'badBlocks' encountered! They might not be " 150 "taken into account!");
151 for (
auto &[_, bad_block] : bad_blocks_opt.value()) {
154 bad_block.get<std::string>(
"")));
159 auto consensus_engine_opt = tree.get_child_optional(
"consensusEngine");
160 if (consensus_engine_opt.has_value()) {
161 auto consensus_engine = consensus_engine_opt.value().get<std::string>(
"");
162 if (consensus_engine !=
"null") {
167 auto code_substitutes_opt = tree.get_child_optional(
"codeSubstitutes");
168 if (code_substitutes_opt.has_value()) {
169 for (
const auto &[block_id, code] : code_substitutes_opt.value()) {
175 return outcome::success();
179 const std::string_view block_id_str)
const {
181 if (block_id_str.rfind(
"0x", 0) != std::string::npos) {
183 block_id = block_hash;
186 auto res = std::from_chars(block_id_str.data(),
187 block_id_str.data() + block_id_str.size(),
189 if (res.ec != std::errc()) {
192 block_id = block_num;
206 }
catch (pt::json_parser_error &e) {
208 "Parser error: {}, line {}: {}", e.filename(), e.line(), e.message());
212 auto code_substitutes_opt = tree.get_child_optional(
"codeSubstitutes");
213 if (code_substitutes_opt.has_value()) {
214 for (
const auto &[_block_id, _code] : code_substitutes_opt.value()) {
219 return arg == block_info.
number;
222 return arg == block_info.
hash;
225 return outcome::success(code_processed);
233 const boost::property_tree::ptree &tree) {
234 OUTCOME_TRY(genesis_tree,
235 ensure(
"genesis", tree.get_child_optional(
"genesis")));
236 OUTCOME_TRY(genesis_raw_tree,
237 ensure(
"genesis/raw", genesis_tree.get_child_optional(
"raw")));
238 boost::property_tree::ptree top_tree;
240 if (
auto top_tree_opt = genesis_raw_tree.get_child_optional(
"top");
241 top_tree_opt.has_value()) {
242 top_tree = top_tree_opt.value();
245 top_tree = genesis_raw_tree.begin()->second;
248 auto read_key_block = [](
const auto &tree,
250 for (
const auto &[child_key, child_value] : tree) {
254 data.emplace_back(std::move(key_processed), std::move(value_processed));
256 return outcome::success();
259 if (
auto children_default_tree_opt =
260 genesis_raw_tree.get_child_optional(
"childrenDefault");
261 children_default_tree_opt.has_value()) {
262 for (
const auto &[key, value] : children_default_tree_opt.value()) {
264 OUTCOME_TRY(read_key_block(value, child));
267 log_->trace(
"Child address {} added", key);
271 OUTCOME_TRY(read_key_block(top_tree,
genesis_));
273 return outcome::success();
277 const boost::property_tree::ptree &tree) {
278 OUTCOME_TRY(boot_nodes,
279 ensure(
"bootNodes", tree.get_child_optional(
"bootNodes")));
280 for (
auto &v : boot_nodes) {
281 if (
auto ma_res = libp2p::multi::Multiaddress::create(v.second.data())) {
282 auto &&multiaddr = ma_res.value();
283 if (
auto peer_id_base58 = multiaddr.getPeerId();
284 peer_id_base58.has_value()) {
285 OUTCOME_TRY(libp2p::peer::PeerId::fromBase58(peer_id_base58.value()));
291 log_->warn(
"Unsupported multiaddress '{}'. Ignoring that boot node",
295 return outcome::success();
std::shared_ptr< primitives::CodeSubstituteBlockIds > known_code_substitutes_
std::vector< libp2p::multi::Multiaddress > boot_nodes_
std::map< std::string, std::string > properties_
outcome::result< void > loadFromJson(const std::string &file_path)
outcome::result< primitives::BlockId > parseBlockId(const std::string_view block_id_str) const
outcome::result< std::vector< uint8_t > > unhexWith0x(std::string_view hex_with_prefix)
Unhex hex-string with 0x in the begining.
outcome::result< common::Buffer > fetchCodeSubstituteByBlockInfo(const primitives::BlockInfo &block_info) const override
std::vector< std::pair< std::string, size_t > > telemetry_endpoints_
OUTCOME_CPP_DEFINE_CATEGORY(kagome::application, ChainSpecImpl::Error, e)
ChildrenDefaultRawData children_default_
static outcome::result< std::shared_ptr< ChainSpecImpl > > loadFrom(const std::string &config_path)
outcome::result< void > loadFields(const boost::property_tree::ptree &tree)
std::set< primitives::BlockHash > fork_blocks_
std::vector< std::pair< common::Buffer, common::Buffer >> GenesisRawData
static outcome::result< Blob< size_ > > fromHexWithPrefix(std::string_view hex)
std::optional< std::string > consensus_engine_
std::set< primitives::BlockHash > bad_blocks_
outcome::result< void > loadGenesis(const boost::property_tree::ptree &tree)
boost::variant< BlockHash, BlockNumber > BlockId
Block id is the variant over BlockHash and BlockNumber.
outcome::result< void > loadBootNodes(const boost::property_tree::ptree &tree)
const std::string & name() const override
outcome::result< std::decay_t< T > > ensure(std::string_view entry_name, boost::optional< T > opt_entry)