referrerpolicy=no-referrer-when-downgrade

substrate_relay_helper/cli/
mod.rs

1// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Bridges Common is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Deal with CLI args of substrate-to-substrate relay.
18
19use clap::Parser;
20use rbtag::BuildInfo;
21use sp_runtime::traits::TryConvert;
22use std::str::FromStr;
23
24pub mod bridge;
25pub mod chain_schema;
26pub mod detect_equivocations;
27pub mod init_bridge;
28pub mod relay_headers;
29pub mod relay_headers_and_messages;
30pub mod relay_messages;
31pub mod relay_parachains;
32
33/// The target that will be used when publishing logs related to this pallet.
34pub const LOG_TARGET: &str = "bridge";
35
36/// Default Substrate client type that we are using. We'll use it all over the glue CLI code
37/// to avoid multiple level generic arguments and constraints. We still allow usage of other
38/// clients in the **core logic code**.
39pub type DefaultClient<C> = relay_substrate_client::RpcWithCachingClient<C>;
40
41/// Lane id.
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct HexLaneId(Vec<u8>);
44
45impl<T: TryFrom<Vec<u8>>> TryConvert<HexLaneId, T> for HexLaneId {
46	fn try_convert(lane_id: HexLaneId) -> Result<T, HexLaneId> {
47		T::try_from(lane_id.0.clone()).map_err(|_| lane_id)
48	}
49}
50
51impl FromStr for HexLaneId {
52	type Err = hex::FromHexError;
53
54	fn from_str(s: &str) -> Result<Self, Self::Err> {
55		hex::decode(s).map(Self)
56	}
57}
58
59/// Prometheus metrics params.
60#[derive(Clone, Debug, PartialEq, Parser)]
61pub struct PrometheusParams {
62	/// Do not expose a Prometheus metric endpoint.
63	#[arg(long)]
64	pub no_prometheus: bool,
65	/// Expose Prometheus endpoint at given interface.
66	#[arg(long, default_value = "127.0.0.1")]
67	pub prometheus_host: String,
68	/// Expose Prometheus endpoint at given port.
69	#[arg(long, default_value = "9616")]
70	pub prometheus_port: u16,
71}
72
73/// Struct to get git commit info and build time.
74#[derive(BuildInfo)]
75struct SubstrateRelayBuildInfo;
76
77impl SubstrateRelayBuildInfo {
78	/// Get git commit in form `<short-sha-(clean|dirty)>`.
79	pub fn get_git_commit() -> String {
80		// on gitlab we use images without git installed, so we can't use `rbtag` there
81		// locally we don't have `CI_*` env variables, so we can't rely on them
82		// => we are using `CI_*` env variables or else `rbtag`
83		let maybe_sha_from_ci = option_env!("CI_COMMIT_SHORT_SHA");
84		maybe_sha_from_ci
85			.map(|short_sha| {
86				// we assume that on CI the copy is always clean
87				format!("{short_sha}-clean")
88			})
89			.unwrap_or_else(|| SubstrateRelayBuildInfo.get_build_commit().into())
90	}
91}
92
93impl PrometheusParams {
94	/// Tries to convert CLI metrics params into metrics params, used by the relay.
95	pub fn into_metrics_params(self) -> anyhow::Result<relay_utils::metrics::MetricsParams> {
96		let metrics_address = if !self.no_prometheus {
97			Some(relay_utils::metrics::MetricsAddress {
98				host: self.prometheus_host,
99				port: self.prometheus_port,
100			})
101		} else {
102			None
103		};
104
105		let relay_version = relay_utils::initialize::RELAYER_VERSION
106			.lock()
107			.clone()
108			.unwrap_or_else(|| "unknown".to_string());
109		let relay_commit = SubstrateRelayBuildInfo::get_git_commit();
110		relay_utils::metrics::MetricsParams::new(metrics_address, relay_version, relay_commit)
111			.map_err(|e| anyhow::format_err!("{:?}", e))
112	}
113}
114
115/// Either explicit or maximal allowed value.
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub enum ExplicitOrMaximal<V> {
118	/// User has explicitly specified argument value.
119	Explicit(V),
120	/// Maximal allowed value for this argument.
121	Maximal,
122}
123
124impl<V: std::str::FromStr> std::str::FromStr for ExplicitOrMaximal<V>
125where
126	V::Err: std::fmt::Debug,
127{
128	type Err = String;
129
130	fn from_str(s: &str) -> Result<Self, Self::Err> {
131		if s.to_lowercase() == "max" {
132			return Ok(ExplicitOrMaximal::Maximal)
133		}
134
135		V::from_str(s)
136			.map(ExplicitOrMaximal::Explicit)
137			.map_err(|e| format!("Failed to parse '{e:?}'. Expected 'max' or explicit value"))
138	}
139}
140
141#[cfg(test)]
142mod tests {
143	use super::*;
144	use bp_messages::{HashedLaneId, LegacyLaneId};
145	use sp_core::H256;
146
147	#[test]
148	fn hex_lane_id_from_str_works() {
149		// hash variant
150		assert!(HexLaneId::from_str(
151			"101010101010101010101010101010101010101010101010101010101010101"
152		)
153		.is_err());
154		assert!(HexLaneId::from_str(
155			"00101010101010101010101010101010101010101010101010101010101010101"
156		)
157		.is_err());
158		assert_eq!(
159			HexLaneId::try_convert(
160				HexLaneId::from_str(
161					"0101010101010101010101010101010101010101010101010101010101010101"
162				)
163				.unwrap()
164			),
165			Ok(HashedLaneId::from_inner(H256::from([1u8; 32])))
166		);
167
168		// array variant
169		assert!(HexLaneId::from_str("0000001").is_err());
170		assert!(HexLaneId::from_str("000000001").is_err());
171		assert_eq!(
172			HexLaneId::try_convert(HexLaneId::from_str("00000001").unwrap()),
173			Ok(LegacyLaneId([0, 0, 0, 1]))
174		);
175	}
176}