1// This file is part of Frontier.
23// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
56// 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.
1011// 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.
1516// 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/>.
1819#![allow(clippy::result_large_err)]
2021mod mapping_db;
22mod meta_db;
23#[cfg(test)]
24mod tests;
25pub(crate) mod utils;
2627use std::{path::PathBuf, str::FromStr, sync::Arc};
2829use 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;
3738use self::{
39 mapping_db::{MappingDb, MappingKey, MappingValue},
40 meta_db::{MetaDb, MetaKey, MetaValue},
41};
4243/// 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)]
50pub operation: Operation,
5152/// Specify the column to query.
53 ///
54 /// Can be one of `meta | block | transaction`.
55#[arg(value_enum, ignore_case = true, required = true)]
56pub column: Column,
5758/// Specify the key to either read or write.
59#[arg(short('k'), long, required = true)]
60pub key: String,
6162/// 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)]
69pub value: Option<PathBuf>,
7071/// Shared parameters
72#[command(flatten)]
73pub shared_params: SharedParams,
7475#[allow(missing_docs)]
76 #[command(flatten)]
77pub pruning_params: PruningParams,
78}
7980#[derive(ValueEnum, Debug, Clone)]
81pub enum Operation {
82 Create,
83 Read,
84 Update,
85 Delete,
86}
8788#[derive(ValueEnum, Debug, Clone)]
89pub enum Column {
90 Meta,
91 Block,
92 Transaction,
93}
9495#[derive(Debug, Deserialize)]
96#[serde(untagged)]
97pub enum DbValue<H> {
98 Meta(MetaValue<H>),
99 Mapping(MappingValue<H>),
100}
101102impl FrontierDbCmd {
103pub fn run<B, C>(
104&self,
105 client: Arc<C>,
106 backend: Arc<fc_db::kv::Backend<B, C>>,
107 ) -> sc_cli::Result<()>
108where
109B: BlockT,
110 C: HeaderBackend<B> + ProvideRuntimeApi<B>,
111 C::Api: fp_rpc::EthereumRuntimeRPCApi<B>,
112 {
113match self.column {
114 Column::Meta => {
115// New meta db handler
116let meta_db = MetaDb::new(self, backend);
117// Maybe get a MetaKey
118let key = MetaKey::from_str(&self.key)?;
119// Maybe get a MetaValue
120let value = match utils::maybe_deserialize_value::<B>(
121&self.operation,
122self.value.as_ref(),
123 )? {
124Some(DbValue::Meta(value)) => Some(value),
125None => None,
126_ => return Err(format!("Unexpected `{:?}` value", self.value).into()),
127 };
128// Run the query
129meta_db.query(&key, &value)?
130}
131 Column::Block | Column::Transaction => {
132// New mapping db handler
133let mapping_db = MappingDb::new(self, client, backend);
134// Maybe get a MappingKey
135let key = MappingKey::EthBlockOrTransactionHash(
136 H256::from_str(&self.key).expect("H256 provided key"),
137 );
138// Maybe get a MappingValue
139let value = match utils::maybe_deserialize_value::<B>(
140&self.operation,
141self.value.as_ref(),
142 )? {
143Some(DbValue::Mapping(value)) => Some(value),
144None => None,
145_ => return Err(format!("Unexpected `{:?}` value", self.value).into()),
146 };
147// Run the query
148mapping_db.query(&self.column, &key, &value)?
149}
150 }
151Ok(())
152 }
153}
154155impl sc_cli::CliConfiguration for FrontierDbCmd {
156fn shared_params(&self) -> &SharedParams {
157&self.shared_params
158 }
159160fn pruning_params(&self) -> Option<&PruningParams> {
161Some(&self.pruning_params)
162 }
163}