fc_cli/frontier_db_cmd/
meta_db.rs1use std::{
20 collections::HashMap,
21 str::{self, FromStr},
22 sync::Arc,
23};
24
25use ethereum_types::H256;
26use serde::Deserialize;
27use sp_blockchain::HeaderBackend;
28use sp_runtime::traits::Block as BlockT;
30
31use super::{utils::FrontierDbMessage, FrontierDbCmd, Operation};
32
33#[derive(Debug, Deserialize)]
34#[serde(untagged)]
35pub enum MetaValue<H> {
36 Tips(Vec<H>),
37 Schema(HashMap<H256, fp_storage::EthereumStorageSchema>),
38}
39
40#[derive(Clone, Copy, Debug)]
41pub enum MetaKey {
42 Tips,
43 Schema,
44}
45
46impl FromStr for MetaKey {
47 type Err = sc_cli::Error;
48
49 fn from_str(input: &str) -> Result<MetaKey, Self::Err> {
51 let tips = str::from_utf8(fc_db::kv::static_keys::CURRENT_SYNCING_TIPS).unwrap();
52 let schema = str::from_utf8(fp_storage::PALLET_ETHEREUM_SCHEMA_CACHE).unwrap();
53 match input {
54 x if x == tips => Ok(MetaKey::Tips),
55 y if y == schema => Ok(MetaKey::Schema),
56 _ => Err(format!("`{input:?}` is not a meta column static key").into()),
57 }
58 }
59}
60
61pub struct MetaDb<'a, B, C> {
62 cmd: &'a FrontierDbCmd,
63 backend: Arc<fc_db::kv::Backend<B, C>>,
64}
65
66impl<'a, B: BlockT, C: HeaderBackend<B>> MetaDb<'a, B, C> {
67 pub fn new(cmd: &'a FrontierDbCmd, backend: Arc<fc_db::kv::Backend<B, C>>) -> Self {
68 Self { cmd, backend }
69 }
70
71 pub fn query(&self, key: &MetaKey, value: &Option<MetaValue<B::Hash>>) -> sc_cli::Result<()> {
72 match self.cmd.operation {
73 Operation::Create => match (key, value) {
74 (MetaKey::Tips, Some(MetaValue::Tips(hashes))) => {
76 if self.backend.meta().current_syncing_tips()?.is_empty() {
77 self.backend
78 .meta()
79 .write_current_syncing_tips(hashes.clone())?;
80 } else {
81 return Err(self.key_not_empty_error(key));
82 }
83 }
84 (MetaKey::Schema, Some(MetaValue::Schema(schema_map))) => {
86 if self.backend.meta().ethereum_schema()?.is_none() {
87 let data = schema_map
88 .iter()
89 .map(|(key, value)| (*value, *key))
90 .collect::<Vec<(fp_storage::EthereumStorageSchema, H256)>>();
91 self.backend.meta().write_ethereum_schema(data)?;
92 } else {
93 return Err(self.key_not_empty_error(key));
94 }
95 }
96 _ => return Err(self.key_value_error(key, value)),
97 },
98 Operation::Read => match key {
99 MetaKey::Tips => {
101 let value = self.backend.meta().current_syncing_tips()?;
102 println!("{value:?}");
103 }
104 MetaKey::Schema => {
106 let value = self.backend.meta().ethereum_schema()?;
107 println!("{value:?}");
108 }
109 },
110 Operation::Update => match (key, value) {
111 (MetaKey::Tips, Some(MetaValue::Tips(new_value))) => {
113 let value = self.backend.meta().current_syncing_tips()?;
114 self.confirmation_prompt(&self.cmd.operation, key, &value, new_value)?;
115 self.backend
116 .meta()
117 .write_current_syncing_tips(new_value.clone())?;
118 }
119 (MetaKey::Schema, Some(MetaValue::Schema(schema_map))) => {
121 let value = self.backend.meta().ethereum_schema()?;
122 let new_value = schema_map
123 .iter()
124 .map(|(key, value)| (*value, *key))
125 .collect::<Vec<(fp_storage::EthereumStorageSchema, H256)>>();
126 self.confirmation_prompt(
127 &self.cmd.operation,
128 key,
129 &value,
130 &Some(new_value.clone()),
131 )?;
132 self.backend.meta().write_ethereum_schema(new_value)?;
133 }
134 _ => return Err(self.key_value_error(key, value)),
135 },
136 Operation::Delete => match key {
137 MetaKey::Tips => {
139 let value = self.backend.meta().current_syncing_tips()?;
140 self.confirmation_prompt(&self.cmd.operation, key, &value, &vec![])?;
141 self.backend.meta().write_current_syncing_tips(vec![])?;
142 }
143 MetaKey::Schema => {
145 let value = self.backend.meta().ethereum_schema()?;
146 self.confirmation_prompt(&self.cmd.operation, key, &value, &Some(vec![]))?;
147 self.backend.meta().write_ethereum_schema(vec![])?;
148 }
149 },
150 }
151 Ok(())
152 }
153}
154
155impl<B: BlockT, C: HeaderBackend<B>> FrontierDbMessage for MetaDb<'_, B, C> {}