partner_chains_smart_contracts_commands/
governed_map.rs

1use crate::{GenesisUtxo, PaymentFilePath};
2use partner_chains_cardano_offchain::governed_map::{
3	run_get, run_insert, run_list, run_remove, run_update,
4};
5use serde_json::json;
6use sidechain_domain::byte_string::ByteString;
7use std::collections::HashMap;
8
9#[derive(Clone, Debug, clap::Subcommand)]
10#[allow(clippy::large_enum_variant)]
11/// Commands for managing the Governed Map key-value store on Cardano
12pub enum GovernedMapCmd {
13	/// Inserts a key-value pair into the Governed Map. If a value for the key already exists it won't be updated.
14	///
15	/// NOTE: In rare cases, race conditions may occur, and two inserts with the same key will both succeed.
16	/// In that case the second one in terms of block and transaction number is considered valid.
17	Insert(InsertCmd),
18	/// Updates a key-value pair in the Governed Map. If the key is missing it won't be inserted.
19	Update(UpdateCmd),
20	/// Removes a key-value pair from the Governed Map
21	Remove(RemoveCmd),
22	/// Lists all key-value pairs currently stored in the Governed Map
23	List(ListCmd),
24	/// Retrieves the value stored in the Governed Map for the given key
25	Get(GetCmd),
26}
27
28impl GovernedMapCmd {
29	/// Executes the internal command
30	pub async fn execute(self) -> crate::SubCmdResult {
31		match self {
32			Self::Insert(cmd) => cmd.execute().await,
33			Self::Update(cmd) => cmd.execute().await,
34			Self::Remove(cmd) => cmd.execute().await,
35			Self::List(cmd) => cmd.execute().await,
36			Self::Get(cmd) => cmd.execute().await,
37		}
38	}
39}
40
41#[derive(Clone, Debug, clap::Parser)]
42/// Command for inserting a key-value pair into the Governed Map
43pub struct InsertCmd {
44	#[clap(flatten)]
45	common_arguments: crate::CommonArguments,
46	#[arg(long)]
47	/// The key of the entry, UTF-8 encodable string.
48	key: String,
49	#[arg(long)]
50	/// The value of the entry, hex encoded bytes.
51	value: ByteString,
52	#[clap(flatten)]
53	/// Path to the payment key file
54	payment_key_file: PaymentFilePath,
55	#[clap(flatten)]
56	/// Genesis UTXO
57	genesis_utxo: GenesisUtxo,
58}
59
60impl InsertCmd {
61	/// Inserts a key-value pair into the Governed Map.
62	pub async fn execute(self) -> crate::SubCmdResult {
63		let payment_key = self.payment_key_file.read_key()?;
64
65		let client = self.common_arguments.get_ogmios_client().await?;
66
67		let result = run_insert(
68			self.genesis_utxo.into(),
69			self.key,
70			self.value,
71			&payment_key,
72			&client,
73			&self.common_arguments.retries(),
74		)
75		.await;
76		print_result_json(result)
77	}
78}
79
80#[derive(Clone, Debug, clap::Parser)]
81/// Command for updating a existing key-value pair in the Governed Map
82pub struct UpdateCmd {
83	#[clap(flatten)]
84	common_arguments: crate::CommonArguments,
85	#[arg(long)]
86	/// The key of the entry, UTF-8 encodable string.
87	key: String,
88	#[arg(long)]
89	/// The value of the entry, hex encoded bytes.
90	value: ByteString,
91	#[arg(long)]
92	/// If provided, update will fail unless the current value matches the one on the ledger.
93	current_value: Option<ByteString>,
94	#[clap(flatten)]
95	/// Path to the payment key file
96	payment_key_file: PaymentFilePath,
97	#[clap(flatten)]
98	/// Genesis UTXO
99	genesis_utxo: GenesisUtxo,
100}
101
102impl UpdateCmd {
103	/// Updates a key-value pair in the Governed Map.
104	pub async fn execute(self) -> crate::SubCmdResult {
105		let payment_key = self.payment_key_file.read_key()?;
106
107		let client = self.common_arguments.get_ogmios_client().await?;
108
109		let result = run_update(
110			self.genesis_utxo.into(),
111			self.key,
112			self.value,
113			self.current_value,
114			&payment_key,
115			&client,
116			&self.common_arguments.retries(),
117		)
118		.await;
119		print_result_json(result)
120	}
121}
122
123#[derive(Clone, Debug, clap::Parser)]
124/// Command for removing a key-value pair from the Governed Map
125pub struct RemoveCmd {
126	#[clap(flatten)]
127	common_arguments: crate::CommonArguments,
128	#[arg(long)]
129	/// The key of the entry, UTF-8 encodable string.
130	key: String,
131	#[clap(flatten)]
132	/// Path to the payment key file
133	payment_key_file: PaymentFilePath,
134	#[clap(flatten)]
135	/// Genesis UTXO
136	genesis_utxo: GenesisUtxo,
137}
138
139impl RemoveCmd {
140	/// Removes a key-value pair from the Governed Map.
141	pub async fn execute(self) -> crate::SubCmdResult {
142		let payment_key = self.payment_key_file.read_key()?;
143
144		let client = self.common_arguments.get_ogmios_client().await?;
145
146		let result = run_remove(
147			self.genesis_utxo.into(),
148			self.key,
149			&payment_key,
150			&client,
151			&self.common_arguments.retries(),
152		)
153		.await;
154		print_result_json(result)
155	}
156}
157
158#[derive(Clone, Debug, clap::Parser)]
159/// Command for listing all key-value pairs currently stored in the Governed Map
160pub struct ListCmd {
161	#[clap(flatten)]
162	common_arguments: crate::CommonArguments,
163	#[clap(flatten)]
164	/// Genesis UTXO
165	genesis_utxo: GenesisUtxo,
166}
167
168impl ListCmd {
169	/// Lists all key-value pairs currently stored in the Governed Map.
170	pub async fn execute(self) -> crate::SubCmdResult {
171		let client = self.common_arguments.get_ogmios_client().await?;
172		let kv_pairs: HashMap<_, _> = run_list(self.genesis_utxo.into(), &client)
173			.await?
174			.map(|datum| (datum.key, datum.value.to_hex_string()))
175			.collect();
176
177		Ok(json!(kv_pairs))
178	}
179}
180
181#[derive(Clone, Debug, clap::Parser)]
182/// Command for retrieving the value stored in the Governed Map for the given key
183pub struct GetCmd {
184	#[clap(flatten)]
185	common_arguments: crate::CommonArguments,
186	#[arg(long)]
187	/// The key of the entry, UTF-8 encodable string.
188	key: String,
189	#[clap(flatten)]
190	/// Genesis UTXO
191	genesis_utxo: GenesisUtxo,
192}
193
194impl GetCmd {
195	/// Retrieves the value stored in the Governed Map for the given key.
196	pub async fn execute(self) -> crate::SubCmdResult {
197		let client = self.common_arguments.get_ogmios_client().await?;
198		let Some(value) = run_get(self.genesis_utxo.into(), self.key.clone(), &client).await?
199		else {
200			return Ok(json!({}).into());
201		};
202
203		Ok(json!(value.to_hex_string()).into())
204	}
205}
206
207/// Converts the result of a command into a JSON object.
208fn print_result_json(
209	result: anyhow::Result<Option<crate::MultiSigSmartContractResult>>,
210) -> crate::SubCmdResult {
211	match result {
212		Err(err) => Err(err)?,
213		Ok(Some(res)) => Ok(json!(res)),
214		Ok(None) => Ok(json!({})),
215	}
216}