Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: input-output-hk/partner-chains
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 806c1af38586b662291b870c09f31025caeb056f
Choose a base ref
..
head repository: input-output-hk/partner-chains
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a7ccd2c125d2146fef9640ed18f8873e44405f2e
Choose a head ref
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ This changelog is based on [Keep A Changelog](https://keepachangelog.com/en/1.1.

## Changed

* `governance update` command now accepts multiple governance authority key hashes, not just one. It also takes `new-governance-threshold` parameter, which is the number of signatures required to perform governance action.
* `governance init` and `governance update` will set Multisig policy implemented with ALeastN Native Script, instead of custom policy implemented as Plutus Script in partner-chains-smart-contracts. This policy doesn't require to set `required_signers` field in the transaction making it more user friendly.
* Extracted the "Ariadne" committee selection algorithm to the `selection` crate.

6 changes: 4 additions & 2 deletions docs/user-guides/governance/governance.md
Original file line number Diff line number Diff line change
@@ -64,13 +64,15 @@ In version v1.5 command to initialize governance is available in the Partner Cha
--genesis-utxo <GENESIS_UTXO> \
--ogmios-url <OGMIOS_URL> \
--payment-key-file <PAYMENT_KEY_FILE> \
--new-governance-authority <NEW_GOVERNANCE_AUTHORITY>
--new-governance-authority <NEW_GOVERNANCE_AUTHORITY> \
--new-governance-threshold <NEW_GOVERNANCE_THRESHOLD>
```

* `<GENESIS_UTXO>`: The genesis UTXO of the Partner Chain. Same as the one used for `governance init`.
* `<OGMIOS_URL>`: The URL of the Ogmios service connected to the Cardano node, it is optional and defaults to `ws://localhost:1337`.
* `<PAYMENT_KEY_FILE>`: Cardano Shelley Payment Signing Key file (normal or extended) of the current governance authority (ie. hash of its public key should equal current governance authority hey hash).
* `<NEW_GOVERNANCE_AUTHORITY>`: Hex encoded blake2b-224 hash of public key related to private key that will be required to sign governance operations following this operation.
* `<NEW_GOVERNANCE_AUTHORITY>`: List of hex encoded blake2b-224 hashes of public keys related to private keys that will be required to sign governance operations following this operation. Multiple keys can be provided, separated by spaces.
* `<NEW_GOVERNANCE_THRESHOLD>`: Number of keys required to sign a transaction.

In version v1.4 this functionality is available in the smart contracts CLI application `pc-contracts-cli update-governance`.

1 change: 1 addition & 0 deletions toolkit/cli/smart-contracts-commands/Cargo.toml
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ ogmios-client = { workspace = true }
tokio = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
anyhow = { workspace = true }

[dev-dependencies]
hex-literal = { workspace = true }
22 changes: 17 additions & 5 deletions toolkit/cli/smart-contracts-commands/src/governance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::PaymentFilePath;
use anyhow::anyhow;
use partner_chains_cardano_offchain::{
await_tx::FixedDelayRetries, init_governance::run_init_governance,
update_governance::run_update_governance,
@@ -27,7 +28,7 @@ impl GovernanceCmd {
pub struct InitGovernanceCmd {
#[clap(flatten)]
common_arguments: crate::CommonArguments,
/// Governance authority hash to be set.
/// Governance authority to be set
#[arg(long, short = 'g')]
governance_authority: MainchainKeyHash,
#[clap(flatten)]
@@ -58,9 +59,12 @@ impl InitGovernanceCmd {
pub struct UpdateGovernanceCmd {
#[clap(flatten)]
common_arguments: crate::CommonArguments,
/// Governance authority hash to be set.
#[arg(long, short = 'g')]
new_governance_authority: MainchainKeyHash,
/// New governance authorities keys hashes, hex encoded, space delimited, order does not matter
#[arg(short = 'g', long, num_args = 1.., value_delimiter = ' ')]
new_governance_authority: Vec<MainchainKeyHash>,
/// Governance threshold to be set
#[arg(long)]
new_governance_threshold: u8,
#[clap(flatten)]
payment_key_file: PaymentFilePath,
/// Genesis UTXO of the chain
@@ -70,11 +74,19 @@ pub struct UpdateGovernanceCmd {

impl UpdateGovernanceCmd {
pub async fn execute(self) -> crate::CmdResult<()> {
if self.new_governance_threshold > self.new_governance_authority.len() as u8 {
return Err(anyhow!(
"New governance threshold is greater than the number of governance authorities"
)
.into());
}

let payment_key = self.payment_key_file.read_key()?;
let client = self.common_arguments.get_ogmios_client().await?;

run_update_governance(
self.new_governance_authority,
&self.new_governance_authority,
self.new_governance_threshold,
&payment_key,
self.genesis_utxo,
&client,
67 changes: 46 additions & 21 deletions toolkit/offchain/src/update_governance/mod.rs
Original file line number Diff line number Diff line change
@@ -15,16 +15,21 @@ use crate::{
init_governance::transaction::version_oracle_datum_output,
plutus_script::PlutusScript,
};
use anyhow::anyhow;
use cardano_serialization_lib::{
Language, PlutusData, Transaction, TransactionBuilder, TxInputsBuilder,
};
use ogmios_client::{
query_ledger_state::{QueryLedgerState, QueryUtxoByUtxoId},
query_network::QueryNetwork,
transactions::Transactions,
types::OgmiosTx,
};
use sidechain_domain::{MainchainKeyHash, McTxHash, UtxoId, UtxoIndex};
use serde_json::json;
use sidechain_domain::{
MainchainKeyHash, McSmartContractResult,
McSmartContractResult::{TxCBOR, TxHash},
McTxHash, UtxoId, UtxoIndex,
};

#[cfg(test)]
mod test;
@@ -35,12 +40,13 @@ pub async fn run_update_governance<
T: QueryLedgerState + Transactions + QueryNetwork + QueryUtxoByUtxoId,
A: AwaitTx,
>(
new_governance_authority: MainchainKeyHash,
new_governance_authority: &Vec<MainchainKeyHash>,
new_governance_threshold: u8,
payment_key: &CardanoPaymentSigningKey,
genesis_utxo_id: UtxoId,
client: &T,
await_tx: A,
) -> anyhow::Result<OgmiosTx> {
) -> anyhow::Result<McSmartContractResult> {
let ctx = TransactionContext::for_payment_key(payment_key, client).await?;
let governance_data = GovernanceData::get(genesis_utxo_id, client).await?;

@@ -51,6 +57,7 @@ pub async fn run_update_governance<
raw_scripts::VERSION_ORACLE_POLICY,
genesis_utxo_id,
new_governance_authority,
new_governance_threshold,
&governance_data,
costs,
&ctx,
@@ -60,33 +67,51 @@ pub async fn run_update_governance<
)
.await?;

let signed_tx = ctx.sign(&tx);

let response = client.submit_transaction(&signed_tx.to_bytes()).await?;
log::info!("Submitted transaction: {}", hex::encode(response.transaction.id));

await_tx
.await_tx_output(
client,
UtxoId { tx_hash: McTxHash(response.transaction.id), index: UtxoIndex(0) },
)
.await?;

Ok(response.transaction)
if governance_data.policy.is_single_key_policy_for(&ctx.payment_key_hash()) {
let signed_tx = ctx.sign(&tx).to_bytes();
let res = client.submit_transaction(&signed_tx).await.map_err(|e| {
anyhow!(
"Submit governance update transaction request failed: {}, bytes: {}",
e,
hex::encode(signed_tx)
)
})?;
let tx_id = McTxHash(res.transaction.id);
log::info!("Update Governance transaction submitted: {}", hex::encode(tx_id.0));
await_tx
.await_tx_output(
client,
UtxoId { tx_hash: McTxHash(res.transaction.id), index: UtxoIndex(0) },
)
.await?;
Ok(TxHash(tx_id))
} else {
let tx_envelope = json!(
{ "type": "Unwitnessed Tx ConwayEra",
"description": "",
"cborHex": hex::encode(tx.to_bytes())
}
);
log::info!("Transaction envelope: {}", tx_envelope);
Ok(TxCBOR(tx.to_bytes()))
}
}

fn update_governance_tx(
version_oracle_validator: &[u8],
version_oracle_policy: &[u8],
genesis_utxo: UtxoId,
new_governance_authority: MainchainKeyHash,
new_governance_authority: &Vec<MainchainKeyHash>,
new_governance_threshold: u8,
governance_data: &GovernanceData,
costs: Costs,
ctx: &TransactionContext,
) -> anyhow::Result<Transaction> {
let multi_sig_policy =
SimpleAtLeastN { threshold: 1, key_hashes: vec![new_governance_authority.0] }
.to_csl_native_script();
let multi_sig_policy = SimpleAtLeastN {
threshold: new_governance_threshold.into(),
key_hashes: new_governance_authority.iter().map(|key| key.0).collect(),
}
.to_csl_native_script();
let version_oracle_validator =
PlutusScript::from_wrapped_cbor(version_oracle_validator, Language::new_plutus_v2())?
.apply_data(genesis_utxo)?;
3 changes: 2 additions & 1 deletion toolkit/offchain/src/update_governance/test.rs
Original file line number Diff line number Diff line change
@@ -125,7 +125,8 @@ fn test_update_governance_tx() -> Transaction {
test_values::VERSION_ORACLE_VALIDATOR,
test_values::VERSION_ORACLE_POLICY,
genesis_utxo().to_domain(),
new_governance_authority(),
&vec![new_governance_authority()],
1,
&governance_data(),
test_costs(),
&tx_context(),
3 changes: 2 additions & 1 deletion toolkit/offchain/tests/integration_tests.rs
Original file line number Diff line number Diff line change
@@ -296,7 +296,8 @@ async fn run_update_goveranance<
genesis_utxo: UtxoId,
) {
let _ = update_governance::run_update_governance(
EVE_PUBLIC_KEY_HASH,
&vec![EVE_PUBLIC_KEY_HASH],
1,
&governance_authority_payment_key(),
genesis_utxo,
client,