Skip to content

Commit

Permalink
change: remove filtering out of multi-asset UTXOs from the wizard (#277)
Browse files Browse the repository at this point in the history
  • Loading branch information
jankun4 authored Nov 29, 2024
1 parent 2acd339 commit 2b7039d
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 125 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -16,15 +16,14 @@ pub fn prepare_chain_params<C: IOContext>(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<ValidUtxo> = 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);

Expand Down Expand Up @@ -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 {
Expand All @@ -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),
Expand Down
14 changes: 6 additions & 8 deletions toolkit/partner-chains-cli/src/register/register1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<ValidUtxo> = 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.",
Expand All @@ -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("");
Expand Down Expand Up @@ -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";

Expand Down Expand Up @@ -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<MockIO> {
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(""),
Expand Down
132 changes: 22 additions & 110 deletions toolkit/partner-chains-cli/src/select_utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<C: IOContext>(
Expand All @@ -38,41 +37,18 @@ pub(crate) fn query_utxos<C: IOContext>(
}
}

// Take only the UTXOs without multi-asset tokens
pub(crate) fn filter_utxos(utxos: Vec<OgmiosUtxo>) -> Vec<ValidUtxo> {
let mut utxos: Vec<ValidUtxo> = 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<C: IOContext>(
context: &C,
prompt: &str,
utxos: Vec<ValidUtxo>,
utxos: Vec<OgmiosUtxo>,
) -> Result<UtxoId, anyhow::Error> {
let utxo_display_options: Vec<String> =
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}"));
Expand All @@ -84,79 +60,13 @@ pub(crate) fn select_from_utxos<C: IOContext>(
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<OgmiosUtxo> {
pub(crate) fn mock_result_7_valid() -> Vec<OgmiosUtxo> {
vec![
OgmiosUtxo {
transaction: OgmiosTx {
Expand Down Expand Up @@ -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([(
Expand All @@ -232,14 +142,16 @@ pub(crate) mod tests {
]
}

pub(crate) fn mock_5_valid_utxos_rows() -> Vec<String> {
pub(crate) fn mock_7_valid_utxos_rows() -> Vec<String> {
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<OgmiosUtxo> {
Expand Down

0 comments on commit 2b7039d

Please sign in to comment.