fc_cli/frontier_db_cmd/
mod.rs

1// This file is part of Frontier.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19#![allow(clippy::result_large_err)]
20
21mod mapping_db;
22mod meta_db;
23#[cfg(test)]
24mod tests;
25pub(crate) mod utils;
26
27use std::{path::PathBuf, str::FromStr, sync::Arc};
28
29use clap::ValueEnum;
30use ethereum_types::H256;
31use serde::Deserialize;
32// Substrate
33use sc_cli::{PruningParams, SharedParams};
34use sp_api::ProvideRuntimeApi;
35use sp_blockchain::HeaderBackend;
36use sp_runtime::traits::Block as BlockT;
37
38use self::{
39	mapping_db::{MappingDb, MappingKey, MappingValue},
40	meta_db::{MetaDb, MetaKey, MetaValue},
41};
42
43/// Cli tool to interact with the Frontier backend db
44#[derive(Debug, Clone, clap::Parser)]
45pub struct FrontierDbCmd {
46	/// Specify the operation to perform.
47	///
48	/// Can be one of `create | read | update | delete`.
49	#[arg(value_enum, ignore_case = true, required = true)]
50	pub operation: Operation,
51
52	/// Specify the column to query.
53	///
54	/// Can be one of `meta | block | transaction`.
55	#[arg(value_enum, ignore_case = true, required = true)]
56	pub column: Column,
57
58	/// Specify the key to either read or write.
59	#[arg(short('k'), long, required = true)]
60	pub key: String,
61
62	/// Specify the value to write.
63	///
64	/// - When `Some`, path to file.
65	/// - When `None`, read from stdin.
66	///
67	/// In any case, payload must be serializable to a known type.
68	#[arg(long)]
69	pub value: Option<PathBuf>,
70
71	/// Shared parameters
72	#[command(flatten)]
73	pub shared_params: SharedParams,
74
75	#[allow(missing_docs)]
76	#[command(flatten)]
77	pub pruning_params: PruningParams,
78}
79
80#[derive(ValueEnum, Debug, Clone)]
81pub enum Operation {
82	Create,
83	Read,
84	Update,
85	Delete,
86}
87
88#[derive(ValueEnum, Debug, Clone)]
89pub enum Column {
90	Meta,
91	Block,
92	Transaction,
93}
94
95#[derive(Debug, Deserialize)]
96#[serde(untagged)]
97pub enum DbValue<H> {
98	Meta(MetaValue<H>),
99	Mapping(MappingValue<H>),
100}
101
102impl FrontierDbCmd {
103	pub fn run<B, C>(
104		&self,
105		client: Arc<C>,
106		backend: Arc<fc_db::kv::Backend<B, C>>,
107	) -> sc_cli::Result<()>
108	where
109		B: BlockT,
110		C: HeaderBackend<B> + ProvideRuntimeApi<B>,
111		C::Api: fp_rpc::EthereumRuntimeRPCApi<B>,
112	{
113		match self.column {
114			Column::Meta => {
115				// New meta db handler
116				let meta_db = MetaDb::new(self, backend);
117				// Maybe get a MetaKey
118				let key = MetaKey::from_str(&self.key)?;
119				// Maybe get a MetaValue
120				let value = match utils::maybe_deserialize_value::<B>(
121					&self.operation,
122					self.value.as_ref(),
123				)? {
124					Some(DbValue::Meta(value)) => Some(value),
125					None => None,
126					_ => return Err(format!("Unexpected `{:?}` value", self.value).into()),
127				};
128				// Run the query
129				meta_db.query(&key, &value)?
130			}
131			Column::Block | Column::Transaction => {
132				// New mapping db handler
133				let mapping_db = MappingDb::new(self, client, backend);
134				// Maybe get a MappingKey
135				let key = MappingKey::EthBlockOrTransactionHash(
136					H256::from_str(&self.key).expect("H256 provided key"),
137				);
138				// Maybe get a MappingValue
139				let value = match utils::maybe_deserialize_value::<B>(
140					&self.operation,
141					self.value.as_ref(),
142				)? {
143					Some(DbValue::Mapping(value)) => Some(value),
144					None => None,
145					_ => return Err(format!("Unexpected `{:?}` value", self.value).into()),
146				};
147				// Run the query
148				mapping_db.query(&self.column, &key, &value)?
149			}
150		}
151		Ok(())
152	}
153}
154
155impl sc_cli::CliConfiguration for FrontierDbCmd {
156	fn shared_params(&self) -> &SharedParams {
157		&self.shared_params
158	}
159
160	fn pruning_params(&self) -> Option<&PruningParams> {
161		Some(&self.pruning_params)
162	}
163}