From 2b7039d09367ce95a4bde8a7ad651fd9ade4346a Mon Sep 17 00:00:00 2001 From: jankun4 <81573167+jankun4@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:14:45 +0100 Subject: [PATCH] change: remove filtering out of multi-asset UTXOs from the wizard (#277) --- changelog.md | 1 + .../prepare_chain_params.rs | 13 +- .../src/register/register1.rs | 14 +- toolkit/partner-chains-cli/src/select_utxo.rs | 132 +++--------------- 4 files changed, 35 insertions(+), 125 deletions(-) diff --git a/changelog.md b/changelog.md index e84fa28ce..9ba0d633c 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,7 @@ This changelog is based on [Keep A Changelog](https://keepachangelog.com/en/1.1. ## Changed +* `genesis_utxo` and `registration_utxo` no longer have to have no native tokens. * Update ogmios to v6.9.0 * Organized Rust sources into two directories: toolkit and node. * Implemented transaction balancing with CSL in offchain code. diff --git a/toolkit/partner-chains-cli/src/prepare_configuration/prepare_chain_params.rs b/toolkit/partner-chains-cli/src/prepare_configuration/prepare_chain_params.rs index 2b23ff9a2..6a7352623 100644 --- a/toolkit/partner-chains-cli/src/prepare_configuration/prepare_chain_params.rs +++ b/toolkit/partner-chains-cli/src/prepare_configuration/prepare_chain_params.rs @@ -1,7 +1,7 @@ use crate::config::config_fields::{self, GENESIS_UTXO}; use crate::config::{ConfigFieldDefinition, ServiceConfig}; use crate::io::IOContext; -use crate::select_utxo::{filter_utxos, query_utxos, select_from_utxos, ValidUtxo}; +use crate::select_utxo::{query_utxos, select_from_utxos}; use crate::{cardano_key, pc_contracts_cli_resources}; use anyhow::anyhow; use partner_chains_cardano_offchain::csl::NetworkTypeExt; @@ -16,15 +16,14 @@ pub fn prepare_chain_params(context: &C) -> anyhow::Result<(UtxoId let shelley_config = get_shelley_config(&ogmios_configuration.to_string(), context)?; let address = derive_address(context, shelley_config.network)?; let utxo_query_result = query_utxos(context, &ogmios_configuration, &address)?; - let valid_utxos: Vec = filter_utxos(utxo_query_result); - if valid_utxos.is_empty() { + if utxo_query_result.is_empty() { context.eprint("⚠️ No UTXOs found for the given address"); context.eprint("There has to be at least one UTXO in the governance authority wallet."); return Err(anyhow::anyhow!("No UTXOs found")); }; let genesis_utxo = - select_from_utxos(context, "Select an UTXO to use as the genesis UTXO", valid_utxos)?; + select_from_utxos(context, "Select an UTXO to use as the genesis UTXO", utxo_query_result)?; context.print(CAUTION); @@ -70,7 +69,7 @@ mod tests { use crate::prepare_configuration::prepare_chain_params::{ prepare_chain_params, CAUTION, INTRO, }; - use crate::select_utxo::tests::{mock_5_valid_utxos_rows, mock_result_5_valid, query_utxos_io}; + use crate::select_utxo::tests::{mock_7_valid_utxos_rows, mock_result_7_valid, query_utxos_io}; use crate::tests::{MockIO, MockIOContext}; fn test_vkey_file_json() -> serde_json::Value { @@ -93,11 +92,11 @@ mod tests { query_utxos_io( "addr_test1vpmd59ajuvm34d723r8q2qzyz9ylq0x9pygqn7vun8qgpkgs7y5hw", "http://localhost:1337", - mock_result_5_valid(), + mock_result_7_valid(), ), MockIO::prompt_multi_option( "Select an UTXO to use as the genesis UTXO", - mock_5_valid_utxos_rows(), + mock_7_valid_utxos_rows(), "4704a903b01514645067d851382efd4a6ed5d2ff07cf30a538acc78fed7c4c02#93 (1100000 lovelace)" ), MockIO::print(CAUTION), diff --git a/toolkit/partner-chains-cli/src/register/register1.rs b/toolkit/partner-chains-cli/src/register/register1.rs index f0d968b84..39f0c97ff 100644 --- a/toolkit/partner-chains-cli/src/register/register1.rs +++ b/toolkit/partner-chains-cli/src/register/register1.rs @@ -8,7 +8,7 @@ use anyhow::anyhow; use cli_commands::registration_signatures::RegisterValidatorMessage; use cli_commands::signing::sc_public_key_and_signature_for_datum; use partner_chains_cardano_offchain::csl::NetworkTypeExt; -use select_utxo::{filter_utxos, query_utxos, select_from_utxos, ValidUtxo}; +use select_utxo::{query_utxos, select_from_utxos}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sidechain_domain::{NetworkType, SidechainPublicKey, UtxoId}; @@ -45,9 +45,7 @@ impl CmdRun for Register1Cmd { pc_contracts_cli_resources::prompt_ogmios_configuration(context)?; let utxo_query_result = query_utxos(context, &ogmios_configuration, &address)?; - let valid_utxos: Vec = filter_utxos(utxo_query_result); - - if valid_utxos.is_empty() { + if utxo_query_result.is_empty() { context.eprint("⚠️ No UTXOs found for the given address"); context.eprint( "The registering transaction requires at least one UTXO to be present at the address.", @@ -56,7 +54,7 @@ impl CmdRun for Register1Cmd { }; let input_utxo: UtxoId = - select_from_utxos(context, "Select UTXO to use for registration", valid_utxos)?; + select_from_utxos(context, "Select UTXO to use for registration", utxo_query_result)?; context.print("Please do not spend this UTXO, it needs to be consumed by the registration transaction."); context.print(""); @@ -167,7 +165,7 @@ mod tests { use ogmios::OgmiosRequest; use pc_contracts_cli_resources::default_ogmios_service_config; use pc_contracts_cli_resources::tests::prompt_ogmios_configuration_io; - use select_utxo::tests::{mock_5_valid_utxos_rows, mock_result_5_valid}; + use select_utxo::tests::{mock_7_valid_utxos_rows, mock_result_7_valid}; const PAYMENT_VKEY_PATH: &str = "payment.vkey"; @@ -539,14 +537,14 @@ mod tests { crate::select_utxo::tests::query_utxos_io( "addr_test1vqezxrh24ts0775hulcg3ejcwj7hns8792vnn8met6z9gwsxt87zy", "http://localhost:1337", - mock_result_5_valid(), + mock_result_7_valid(), ), ] } fn select_utxo_io() -> Vec { vec![ - MockIO::prompt_multi_option("Select UTXO to use for registration", mock_5_valid_utxos_rows(), "4704a903b01514645067d851382efd4a6ed5d2ff07cf30a538acc78fed7c4c02#93 (1100000 lovelace)"), + MockIO::prompt_multi_option("Select UTXO to use for registration", mock_7_valid_utxos_rows(), "4704a903b01514645067d851382efd4a6ed5d2ff07cf30a538acc78fed7c4c02#93 (1100000 lovelace)"), MockIO::print("Please do not spend this UTXO, it needs to be consumed by the registration transaction."), MockIO::print(""), diff --git a/toolkit/partner-chains-cli/src/select_utxo.rs b/toolkit/partner-chains-cli/src/select_utxo.rs index 9d664bdae..9f75e74a8 100644 --- a/toolkit/partner-chains-cli/src/select_utxo.rs +++ b/toolkit/partner-chains-cli/src/select_utxo.rs @@ -8,16 +8,15 @@ use ogmios_client::types::OgmiosUtxo; use sidechain_domain::{McTxHash, UtxoId}; use std::str::FromStr; -#[derive(Debug, PartialEq)] -pub(crate) struct ValidUtxo { - pub utxo_id: UtxoId, - pub lovelace: u64, +fn utxo_id(utxo: &OgmiosUtxo) -> UtxoId { + UtxoId { + tx_hash: McTxHash(utxo.transaction.id), + index: sidechain_domain::UtxoIndex(utxo.index), + } } -impl ValidUtxo { - pub fn to_display_string(&self) -> String { - format!("{0} ({1} lovelace)", self.utxo_id, self.lovelace) - } +fn to_display_string(utxo: &OgmiosUtxo) -> String { + format!("{0} ({1} lovelace)", utxo_id(utxo), utxo.value.lovelace) } pub(crate) fn query_utxos( @@ -38,41 +37,18 @@ pub(crate) fn query_utxos( } } -// Take only the UTXOs without multi-asset tokens -pub(crate) fn filter_utxos(utxos: Vec) -> Vec { - let mut utxos: Vec = utxos - .into_iter() - .filter_map(|utxo| { - if utxo.value.native_tokens.is_empty() { - Some(ValidUtxo { - utxo_id: UtxoId { - tx_hash: McTxHash(utxo.transaction.id), - index: sidechain_domain::UtxoIndex(utxo.index), - }, - lovelace: utxo.value.lovelace, - }) - } else { - None - } - }) - .collect(); - - utxos.sort_by_key(|utxo| std::cmp::Reverse(utxo.lovelace)); - utxos -} - pub(crate) fn select_from_utxos( context: &C, prompt: &str, - utxos: Vec, + utxos: Vec, ) -> Result { let utxo_display_options: Vec = - utxos.iter().map(|utxo| utxo.to_display_string()).collect(); + utxos.iter().map(|utxo| to_display_string(utxo)).collect(); let selected_utxo_display_string = context.prompt_multi_option(prompt, utxo_display_options); let selected_utxo = utxos .iter() - .find(|utxo| utxo.to_display_string() == selected_utxo_display_string) - .map(|utxo| utxo.utxo_id.to_string()) + .find(|utxo| to_display_string(utxo) == selected_utxo_display_string) + .map(|utxo| utxo_id(utxo).to_string()) .ok_or_else(|| anyhow!("⚠️ Failed to find selected UTXO"))?; UtxoId::from_str(&selected_utxo).map_err(|e| { context.eprint(&format!("⚠️ Failed to parse selected UTXO: {e}")); @@ -84,79 +60,13 @@ pub(crate) fn select_from_utxos( pub(crate) mod tests { use crate::{ ogmios::{OgmiosRequest, OgmiosResponse}, - select_utxo::{filter_utxos, ValidUtxo}, tests::MockIO, }; use hex_literal::hex; use ogmios_client::types::{Asset, OgmiosTx, OgmiosUtxo, OgmiosValue}; - use sidechain_domain::UtxoId; - use std::{collections::HashMap, str::FromStr}; + use std::collections::HashMap; - #[test] - fn test_parse_utxo_query_output() { - { - let utxos = filter_utxos(mock_result_5_valid()); - - assert_eq!(utxos.len(), 5); - assert_eq!( - utxos[0], - ValidUtxo { - utxo_id: UtxoId::from_str( - "f5f58c0d5ab357a3562ca043a4dd67567a8399da77968cef59fb271d72db57bd#0" - ) - .unwrap(), - lovelace: 1700000, - } - ); - assert_eq!( - utxos[1], - ValidUtxo { - utxo_id: UtxoId::from_str( - "b031cda9c257fed6eed781596ab5ca9495ae88a860e807763b2cd67c72c4cc1e#0" - ) - .unwrap(), - lovelace: 1500000, - } - ); - assert_eq!( - utxos[2], - ValidUtxo { - utxo_id: UtxoId::from_str( - "917e3dba3ed5faee7855d99b4a797859ac7b1941b381aef36080d767127bdaba#0" - ) - .unwrap(), - lovelace: 1400000, - } - ); - assert_eq!( - utxos[3], - ValidUtxo { - utxo_id: UtxoId::from_str( - "76ddb0a474eb893e6e17de4cc692bce12e57271351cccb4c0e7e2ad864347b64#0" - ) - .unwrap(), - lovelace: 1200000, - } - ); - assert_eq!( - utxos[4], - ValidUtxo { - utxo_id: UtxoId::from_str( - "4704a903b01514645067d851382efd4a6ed5d2ff07cf30a538acc78fed7c4c02#93" - ) - .unwrap(), - lovelace: 1100000, - } - ); - } - - { - let utxos = filter_utxos(mock_result_0_valid()); - assert_eq!(utxos.len(), 0); - } - } - - pub(crate) fn mock_result_5_valid() -> Vec { + pub(crate) fn mock_result_7_valid() -> Vec { vec![ OgmiosUtxo { transaction: OgmiosTx { @@ -211,7 +121,7 @@ pub(crate) mod tests { transaction: OgmiosTx { id: hex!("b9da3bfe0c7c177d494aeea0937ce4da9827c8dfc80bedb5825cd08887cbedb8"), }, - index: 0, + index: 1, value: OgmiosValue { lovelace: 1600000, native_tokens: HashMap::from([( @@ -232,14 +142,16 @@ pub(crate) mod tests { ] } - pub(crate) fn mock_5_valid_utxos_rows() -> Vec { + pub(crate) fn mock_7_valid_utxos_rows() -> Vec { vec![ - "f5f58c0d5ab357a3562ca043a4dd67567a8399da77968cef59fb271d72db57bd#0 (1700000 lovelace)".to_string(), - "b031cda9c257fed6eed781596ab5ca9495ae88a860e807763b2cd67c72c4cc1e#0 (1500000 lovelace)".to_string(), - "917e3dba3ed5faee7855d99b4a797859ac7b1941b381aef36080d767127bdaba#0 (1400000 lovelace)".to_string(), - "76ddb0a474eb893e6e17de4cc692bce12e57271351cccb4c0e7e2ad864347b64#0 (1200000 lovelace)".to_string(), "4704a903b01514645067d851382efd4a6ed5d2ff07cf30a538acc78fed7c4c02#93 (1100000 lovelace)".to_string(), - ] + "76ddb0a474eb893e6e17de4cc692bce12e57271351cccb4c0e7e2ad864347b64#0 (1200000 lovelace)".to_string(), + "b9da3bfe0c7c177d494aeea0937ce4da9827c8dfc80bedb5825cd08887cbedb8#0 (1300000 lovelace)".to_string(), + "917e3dba3ed5faee7855d99b4a797859ac7b1941b381aef36080d767127bdaba#0 (1400000 lovelace)".to_string(), + "b031cda9c257fed6eed781596ab5ca9495ae88a860e807763b2cd67c72c4cc1e#0 (1500000 lovelace)".to_string(), + "b9da3bfe0c7c177d494aeea0937ce4da9827c8dfc80bedb5825cd08887cbedb8#1 (1600000 lovelace)".to_string(), + "f5f58c0d5ab357a3562ca043a4dd67567a8399da77968cef59fb271d72db57bd#0 (1700000 lovelace)".to_string(), + ] } pub(crate) fn mock_result_0_valid() -> Vec {