Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc cleanups #432

Merged
merged 5 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions toolkit/offchain/src/csl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,15 +489,7 @@ impl TransactionBuilderExt for TransactionBuilder {
.with_plutus_data(datum)
.next()?;
let ma = MultiAsset::new().with_asset_amount(&policy.empty_name_asset(), 1u64)?;
let output = amount_builder.with_coin_and_asset(&0u64.into(), &ma).build()?;
let min_ada = MinOutputAdaCalculator::new(
&output,
&DataCost::new_coins_per_byte(
&ctx.protocol_parameters.min_utxo_deposit_coefficient.into(),
),
)
.calculate_ada()?;
let output = amount_builder.with_coin_and_asset(&min_ada, &ma).build()?;
let output = amount_builder.with_minimum_ada_and_asset(&ma, ctx)?.build()?;
self.add_output(&output)
}

Expand Down
6 changes: 3 additions & 3 deletions toolkit/offchain/src/d_param/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::csl::{
empty_asset_name, get_builder_config, unit_plutus_data, CostStore, Costs, InputsBuilderExt,
TransactionBuilderExt, TransactionContext,
};
use crate::init_governance::{self, GovernanceData};
use crate::governance::GovernanceData;
use crate::plutus_script::PlutusScript;
use anyhow::anyhow;
use cardano_serialization_lib::{PlutusData, Transaction, TransactionBuilder, TxInputsBuilder};
Expand Down Expand Up @@ -132,7 +132,7 @@ async fn insert_d_param<C: QueryLedgerState + Transactions + QueryNetwork>(
genesis_utxo: UtxoId,
client: &C,
) -> anyhow::Result<McTxHash> {
let gov_data = init_governance::get_governance_data(genesis_utxo, client).await?;
let gov_data = GovernanceData::get(genesis_utxo, client).await?;

let tx = Costs::calculate_costs(
|costs| mint_d_param_token_tx(validator, policy, d_parameter, &gov_data, costs, &ctx),
Expand Down Expand Up @@ -162,7 +162,7 @@ async fn update_d_param<C: QueryLedgerState + Transactions + QueryNetwork>(
genesis_utxo: UtxoId,
client: &C,
) -> anyhow::Result<McTxHash> {
let governance_data = init_governance::get_governance_data(genesis_utxo, client).await?;
let governance_data = GovernanceData::get(genesis_utxo, client).await?;

let tx = Costs::calculate_costs(
|costs| {
Expand Down
2 changes: 1 addition & 1 deletion toolkit/offchain/src/d_param/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{mint_d_param_token_tx, update_d_param_tx};
use crate::init_governance::GovernanceData;
use crate::governance::GovernanceData;
use crate::{
csl::{empty_asset_name, TransactionContext},
test_values::*,
Expand Down
96 changes: 96 additions & 0 deletions toolkit/offchain/src/governance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use crate::csl::{NetworkTypeExt, OgmiosUtxoExt};
use crate::plutus_script;
use crate::scripts_data;
use cardano_serialization_lib::*;
use ogmios_client::{
query_ledger_state::QueryLedgerState, query_network::QueryNetwork, types::OgmiosUtxo,
};
use partner_chains_plutus_data::version_oracle::VersionOracleDatum;
use sidechain_domain::UtxoId;

#[derive(Clone, Debug)]
pub(crate) struct GovernanceData {
pub(crate) policy_script: plutus_script::PlutusScript,
pub(crate) utxo: OgmiosUtxo,
}

impl GovernanceData {
pub fn utxo_id(&self) -> sidechain_domain::UtxoId {
self.utxo.utxo_id()
}

pub(crate) fn utxo_id_as_tx_input(&self) -> TransactionInput {
TransactionInput::new(
&TransactionHash::from_bytes(self.utxo_id().tx_hash.0.to_vec()).unwrap(),
self.utxo_id().index.0.into(),
)
}

async fn get_governance_utxo<T: QueryLedgerState + QueryNetwork>(
genesis_utxo: UtxoId,
client: &T,
) -> Result<OgmiosUtxo, JsError> {
let network = client
.shelley_genesis_configuration()
.await
.map_err(|e| {
JsError::from_str(&format!("Could not get Shelley Genesis Configuration: {}", e))
})?
.network;

let (_, version_oracle_policy, validator_address) =
scripts_data::version_scripts_and_address(genesis_utxo, network.to_csl()).map_err(
|e| {
JsError::from_str(&format!(
"Could not get Version Oracle Script Data for: {}, {}",
genesis_utxo, e
))
},
)?;

let utxos = client.query_utxos(&[validator_address.clone()]).await.map_err(|e| {
JsError::from_str(&format!(
"Could not query UTXOs Governance Validator at {}: {}",
validator_address, e
))
})?;

utxos
.into_iter()
.find(|utxo| {
let correct_datum =
utxo.get_plutus_data()
.and_then(|plutus_data| VersionOracleDatum::try_from(plutus_data).ok())
.map(|data| data.version_oracle == 32)
.unwrap_or(false);

let contains_version_oracle_token =
utxo.value.native_tokens.contains_key(&version_oracle_policy.script_hash());
correct_datum && contains_version_oracle_token
})
.ok_or_else(|| JsError::from_str("Could not find governance versioning UTXO. This most likely means that governance was not properly set up on Cardano using governance init command."))
}

pub(crate) async fn get<T: QueryLedgerState + QueryNetwork>(
genesis_utxo: UtxoId,
client: &T,
) -> Result<GovernanceData, JsError> {
let utxo = Self::get_governance_utxo(genesis_utxo, client).await?;
let policy_script = read_policy(&utxo)?;
Ok(GovernanceData { policy_script, utxo })
}
}

fn read_policy(governance_utxo: &OgmiosUtxo) -> Result<plutus_script::PlutusScript, JsError> {
let script = governance_utxo
.script
.clone()
.ok_or_else(|| JsError::from_str("No 'script' in governance UTXO"))?;
plutus_script::PlutusScript::from_ogmios(script).map_err(|e| {
JsError::from_str(&format!(
"Cannot convert script from UTXO {}: {}",
governance_utxo.to_domain(),
e
))
})
}
97 changes: 2 additions & 95 deletions toolkit/offchain/src/init_governance/mod.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
use crate::cardano_keys::CardanoPaymentSigningKey;
use crate::csl::Costs;
use crate::csl::OgmiosUtxoExt;
use crate::plutus_script;
use crate::scripts_data;
use crate::{
await_tx::{AwaitTx, FixedDelayRetries},
csl::{key_hash_address, NetworkTypeExt},
csl::key_hash_address,
OffchainError,
};
use anyhow::anyhow;
use cardano_serialization_lib::*;
use ogmios_client::{
query_ledger_state::{QueryLedgerState, QueryUtxoByUtxoId},
query_network::QueryNetwork,
transactions::Transactions,
types::{OgmiosTx, OgmiosUtxo},
types::OgmiosTx,
};
use partner_chains_plutus_data::version_oracle::VersionOracleDatum;
use sidechain_domain::{MainchainKeyHash, UtxoId};

#[cfg(test)]
Expand Down Expand Up @@ -113,92 +109,3 @@ pub async fn run_init_governance<

Ok((genesis_utxo.to_domain(), result.transaction))
}

pub(crate) async fn get_governance_utxo<T: QueryLedgerState + Transactions + QueryNetwork>(
genesis_utxo: UtxoId,
client: &T,
) -> Result<OgmiosUtxo, JsError> {
let network = client
.shelley_genesis_configuration()
.await
.map_err(|e| {
JsError::from_str(&format!("Could not get Shelley Genesis Configuration: {}", e))
})?
.network;

let (_, version_oracle_policy, validator_address) =
scripts_data::version_scripts_and_address(genesis_utxo, network.to_csl()).map_err(|e| {
JsError::from_str(&format!(
"Could not get Version Oracle Script Data for: {}, {}",
genesis_utxo, e
))
})?;

let utxos = client.query_utxos(&[validator_address.clone()]).await.map_err(|e| {
JsError::from_str(&format!(
"Could not query UTXOs Governance Validator at {}: {}",
validator_address, e
))
})?;

utxos
.into_iter()
.find(|utxo| {
let correct_datum =
utxo.get_plutus_data()
.and_then(|plutus_data| VersionOracleDatum::try_from(plutus_data).ok())
.map(|data| data.version_oracle == 32)
.unwrap_or(false);

let contains_version_oracle_token =
utxo.value.native_tokens.contains_key(&version_oracle_policy.script_hash());
correct_datum && contains_version_oracle_token
})
.ok_or_else(|| JsError::from_str("Could not find governance versioning UTXO. This most likely means that governance was not properly set up on Cardano using governance init command."))
}

#[derive(Clone, Debug)]
pub(crate) struct GovernanceData {
pub(crate) policy_script: plutus_script::PlutusScript,
pub(crate) utxo: OgmiosUtxo,
}

impl GovernanceData {
pub fn utxo_id(&self) -> sidechain_domain::UtxoId {
self.utxo.utxo_id()
}
}

impl GovernanceData {
pub(crate) fn utxo_id_as_tx_input(&self) -> TransactionInput {
TransactionInput::new(
&TransactionHash::from_bytes(self.utxo_id().tx_hash.0.to_vec()).unwrap(),
self.utxo_id().index.0.into(),
)
}
}

pub(crate) async fn get_governance_data<T: QueryLedgerState + Transactions + QueryNetwork>(
genesis_utxo: UtxoId,
client: &T,
) -> Result<GovernanceData, JsError> {
let utxo = get_governance_utxo(genesis_utxo, client).await?;
let policy_script = read_policy(&utxo)?;
Ok(GovernanceData { policy_script, utxo })
}

pub(crate) fn read_policy(
governance_utxo: &OgmiosUtxo,
) -> Result<plutus_script::PlutusScript, JsError> {
let script = governance_utxo
.script
.clone()
.ok_or_else(|| JsError::from_str("No 'script' in governance UTXO"))?;
plutus_script::PlutusScript::from_ogmios(script).map_err(|e| {
JsError::from_str(&format!(
"Cannot convert script from UTXO {}: {}",
governance_utxo.to_domain(),
e
))
})
}
4 changes: 2 additions & 2 deletions toolkit/offchain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub mod cardano_keys;
pub mod csl;
/// Supports D-Parameter upsert
pub mod d_param;
/// Governance data types
pub mod governance;
/// Supports governance initialization
pub mod init_governance;
#[cfg(test)]
Expand All @@ -23,8 +25,6 @@ pub mod reserve;
pub mod scripts_data;
#[cfg(test)]
pub mod test_values;
/// Module for interaction with the untyped plutus scripts
pub mod untyped_plutus;
/// Supports governance updates
pub mod update_governance;

Expand Down
8 changes: 4 additions & 4 deletions toolkit/offchain/src/permissioned_candidates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::csl::{
empty_asset_name, get_builder_config, CostStore, Costs, InputsBuilderExt,
TransactionBuilderExt, TransactionContext,
};
use crate::init_governance::{self, GovernanceData};
use crate::governance::GovernanceData;
use crate::plutus_script::PlutusScript;
use crate::{cardano_keys::CardanoPaymentSigningKey, scripts_data};
use anyhow::anyhow;
Expand Down Expand Up @@ -70,7 +70,7 @@ pub async fn upsert_permissioned_candidates<
let ctx = TransactionContext::for_payment_key(payment_signing_key, ogmios_client).await?;
let (validator, policy) =
scripts_data::permissioned_candidates_scripts(genesis_utxo, ctx.network)?;
let governance_data = init_governance::get_governance_data(genesis_utxo, ogmios_client).await?;
let governance_data = GovernanceData::get(genesis_utxo, ogmios_client).await?;
let validator_address = validator.address_bech32(ctx.network)?;
let validator_utxos = ogmios_client.query_utxos(&[validator_address]).await?;
let mut candidates = candidates.to_owned();
Expand Down Expand Up @@ -229,7 +229,7 @@ fn mint_permissioned_candidates_token_tx(
validator: &PlutusScript,
policy: &PlutusScript,
permissioned_candidates: &[PermissionedCandidateData],
governance_data: &init_governance::GovernanceData,
governance_data: &GovernanceData,
costs: Costs,
ctx: &TransactionContext,
) -> anyhow::Result<Transaction> {
Expand Down Expand Up @@ -308,7 +308,7 @@ mod tests {
use super::{mint_permissioned_candidates_token_tx, update_permissioned_candidates_tx};
use crate::{
csl::{empty_asset_name, Costs, TransactionContext},
init_governance::GovernanceData,
governance::GovernanceData,
plutus_script::PlutusScript,
test_values::*,
};
Expand Down
32 changes: 25 additions & 7 deletions toolkit/offchain/src/plutus_script.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use crate::csl::*;
use anyhow::{anyhow, Context, Error};
use cardano_serialization_lib::{
Address, JsError, Language, LanguageKind, NetworkIdKind, PlutusData, ScriptHash,
};
use ogmios_client::types::{OgmiosScript, OgmiosScript::Plutus};
use plutus::ToDatum;
use sidechain_domain::{AssetId, AssetName, PolicyId};
use uplc::ast::{DeBruijn, Program};

use crate::{csl::*, untyped_plutus::*};
use uplc::{
ast::{DeBruijn, Program},
plutus_data,
};

/// Wraps a Plutus script cbor
#[derive(Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -41,12 +43,21 @@ impl PlutusScript {
/// This function is needed to create [PlutusScript] from scripts in [raw_scripts],
/// which are encoded as a cbor byte string containing the cbor of the script
/// itself. This function removes this layer of wrapping.
pub fn from_wrapped_cbor(cbor: &[u8], language: Language) -> anyhow::Result<Self> {
Ok(Self::from_cbor(&unwrap_one_layer_of_cbor(cbor)?, language))
pub fn from_wrapped_cbor(
plutus_script_raw_cbor: &[u8],
language: Language,
) -> anyhow::Result<Self> {
let plutus_script_bytes: uplc::PlutusData = minicbor::decode(plutus_script_raw_cbor)?;
let plutus_script_bytes = match plutus_script_bytes {
uplc::PlutusData::BoundedBytes(bb) => Ok(bb),
_ => Err(anyhow!("expected validator raw to be BoundedBytes")),
}?;
Ok(Self::from_cbor(&plutus_script_bytes, language))
}

pub fn apply_data(self, data: impl ToDatum) -> Result<Self, anyhow::Error> {
let data = datum_to_uplc_plutus_data(&data.to_datum());
let data = plutus_data(&minicbor::to_vec(data.to_datum()).expect("to_vec is Infallible"))
.expect("trasformation from PC Datum to pallas PlutusData can't fail");
self.apply_uplc_data(data)
}

Expand All @@ -69,7 +80,14 @@ impl PlutusScript {
// Returns PlutusData representation of the given script. It is done in the same way as on-chain code expects.
// First, the Address is created, then it is converted to PlutusData.
pub fn address_data(&self, network: NetworkIdKind) -> anyhow::Result<uplc::PlutusData> {
csl_plutus_data_to_uplc(&PlutusData::from_address(&self.address(network))?)
let mut se = cbor_event::se::Serializer::new_vec();
cbor_event::se::Serialize::serialize(
&PlutusData::from_address(&self.address(network))?,
&mut se,
)
.map_err(|e| anyhow!(e))?;
let bytes = se.finalize();
minicbor::decode(&bytes).map_err(|e| anyhow!(e.to_string()))
}

/// Returns bech32 address of the given PlutusV2 script
Expand Down
4 changes: 2 additions & 2 deletions toolkit/offchain/src/reserve/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
get_builder_config, CostStore, Costs, MultiAssetExt, OgmiosUtxoExt, TransactionBuilderExt,
TransactionContext, TransactionOutputAmountBuilderExt,
},
init_governance::{get_governance_data, GovernanceData},
governance::GovernanceData,
scripts_data::ReserveScripts,
};
use cardano_serialization_lib::{
Expand Down Expand Up @@ -51,7 +51,7 @@ pub async fn create_reserve_utxo<
await_tx: &A,
) -> anyhow::Result<McTxHash> {
let ctx = TransactionContext::for_payment_key(payment_key, client).await?;
let governance = get_governance_data(genesis_utxo, client).await?;
let governance = GovernanceData::get(genesis_utxo, client).await?;
let reserve = ReserveData::get(genesis_utxo, &ctx, client).await?;

let tx = Costs::calculate_costs(
Expand Down
Loading
Loading