From 38c2bedd8ea3d324e1ff5c85764086cdc673a096 Mon Sep 17 00:00:00 2001 From: jankun4 <81573167+jankun4@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:02:38 +0100 Subject: [PATCH] Add upsert-d-parameter command (#297) --- changelog.md | 5 +- .../src/d_parameter.rs | 35 +++++++++ .../cli/smart-contracts-commands/src/lib.rs | 4 ++ toolkit/offchain/src/d_param/mod.rs | 21 ++++++ toolkit/partner-chains-cli/src/cardano_key.rs | 20 ++++++ toolkit/partner-chains-cli/src/io.rs | 3 +- .../prepare_main_chain_config.rs | 14 +--- .../src/setup_main_chain_state/mod.rs | 55 +++++++------- .../src/setup_main_chain_state/tests.rs | 71 +++++++++++++++---- toolkit/partner-chains-cli/src/tests/mod.rs | 32 ++++++++- toolkit/primitives/domain/src/lib.rs | 8 ++- 11 files changed, 213 insertions(+), 55 deletions(-) create mode 100644 toolkit/cli/smart-contracts-commands/src/d_parameter.rs diff --git a/changelog.md b/changelog.md index 721e7bd2d..88ad97ae1 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,8 @@ This changelog is based on [Keep A Changelog](https://keepachangelog.com/en/1.1. ## Changed +* `setup-main-chain-state` command now uses native Rust to insert the D-Parameter + ## Removed ## Fixed @@ -36,7 +38,8 @@ Do **NOT** perform a normal runtime upgrade, it will break your chain. ## Added -* Added `smart-contracts` command to the node with sub-commands `init-governance` and `get-scripts`. +* Added `smart-contracts` command to the node with sub-commands `init-governance`, `get-scripts` and +`upsert-d-parameter`. # v1.3.0 diff --git a/toolkit/cli/smart-contracts-commands/src/d_parameter.rs b/toolkit/cli/smart-contracts-commands/src/d_parameter.rs new file mode 100644 index 000000000..2605fc8a9 --- /dev/null +++ b/toolkit/cli/smart-contracts-commands/src/d_parameter.rs @@ -0,0 +1,35 @@ +use jsonrpsee::http_client::HttpClient; +use partner_chains_cardano_offchain::d_param::upsert_d_param; +use sidechain_domain::DParameter; +use sidechain_domain::UtxoId; + +use crate::read_private_key_from_file; + +#[derive(Clone, Debug, clap::Parser)] +pub struct UpsertDParameterCmd { + #[clap(flatten)] + common_arguments: crate::CommonArguments, + #[arg(long)] + permissioned_candidates_count: u16, + #[arg(long)] + registered_candidates_count: u16, + #[arg(long, short('k'))] + payment_key_file: String, + #[arg(long, short('c'))] + genesis_utxo: UtxoId, +} + +impl UpsertDParameterCmd { + pub async fn execute(self) -> crate::CmdResult<()> { + let payment_key = read_private_key_from_file(&self.payment_key_file)?; + let d_param = DParameter { + num_permissioned_candidates: self.permissioned_candidates_count, + num_registered_candidates: self.registered_candidates_count, + }; + let client = HttpClient::builder().build(self.common_arguments.ogmios_host)?; + + upsert_d_param(self.genesis_utxo, &d_param, payment_key.0, &client).await?; + + Ok(()) + } +} diff --git a/toolkit/cli/smart-contracts-commands/src/lib.rs b/toolkit/cli/smart-contracts-commands/src/lib.rs index d7e627690..bd2358a71 100644 --- a/toolkit/cli/smart-contracts-commands/src/lib.rs +++ b/toolkit/cli/smart-contracts-commands/src/lib.rs @@ -5,6 +5,7 @@ use log4rs::{ use sidechain_domain::MainchainPrivateKey; pub mod get_scripts; +pub mod d_parameter; pub mod init_governance; #[derive(Clone, Debug, clap::Subcommand)] @@ -14,6 +15,8 @@ pub enum SmartContractsCmd { GetScripts(get_scripts::GetScripts), /// Initialize Partner Chain governance InitGovernance(init_governance::InitGovernanceCmd), + /// Upsert DParameter + UpsertDParameter(d_parameter::UpsertDParameterCmd), } #[derive(Clone, Debug, clap::Parser)] @@ -30,6 +33,7 @@ impl SmartContractsCmd { match self { Self::InitGovernance(cmd) => cmd.execute().await, Self::GetScripts(cmd) => cmd.execute().await, + Self::UpsertDParameter(cmd) => cmd.execute().await, } } diff --git a/toolkit/offchain/src/d_param/mod.rs b/toolkit/offchain/src/d_param/mod.rs index 039f8c02f..0458700e9 100644 --- a/toolkit/offchain/src/d_param/mod.rs +++ b/toolkit/offchain/src/d_param/mod.rs @@ -24,6 +24,27 @@ use sidechain_domain::{DParameter, McTxHash, UtxoId}; #[cfg(test)] mod tests; +pub trait UpsertDParam { + #[allow(async_fn_in_trait)] + async fn upsert_d_param( + &self, + genesis_utxo: UtxoId, + d_parameter: &DParameter, + payment_signing_key: [u8; 32], + ) -> anyhow::Result>; +} + +impl UpsertDParam for C { + async fn upsert_d_param( + &self, + genesis_utxo: UtxoId, + d_parameter: &DParameter, + payment_signing_key: [u8; 32], + ) -> anyhow::Result> { + upsert_d_param(genesis_utxo, d_parameter, payment_signing_key, self).await + } +} + pub async fn upsert_d_param( genesis_utxo: UtxoId, d_parameter: &DParameter, diff --git a/toolkit/partner-chains-cli/src/cardano_key.rs b/toolkit/partner-chains-cli/src/cardano_key.rs index 295783f11..c5d02b770 100644 --- a/toolkit/partner-chains-cli/src/cardano_key.rs +++ b/toolkit/partner-chains-cli/src/cardano_key.rs @@ -1,5 +1,6 @@ use crate::IOContext; use anyhow::anyhow; +use sidechain_domain::{MainchainAddressHash, MainchainPrivateKey}; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] @@ -37,3 +38,22 @@ pub(crate) fn get_key_bytes_from_file( })?; Ok(bytes) } + +pub(crate) fn get_mc_pkey_from_file( + path: &str, + context: &impl IOContext, +) -> anyhow::Result { + Ok(MainchainPrivateKey(get_key_bytes_from_file(path, context)?)) +} + +pub(crate) fn get_mc_address_hash_from_pkey(pkey: &MainchainPrivateKey) -> MainchainAddressHash { + let csl_private_key = cardano_serialization_lib::PrivateKey::from_normal_bytes(&pkey.0) + .expect("Conversion is infallible"); + let csl_public_key_hash = csl_private_key + .to_public() + .hash() + .to_bytes() + .try_into() + .expect("Bytes represent correct public key hash"); + MainchainAddressHash(csl_public_key_hash) +} diff --git a/toolkit/partner-chains-cli/src/io.rs b/toolkit/partner-chains-cli/src/io.rs index b8570a0eb..6b93931fd 100644 --- a/toolkit/partner-chains-cli/src/io.rs +++ b/toolkit/partner-chains-cli/src/io.rs @@ -2,6 +2,7 @@ use crate::config::ServiceConfig; use crate::ogmios::{ogmios_request, OgmiosRequest, OgmiosResponse}; use anyhow::{anyhow, Context}; use jsonrpsee::http_client::HttpClient; +use partner_chains_cardano_offchain::d_param::UpsertDParam; use partner_chains_cardano_offchain::init_governance::InitGovernance; use partner_chains_cardano_offchain::scripts_data::GetScriptsData; use sp_core::offchain::Timestamp; @@ -15,7 +16,7 @@ use tempfile::{TempDir, TempPath}; pub trait IOContext { /// It should implement all the required traits for offchain operations - type Offchain: GetScriptsData + InitGovernance; + type Offchain: GetScriptsData + InitGovernance + UpsertDParam; fn run_command(&self, cmd: &str) -> anyhow::Result; fn print(&self, msg: &str); diff --git a/toolkit/partner-chains-cli/src/prepare_configuration/prepare_main_chain_config.rs b/toolkit/partner-chains-cli/src/prepare_configuration/prepare_main_chain_config.rs index a01c35155..b800c7245 100644 --- a/toolkit/partner-chains-cli/src/prepare_configuration/prepare_main_chain_config.rs +++ b/toolkit/partner-chains-cli/src/prepare_configuration/prepare_main_chain_config.rs @@ -7,7 +7,6 @@ use crate::config::ServiceConfig; use crate::io::IOContext; use crate::prepare_configuration::prepare_cardano_params::prepare_cardano_params; use crate::{config::config_fields, *}; -use cardano_serialization_lib::*; use partner_chains_cardano_offchain::init_governance::InitGovernance; use partner_chains_cardano_offchain::scripts_data::GetScriptsData; use sidechain_domain::{MainchainAddressHash, MainchainPrivateKey, PolicyId, UtxoId}; @@ -42,17 +41,10 @@ fn get_private_key_and_key_hash( ) -> Result<(MainchainPrivateKey, MainchainAddressHash), anyhow::Error> { let cardano_signig_key_file = config_fields::CARDANO_PAYMENT_SIGNING_KEY_FILE .prompt_with_default_from_file_and_save(context); - let bytes = cardano_key::get_key_bytes_from_file(&cardano_signig_key_file, context)?; + let pkey = cardano_key::get_mc_pkey_from_file(&cardano_signig_key_file, context)?; + let addr_hash = cardano_key::get_mc_address_hash_from_pkey(&pkey); - let csl_private_key = PrivateKey::from_normal_bytes(&bytes)?; - let csl_public_key_hash = csl_private_key - .to_public() - .hash() - .to_bytes() - .try_into() - .expect("Bytes represent correct public key hash"); - - Ok((MainchainPrivateKey(bytes), MainchainAddressHash(csl_public_key_hash))) + Ok((pkey, addr_hash)) } fn set_up_cardano_addresses( diff --git a/toolkit/partner-chains-cli/src/setup_main_chain_state/mod.rs b/toolkit/partner-chains-cli/src/setup_main_chain_state/mod.rs index 163ae8aa7..084890ad1 100644 --- a/toolkit/partner-chains-cli/src/setup_main_chain_state/mod.rs +++ b/toolkit/partner-chains-cli/src/setup_main_chain_state/mod.rs @@ -4,11 +4,14 @@ use crate::config::{ CHAIN_CONFIG_FILE_PATH, PC_CONTRACTS_CLI_PATH, }; use crate::io::IOContext; -use crate::pc_contracts_cli_resources::establish_pc_contracts_cli_configuration; +use crate::pc_contracts_cli_resources::{ + establish_pc_contracts_cli_configuration, prompt_ogmios_configuration, +}; use crate::permissioned_candidates::{ParsedPermissionedCandidatesKeys, PermissionedCandidateKeys}; -use crate::{smart_contracts, CmdRun}; +use crate::{cardano_key, smart_contracts, CmdRun}; use anyhow::anyhow; use anyhow::Context; +use partner_chains_cardano_offchain::d_param::UpsertDParam; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sidechain_domain::mainchain_epoch::MainchainEpochDerivation; @@ -50,13 +53,6 @@ enum InsertOrUpdate { } impl InsertOrUpdate { - fn d_parameter_command(&self) -> &'static str { - match self { - InsertOrUpdate::Insert => "insert-d-parameter", - InsertOrUpdate::Update => "update-d-parameter", - } - } - fn permissioned_candidates_command(&self) -> &'static str { "update-permissioned-candidates --remove-all-candidates" } @@ -92,6 +88,13 @@ impl SortedPermissionedCandidates { impl CmdRun for SetupMainChainStateCmd { fn run(&self, context: &C) -> anyhow::Result<()> { + let runtime = tokio::runtime::Runtime::new().map_err(|e| anyhow::anyhow!(e))?; + runtime.block_on(self.run_async(context)) + } +} + +impl SetupMainChainStateCmd { + async fn run_async(&self, context: &C) -> anyhow::Result<()> { let chain_config = crate::config::load_chain_config(context)?; context.print( "This wizard will set or update D-Parameter and Permissioned Candidates on the main chain. Setting either of these costs ADA!", @@ -128,8 +131,8 @@ impl CmdRun for SetupMainChainStateCmd { context, ariadne_parameters.d_parameter, chain_config.chain_parameters.genesis_utxo, - InsertOrUpdate::Update, - )?; + ) + .await?; } else { set_candidates_on_main_chain( context, @@ -143,8 +146,8 @@ impl CmdRun for SetupMainChainStateCmd { context, default_d_parameter, chain_config.chain_parameters.genesis_utxo, - InsertOrUpdate::Insert, - )?; + ) + .await?; } context.print("Done. Main chain state is set. Please remember that any changes can be observed immediately, but from the Partner Chain point of view they will be effective in two main chain epochs."); Ok(()) @@ -283,37 +286,35 @@ fn set_candidates_on_main_chain( Ok(()) } -fn set_d_parameter_on_main_chain( +async fn set_d_parameter_on_main_chain( context: &C, default_d_parameter: DParameter, genesis_utxo: UtxoId, - insert: InsertOrUpdate, ) -> anyhow::Result<()> { let update = context .prompt_yes_no("Do you want to set/update the D-parameter on the main chain?", false); if update { + let ogmios_config = prompt_ogmios_configuration(context)?; let p = context.prompt( "Enter P, the number of permissioned candidates seats, as a non-negative integer.", Some(&default_d_parameter.num_permissioned_candidates.to_string()), ); - let p: u64 = p.parse()?; + let num_permissioned_candidates: u16 = p.parse()?; let r = context.prompt( "Enter R, the number of registered candidates seats, as a non-negative integer.", Some(&default_d_parameter.num_registered_candidates.to_string()), ); - let r: u64 = r.parse()?; - let pc_contracts_cli_resources = establish_pc_contracts_cli_configuration(context)?; + let num_registered_candidates: u16 = r.parse()?; let payment_signing_key_path = CARDANO_PAYMENT_SIGNING_KEY_FILE.prompt_with_default_from_file_and_save(context); - let pc_contracts_cli_command = insert.d_parameter_command(); - let cardano_network = get_cardano_network_from_file(context)?; - let command = format!( - "{PC_CONTRACTS_CLI_PATH} {pc_contracts_cli_command} --network {} --d-parameter-permissioned-candidates-count {p} --d-parameter-registered-candidates-count {r} {} {}", - cardano_network, - smart_contracts::sidechain_params_arguments(genesis_utxo), - smart_contracts::runtime_config_arguments(&pc_contracts_cli_resources, &payment_signing_key_path) - ); - context.run_command(&command).context("Setting D-parameter failed")?; + let payment_signing_key = + cardano_key::get_mc_pkey_from_file(&payment_signing_key_path, context)?; + let d_parameter = + sidechain_domain::DParameter { num_permissioned_candidates, num_registered_candidates }; + context + .offchain_impl(&ogmios_config)? + .upsert_d_param(genesis_utxo, &d_parameter, payment_signing_key.0) + .await?; context.print(&format!("D-parameter updated to ({}, {}). The change will be effective in two main chain epochs.", p, r)); } Ok(()) diff --git a/toolkit/partner-chains-cli/src/setup_main_chain_state/tests.rs b/toolkit/partner-chains-cli/src/setup_main_chain_state/tests.rs index 5d3ba3fb7..03bddff5c 100644 --- a/toolkit/partner-chains-cli/src/setup_main_chain_state/tests.rs +++ b/toolkit/partner-chains-cli/src/setup_main_chain_state/tests.rs @@ -1,15 +1,19 @@ use crate::config::config_fields::CARDANO_PAYMENT_SIGNING_KEY_FILE; use crate::config::{config_fields, PC_CONTRACTS_CLI_PATH}; use crate::config::{CHAIN_CONFIG_FILE_PATH, RESOURCES_CONFIG_FILE_PATH}; -use crate::pc_contracts_cli_resources::tests::establish_pc_contracts_cli_configuration_io; -use crate::pc_contracts_cli_resources::PcContractsCliResources; +use crate::pc_contracts_cli_resources::tests::{ + establish_pc_contracts_cli_configuration_io, prompt_ogmios_configuration_io, +}; +use crate::pc_contracts_cli_resources::{default_ogmios_service_config, PcContractsCliResources}; use crate::prepare_configuration::tests::{ prompt_and_save_to_existing_file, prompt_with_default_and_save_to_existing_file, }; use crate::setup_main_chain_state::SetupMainChainStateCmd; -use crate::tests::{MockIO, MockIOContext}; +use crate::tests::{MockIO, MockIOContext, OffchainMock, OffchainMocks}; use crate::CmdRun; +use hex_literal::hex; use serde_json::json; +use sidechain_domain::{DParameter, MainchainPrivateKey, McTxHash, UtxoId}; use sp_core::offchain::Timestamp; #[test] @@ -35,10 +39,18 @@ fn no_ariadne_parameters_on_main_chain_no_updates() { #[test] fn no_ariadne_parameters_on_main_chain_do_updates() { + let offchain_mock = OffchainMock::new().with_upsert_d_param( + UtxoId::default(), + new_d_parameter(), + payment_signing_key(), + Ok(Some(McTxHash::default())), + ); let mock_context = MockIOContext::new() .with_file(PC_CONTRACTS_CLI_PATH, "") .with_json_file(CHAIN_CONFIG_FILE_PATH, test_chain_config_content()) .with_json_file(RESOURCES_CONFIG_FILE_PATH, test_resources_config_content()) + .with_json_file("payment.skey", valid_payment_signing_key_content()) + .with_offchain_mocks(OffchainMocks::new_with_mock("http://localhost:1337", offchain_mock)) .with_expected_io(vec![ read_chain_config_io(), print_info_io(), @@ -78,10 +90,18 @@ fn ariadne_parameters_are_on_main_chain_no_updates() { #[test] fn ariadne_parameters_are_on_main_chain_do_update() { + let offchain_mock = OffchainMock::new().with_upsert_d_param( + UtxoId::default(), + new_d_parameter(), + payment_signing_key(), + Ok(Some(McTxHash::default())), + ); let mock_context = MockIOContext::new() .with_file(PC_CONTRACTS_CLI_PATH, "") .with_json_file(CHAIN_CONFIG_FILE_PATH, test_chain_config_content()) .with_json_file(RESOURCES_CONFIG_FILE_PATH, test_resources_config_content()) + .with_json_file("payment.skey", valid_payment_signing_key_content()) + .with_offchain_mocks(OffchainMocks::new_with_mock("http://localhost:1337", offchain_mock)) .with_expected_io(vec![ read_chain_config_io(), print_info_io(), @@ -258,8 +278,16 @@ fn establish_pc_contracts_cli_config_io() -> MockIO { ]) } +fn new_d_parameter() -> DParameter { + DParameter::new(4, 7) +} + fn insert_d_parameter_io() -> MockIO { MockIO::Group(vec![ + prompt_ogmios_configuration_io( + &default_ogmios_service_config(), + &default_ogmios_service_config(), + ), MockIO::prompt( "Enter P, the number of permissioned candidates seats, as a non-negative integer.", Some("0"), @@ -270,12 +298,12 @@ fn insert_d_parameter_io() -> MockIO { Some("0"), "7", ), - establish_pc_contracts_cli_config_io(), - MockIO::file_read("partner-chains-cli-chain-config.json"), - MockIO::run_command( - "./pc-contracts-cli insert-d-parameter --network testnet --d-parameter-permissioned-candidates-count 4 --d-parameter-registered-candidates-count 7 --genesis-utxo 0000000000000000000000000000000000000000000000000000000000000000#0 --kupo-host localhost --kupo-port 1442 --ogmios-host localhost --ogmios-port 1337 --payment-signing-key-file payment.skey", - "{\"endpoint\":\"UpdateDParameter\",\"transactionId\":\"d7127c3b728501a80c27e513d7eadb2c713f10a540441f98dbca45a323118a65\"}" + prompt_with_default_and_save_to_existing_file( + CARDANO_PAYMENT_SIGNING_KEY_FILE, + Some("payment.skey"), + "payment.skey", ), + MockIO::file_read("payment.skey"), MockIO::print( "D-parameter updated to (4, 7). The change will be effective in two main chain epochs.", ), @@ -284,6 +312,10 @@ fn insert_d_parameter_io() -> MockIO { fn update_d_parameter_io() -> MockIO { MockIO::Group(vec![ + prompt_ogmios_configuration_io( + &default_ogmios_service_config(), + &default_ogmios_service_config(), + ), MockIO::prompt( "Enter P, the number of permissioned candidates seats, as a non-negative integer.", Some("6"), @@ -294,12 +326,12 @@ fn update_d_parameter_io() -> MockIO { Some("4"), "7", ), - establish_pc_contracts_cli_config_io(), - MockIO::file_read("partner-chains-cli-chain-config.json"), - MockIO::run_command( - "./pc-contracts-cli update-d-parameter --network testnet --d-parameter-permissioned-candidates-count 4 --d-parameter-registered-candidates-count 7 --genesis-utxo 0000000000000000000000000000000000000000000000000000000000000000#0 --kupo-host localhost --kupo-port 1442 --ogmios-host localhost --ogmios-port 1337 --payment-signing-key-file payment.skey", - "{\"endpoint\":\"UpdateDParameter\",\"transactionId\":\"d7127c3b728501a80c27e513d7eadb2c713f10a540441f98dbca45a323118a65\"}" + prompt_with_default_and_save_to_existing_file( + CARDANO_PAYMENT_SIGNING_KEY_FILE, + Some("payment.skey"), + "payment.skey", ), + MockIO::file_read("payment.skey"), MockIO::print( "D-parameter updated to (4, 7). The change will be effective in two main chain epochs.", ), @@ -446,3 +478,16 @@ fn ariadne_parameters_same_as_in_config_response() -> serde_json::Value { } ) } + +fn valid_payment_signing_key_content() -> serde_json::Value { + json!( + { + "type": "PaymentSigningKeyShelley_ed25519", + "description": "Payment Signing Key", + "cborHex": "58200000000000000000000000000000000000000000000000000000000000000001" + }) +} + +fn payment_signing_key() -> MainchainPrivateKey { + MainchainPrivateKey(hex!("0000000000000000000000000000000000000000000000000000000000000001")) +} diff --git a/toolkit/partner-chains-cli/src/tests/mod.rs b/toolkit/partner-chains-cli/src/tests/mod.rs index a1df781a0..10e6ddf3a 100644 --- a/toolkit/partner-chains-cli/src/tests/mod.rs +++ b/toolkit/partner-chains-cli/src/tests/mod.rs @@ -1,11 +1,13 @@ use crate::io::IOContext; use crate::ogmios::{OgmiosRequest, OgmiosResponse}; +use anyhow::anyhow; use ogmios_client::types::OgmiosTx; +use partner_chains_cardano_offchain::d_param::UpsertDParam; use partner_chains_cardano_offchain::init_governance::InitGovernance; use partner_chains_cardano_offchain::scripts_data::{GetScriptsData, ScriptsData}; use partner_chains_cardano_offchain::OffchainError; use pretty_assertions::assert_eq; -use sidechain_domain::{MainchainAddressHash, MainchainPrivateKey, UtxoId}; +use sidechain_domain::{DParameter, MainchainAddressHash, MainchainPrivateKey, McTxHash, UtxoId}; use sp_core::offchain::Timestamp; use std::collections::HashMap; use std::panic::{catch_unwind, resume_unwind, UnwindSafe}; @@ -253,6 +255,7 @@ pub struct OffchainMock { (UtxoId, MainchainAddressHash, MainchainPrivateKey), Result, >, + pub upsert_d_param: HashMap<(UtxoId, DParameter, [u8; 32]), Result, String>>, } impl OffchainMock { @@ -282,6 +285,16 @@ impl OffchainMock { ..self } } + + pub(crate) fn with_upsert_d_param( + self, + genesis_utxo: UtxoId, + d_param: DParameter, + payment_key: MainchainPrivateKey, + result: Result, String>, + ) -> Self { + Self { upsert_d_param: [((genesis_utxo, d_param, payment_key.0), result)].into(), ..self } + } } impl GetScriptsData for OffchainMock { @@ -308,6 +321,23 @@ impl InitGovernance for OffchainMock { } } +impl UpsertDParam for OffchainMock { + async fn upsert_d_param( + &self, + genesis_utxo: UtxoId, + d_parameter: &DParameter, + payment_signing_key: [u8; 32], + ) -> anyhow::Result> { + self.upsert_d_param + .get(&(genesis_utxo, d_parameter.clone(), payment_signing_key)) + .cloned() + .unwrap_or_else(|| { + Err(format!("No mock for upsert_d_param({genesis_utxo}, {d_parameter:?}, {payment_signing_key:?})")) + }) + .map_err(|err| anyhow!("{err}")) + } +} + impl Drop for MockIOContext { fn drop(&mut self) { if std::thread::panicking() { diff --git a/toolkit/primitives/domain/src/lib.rs b/toolkit/primitives/domain/src/lib.rs index f69c847f7..33c3cf68f 100644 --- a/toolkit/primitives/domain/src/lib.rs +++ b/toolkit/primitives/domain/src/lib.rs @@ -616,13 +616,19 @@ impl GrandpaPublicKey { } } -#[derive(Debug, Clone, PartialEq, Decode, Encode, MaxEncodedLen, TypeInfo, Eq)] +#[derive(Debug, Clone, PartialEq, Decode, Encode, MaxEncodedLen, TypeInfo, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct DParameter { pub num_permissioned_candidates: u16, pub num_registered_candidates: u16, } +impl DParameter { + pub fn new(num_permissioned_candidates: u16, num_registered_candidates: u16) -> Self { + Self { num_permissioned_candidates, num_registered_candidates } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, TypeInfo, PartialOrd, Ord)] pub struct PermissionedCandidateData { pub sidechain_public_key: SidechainPublicKey,