diff --git a/Cargo.toml b/Cargo.toml index d2a4d61a..6f1d52c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,8 @@ # this is for the new crate structure. The legacy code (current CML) still resides in the `rust` directory. members = [ + "blockfrost/rust", + "blockfrost/wasm", "chain/rust", "chain/wasm", "chain/wasm/json-gen", diff --git a/blockfrost/rust/Cargo.toml b/blockfrost/rust/Cargo.toml new file mode 100644 index 00000000..8a9f998d --- /dev/null +++ b/blockfrost/rust/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "cml-blockfrost" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +cml-chain = { path = "../../chain/rust", version = "5.1.0" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.57" +thiserror = "1.0.37" + +# only used for direct_api +blockfrost = { version = "1.0.1", optional = true } + +[features] +# This allows directly hooking into the blockfrost-rust crate +direct_api = ["blockfrost"] diff --git a/blockfrost/rust/src/direct_api.rs b/blockfrost/rust/src/direct_api.rs new file mode 100644 index 00000000..294c223b --- /dev/null +++ b/blockfrost/rust/src/direct_api.rs @@ -0,0 +1,93 @@ +use blockfrost::{BlockfrostAPI, BlockfrostError}; +use cml_chain::{ + builders::tx_builder::{TransactionBuilderConfigBuilder, TxBuilderConfigField}, + fees::LinearFee, + plutus::ExUnitPrices, + Coin, SubCoin, +}; +use std::str::FromStr; + +use crate::{parse_cost_models, BlockfrostParamsParseError}; + +#[derive(Debug, thiserror::Error)] +pub enum BlockfrostTxBuilderConfigError { + #[error("Parsing: {0}")] + Parsing(#[from] BlockfrostParamsParseError), + #[error("Blockfrost: {0}")] + Blockfrost(#[from] BlockfrostError), +} + +/** + * Completely automated config creation via supplied blockfrost API. + * Both calls blockfrost via the passed API to get enough information + * and also parses the information to make a TransactionBuilderConfigBuilder + * with all necessary protocol parameter information set + */ +pub async fn make_tx_builder_cfg( + api: &BlockfrostAPI, +) -> Result { + let params = api.epochs_latest_parameters().await?; + let coins_per_utxo_byte = params + .coins_per_utxo_word + .ok_or(BlockfrostParamsParseError::MissingField( + TxBuilderConfigField::CoinsPerUtxoBytes, + )) + .and_then(|c| { + Coin::from_str(&c).map_err(|_| { + BlockfrostParamsParseError::IncorrectFormat(TxBuilderConfigField::CoinsPerUtxoBytes) + }) + })?; + let pool_deposit = Coin::from_str(¶ms.pool_deposit).map_err(|_| { + BlockfrostParamsParseError::IncorrectFormat(TxBuilderConfigField::PoolDeposit) + })?; + let key_deposit = Coin::from_str(¶ms.key_deposit).map_err(|_| { + BlockfrostParamsParseError::IncorrectFormat(TxBuilderConfigField::KeyDeposit) + })?; + let max_value_size = params + .max_val_size + .ok_or(BlockfrostParamsParseError::MissingField( + TxBuilderConfigField::MaxValueSize, + )) + .and_then(|c| { + u32::from_str(&c).map_err(|_| { + BlockfrostParamsParseError::IncorrectFormat(TxBuilderConfigField::MaxValueSize) + }) + })?; + let ex_unit_prices = match (params.price_mem, params.price_step) { + (Some(price_mem), Some(price_step)) => Ok(ExUnitPrices::new( + SubCoin::from_base10_f32(price_mem), + SubCoin::from_base10_f32(price_step), + )), + _ => Err(BlockfrostParamsParseError::MissingField( + TxBuilderConfigField::ExUnitPrices, + )), + }?; + let fee_algo = LinearFee::new(params.min_fee_a as u64, params.min_fee_b as u64); + let max_tx_size = params.max_tx_size as u32; + let collateral_percentage = + params + .collateral_percent + .ok_or(BlockfrostParamsParseError::MissingField( + TxBuilderConfigField::CollateralPercentage, + ))? as u32; + let max_collateral_inputs = + params + .max_collateral_inputs + .ok_or(BlockfrostParamsParseError::MissingField( + TxBuilderConfigField::MaxCollateralInputs, + ))? as u32; + let mut config_builder = TransactionBuilderConfigBuilder::new() + .fee_algo(fee_algo) + .coins_per_utxo_byte(coins_per_utxo_byte) + .pool_deposit(pool_deposit) + .key_deposit(key_deposit) + .max_value_size(max_value_size) + .max_tx_size(max_tx_size) + .ex_unit_prices(ex_unit_prices) + .collateral_percentage(collateral_percentage) + .max_collateral_inputs(max_collateral_inputs); + if let Some(cost_models) = params.cost_models { + config_builder = config_builder.cost_models(parse_cost_models(&cost_models)?); + } + Ok(config_builder) +} diff --git a/blockfrost/rust/src/lib.rs b/blockfrost/rust/src/lib.rs new file mode 100644 index 00000000..6334b869 --- /dev/null +++ b/blockfrost/rust/src/lib.rs @@ -0,0 +1,110 @@ +use cml_chain::{ + builders::tx_builder::TxBuilderConfigField, + plutus::{CostModels, Language}, + DeserializeError, +}; +use std::collections::HashMap; + +#[cfg(feature = "direct_api")] +pub mod direct_api; + +#[derive(Debug, thiserror::Error)] +pub enum CostModelsError { + #[error("Invalid object format: {0:?}")] + InvalidFormat(serde_json::Value), + #[error("Invalid cost format: {0:?}")] + InvalidCost(Option), + #[error("Invalid op count: {0}")] + OpCount(usize), + // likely shouldn't happen as this would be checked earlier + #[error("Couldn't set: {0}")] + Setting(#[from] DeserializeError), +} + +#[derive(Debug, thiserror::Error)] +pub enum BlockfrostParamsParseError { + #[error("Missing field: {0:?}")] + MissingField(TxBuilderConfigField), + #[error("Incorrect format in field: {0:?}")] + IncorrectFormat(TxBuilderConfigField), + #[error("Invalid cost models {0:?} for language {1:?}")] + CostModels(CostModelsError, Language), +} + +pub fn parse_cost_model( + serde_value: &serde_json::Value, + language: Language, +) -> Result, CostModelsError> { + if let serde_json::Value::Object(cost_obj) = serde_value { + let mut costs = vec![]; + // bad idea to assume it's ordered - depends on feature enabled + // and could possibly change + let mut keys: Vec = cost_obj.keys().cloned().collect(); + if keys.len() != CostModels::op_count(language) { + return Err(CostModelsError::OpCount(keys.len())); + } + keys.sort(); + for key in keys { + let cost = cost_obj + .get(&key) + .and_then(|c| c.as_i64()) + .ok_or_else(|| CostModelsError::InvalidCost(cost_obj.get(&key).cloned()))?; + costs.push(cost); + } + Ok(costs) + } else { + Err(CostModelsError::InvalidFormat(serde_value.clone())) + } +} + +pub fn parse_sancho_cost_model( + serde_value: &serde_json::Value, +) -> Result, CostModelsError> { + if let serde_json::Value::Object(cost_obj) = serde_value { + let mut costs = vec![]; + for i in 0..CostModels::PLUTUS_V3_COUNT { + let cost = cost_obj + .get(&i.to_string()) + .and_then(|val| val.as_i64()) + .ok_or_else(|| { + CostModelsError::InvalidCost(cost_obj.get(&i.to_string()).cloned()) + })?; + costs.push(cost); + } + Ok(costs) + } else { + Err(CostModelsError::InvalidFormat(serde_value.clone())) + } +} + +pub fn parse_cost_models( + costs: &HashMap, +) -> Result { + let mut cost_models = CostModels::default(); + if let Some(plutus_v1) = costs.get("PlutusV1") { + cost_models + .set_plutus_v1( + parse_cost_model(plutus_v1, Language::PlutusV1) + .map_err(|e| BlockfrostParamsParseError::CostModels(e, Language::PlutusV1))?, + ) + .map_err(|e| BlockfrostParamsParseError::CostModels(e.into(), Language::PlutusV1))?; + } + if let Some(plutus_v2) = costs.get("PlutusV2") { + cost_models + .set_plutus_v2( + parse_cost_model(plutus_v2, Language::PlutusV2) + .map_err(|e| BlockfrostParamsParseError::CostModels(e, Language::PlutusV2))?, + ) + .map_err(|e| BlockfrostParamsParseError::CostModels(e.into(), Language::PlutusV2))?; + } + // Sancho testnet has a very different format for some reason + if let Some(plutus_v3) = costs.get("PlutusV3") { + cost_models + .set_plutus_v3( + parse_sancho_cost_model(plutus_v3) + .map_err(|e| BlockfrostParamsParseError::CostModels(e, Language::PlutusV3))?, + ) + .map_err(|e| BlockfrostParamsParseError::CostModels(e.into(), Language::PlutusV3))?; + } + Ok(cost_models) +} diff --git a/blockfrost/wasm/Cargo.toml b/blockfrost/wasm/Cargo.toml new file mode 100644 index 00000000..e99df592 --- /dev/null +++ b/blockfrost/wasm/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "cml-blockfrost-wasm" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +cml-blockfrost = { path = "../rust", version = "0.1.0" } +cml-chain = { path = "../../chain/rust", version = "5.1.0" } +cml-chain-wasm = { path = "../../chain/wasm", version = "5.1.0" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.57" +wasm-bindgen = { version = "0.2", features=["serde-serialize"] } \ No newline at end of file diff --git a/blockfrost/wasm/src/lib.rs b/blockfrost/wasm/src/lib.rs new file mode 100644 index 00000000..0d0148de --- /dev/null +++ b/blockfrost/wasm/src/lib.rs @@ -0,0 +1,836 @@ +use cml_blockfrost::{parse_cost_models, BlockfrostParamsParseError}; +use cml_chain::{ + builders::tx_builder::{TransactionBuilderConfigBuilder, TxBuilderConfigField}, + fees::LinearFee, + plutus::ExUnitPrices, + Coin, SubCoin, +}; +use std::str::FromStr; +use wasm_bindgen::prelude::{wasm_bindgen, JsError}; + +fn parse_string_coin_param( + params: &serde_json::Value, + key: &str, + field: TxBuilderConfigField, +) -> Result { + params + .get(key) + .ok_or(BlockfrostParamsParseError::MissingField(field)) + .and_then(|v| { + match v { + serde_json::Value::String(c) => Coin::from_str(c).ok(), + _ => None, + } + .ok_or(BlockfrostParamsParseError::IncorrectFormat(field)) + }) +} + +fn parse_u64_param( + params: &serde_json::Value, + key: &str, + field: TxBuilderConfigField, +) -> Result { + params + .get(key) + .ok_or(BlockfrostParamsParseError::MissingField(field)) + .and_then(|v| { + v.as_u64() + .ok_or(BlockfrostParamsParseError::IncorrectFormat(field)) + }) +} + +fn make_tx_builder_cfg_impl( + params: serde_json::Value, +) -> Result { + let coins_per_utxo_byte = parse_string_coin_param( + ¶ms, + "coins_per_utxo_word", + TxBuilderConfigField::CoinsPerUtxoBytes, + )?; + let pool_deposit = + parse_string_coin_param(¶ms, "pool_deposit", TxBuilderConfigField::PoolDeposit)?; + let key_deposit = + parse_string_coin_param(¶ms, "key_deposit", TxBuilderConfigField::KeyDeposit)?; + let max_value_size = + parse_string_coin_param(¶ms, "max_val_size", TxBuilderConfigField::MaxValueSize)? + as u32; + let ex_unit_prices = match (params.get("price_mem"), params.get("price_step")) { + (Some(price_mem), Some(price_step)) => match (price_mem.as_f64(), price_step.as_f64()) { + (Some(price_mem), Some(price_step)) => Ok(ExUnitPrices::new( + SubCoin::from_base10_f32(price_mem as f32), + SubCoin::from_base10_f32(price_step as f32), + )), + _ => Err(BlockfrostParamsParseError::IncorrectFormat( + TxBuilderConfigField::ExUnitPrices, + )), + }, + _ => Err(BlockfrostParamsParseError::MissingField( + TxBuilderConfigField::ExUnitPrices, + )), + }?; + let fee_algo = match (params.get("min_fee_a"), params.get("min_fee_b")) { + (Some(min_fee_a), Some(min_fee_b)) => match (min_fee_a.as_u64(), min_fee_b.as_u64()) { + (Some(min_fee_a), Some(min_fee_b)) => Ok(LinearFee::new(min_fee_a, min_fee_b)), + _ => Err(BlockfrostParamsParseError::IncorrectFormat( + TxBuilderConfigField::ExUnitPrices, + )), + }, + _ => Err(BlockfrostParamsParseError::MissingField( + TxBuilderConfigField::ExUnitPrices, + )), + }?; + let max_tx_size = + parse_u64_param(¶ms, "max_tx_size", TxBuilderConfigField::MaxTxSize)? as u32; + let collateral_percentage = parse_u64_param( + ¶ms, + "collateral_percent", + TxBuilderConfigField::CollateralPercentage, + )? as u32; + let max_collateral_inputs = parse_u64_param( + ¶ms, + "max_collateral_inputs", + TxBuilderConfigField::MaxCollateralInputs, + )? as u32; + let mut config_builder = TransactionBuilderConfigBuilder::new() + .fee_algo(fee_algo) + .coins_per_utxo_byte(coins_per_utxo_byte) + .pool_deposit(pool_deposit) + .key_deposit(key_deposit) + .max_value_size(max_value_size) + .max_tx_size(max_tx_size) + .ex_unit_prices(ex_unit_prices) + .collateral_percentage(collateral_percentage) + .max_collateral_inputs(max_collateral_inputs); + if let Some(cost_models_value) = params.get("cost_models") { + if let serde_json::Value::Object(cost_models) = cost_models_value { + let cost_models_hashmap = cost_models + .into_iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + config_builder = config_builder.cost_models(parse_cost_models(&cost_models_hashmap)?); + } else { + return Err(BlockfrostParamsParseError::IncorrectFormat( + TxBuilderConfigField::CostModels, + )); + } + } + Ok(config_builder) +} + +/** + * Parses Blockfrost's `epochs/latest/parameters` response JSON to make a TransactionBuilderConfigBuilder + * + * This simplifies `TransactionBuilder` creation if using blockfrost for protocol parameters + */ +#[wasm_bindgen] +pub fn blockfrost_make_tx_builder_cfg( + response_json: &str, +) -> Result { + let params: serde_json::Value = + serde_json::from_str(response_json).map_err(|e| JsError::new(&e.to_string()))?; + make_tx_builder_cfg_impl(params) + .map(Into::into) + .map_err(Into::into) +} + +#[cfg(test)] +mod tests { + use cml_chain::plutus::{CostModels, Language}; + + use super::*; + + #[test] + fn tx_builder_config_from_json() { + let response_json = "{ + \"epoch\": 225, + \"min_fee_a\": 44, + \"min_fee_b\": 155381, + \"max_block_size\": 65536, + \"max_tx_size\": 16384, + \"max_block_header_size\": 1100, + \"key_deposit\": \"2000000\", + \"pool_deposit\": \"500000000\", + \"e_max\": 18, + \"n_opt\": 150, + \"a0\": 0.3, + \"rho\": 0.003, + \"tau\": 0.2, + \"decentralisation_param\": 0.5, + \"extra_entropy\": null, + \"protocol_major_ver\": 2, + \"protocol_minor_ver\": 0, + \"min_utxo\": \"1000000\", + \"min_pool_cost\": \"340000000\", + \"nonce\": \"1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81\", + \"cost_models\": { + \"PlutusV2\": { + \"addInteger-cpu-arguments-intercept\": 205665, + \"addInteger-cpu-arguments-slope\": 812, + \"addInteger-memory-arguments-intercept\": 1, + \"addInteger-memory-arguments-slope\": 1, + \"appendByteString-cpu-arguments-intercept\": 1000, + \"appendByteString-cpu-arguments-slope\": 571, + \"appendByteString-memory-arguments-intercept\": 0, + \"appendByteString-memory-arguments-slope\": 1, + \"appendString-cpu-arguments-intercept\": 1000, + \"appendString-cpu-arguments-slope\": 24177, + \"appendString-memory-arguments-intercept\": 4, + \"appendString-memory-arguments-slope\": 1, + \"bData-cpu-arguments\": 1000, + \"bData-memory-arguments\": 32, + \"blake2b_256-cpu-arguments-intercept\": 117366, + \"blake2b_256-cpu-arguments-slope\": 10475, + \"blake2b_256-memory-arguments\": 4, + \"cekApplyCost-exBudgetCPU\": 23000, + \"cekApplyCost-exBudgetMemory\": 100, + \"cekBuiltinCost-exBudgetCPU\": 23000, + \"cekBuiltinCost-exBudgetMemory\": 100, + \"cekConstCost-exBudgetCPU\": 23000, + \"cekConstCost-exBudgetMemory\": 100, + \"cekDelayCost-exBudgetCPU\": 23000, + \"cekDelayCost-exBudgetMemory\": 100, + \"cekForceCost-exBudgetCPU\": 23000, + \"cekForceCost-exBudgetMemory\": 100, + \"cekLamCost-exBudgetCPU\": 23000, + \"cekLamCost-exBudgetMemory\": 100, + \"cekStartupCost-exBudgetCPU\": 100, + \"cekStartupCost-exBudgetMemory\": 100, + \"cekVarCost-exBudgetCPU\": 23000, + \"cekVarCost-exBudgetMemory\": 100, + \"chooseData-cpu-arguments\": 19537, + \"chooseData-memory-arguments\": 32, + \"chooseList-cpu-arguments\": 175354, + \"chooseList-memory-arguments\": 32, + \"chooseUnit-cpu-arguments\": 46417, + \"chooseUnit-memory-arguments\": 4, + \"consByteString-cpu-arguments-intercept\": 221973, + \"consByteString-cpu-arguments-slope\": 511, + \"consByteString-memory-arguments-intercept\": 0, + \"consByteString-memory-arguments-slope\": 1, + \"constrData-cpu-arguments\": 89141, + \"constrData-memory-arguments\": 32, + \"decodeUtf8-cpu-arguments-intercept\": 497525, + \"decodeUtf8-cpu-arguments-slope\": 14068, + \"decodeUtf8-memory-arguments-intercept\": 4, + \"decodeUtf8-memory-arguments-slope\": 2, + \"divideInteger-cpu-arguments-constant\": 196500, + \"divideInteger-cpu-arguments-model-arguments-intercept\": 453240, + \"divideInteger-cpu-arguments-model-arguments-slope\": 220, + \"divideInteger-memory-arguments-intercept\": 0, + \"divideInteger-memory-arguments-minimum\": 1, + \"divideInteger-memory-arguments-slope\": 1, + \"encodeUtf8-cpu-arguments-intercept\": 1000, + \"encodeUtf8-cpu-arguments-slope\": 28662, + \"encodeUtf8-memory-arguments-intercept\": 4, + \"encodeUtf8-memory-arguments-slope\": 2, + \"equalsByteString-cpu-arguments-constant\": 245000, + \"equalsByteString-cpu-arguments-intercept\": 216773, + \"equalsByteString-cpu-arguments-slope\": 62, + \"equalsByteString-memory-arguments\": 1, + \"equalsData-cpu-arguments-intercept\": 1060367, + \"equalsData-cpu-arguments-slope\": 12586, + \"equalsData-memory-arguments\": 1, + \"equalsInteger-cpu-arguments-intercept\": 208512, + \"equalsInteger-cpu-arguments-slope\": 421, + \"equalsInteger-memory-arguments\": 1, + \"equalsString-cpu-arguments-constant\": 187000, + \"equalsString-cpu-arguments-intercept\": 1000, + \"equalsString-cpu-arguments-slope\": 52998, + \"equalsString-memory-arguments\": 1, + \"fstPair-cpu-arguments\": 80436, + \"fstPair-memory-arguments\": 32, + \"headList-cpu-arguments\": 43249, + \"headList-memory-arguments\": 32, + \"iData-cpu-arguments\": 1000, + \"iData-memory-arguments\": 32, + \"ifThenElse-cpu-arguments\": 80556, + \"ifThenElse-memory-arguments\": 1, + \"indexByteString-cpu-arguments\": 57667, + \"indexByteString-memory-arguments\": 4, + \"lengthOfByteString-cpu-arguments\": 1000, + \"lengthOfByteString-memory-arguments\": 10, + \"lessThanByteString-cpu-arguments-intercept\": 197145, + \"lessThanByteString-cpu-arguments-slope\": 156, + \"lessThanByteString-memory-arguments\": 1, + \"lessThanEqualsByteString-cpu-arguments-intercept\": 197145, + \"lessThanEqualsByteString-cpu-arguments-slope\": 156, + \"lessThanEqualsByteString-memory-arguments\": 1, + \"lessThanEqualsInteger-cpu-arguments-intercept\": 204924, + \"lessThanEqualsInteger-cpu-arguments-slope\": 473, + \"lessThanEqualsInteger-memory-arguments\": 1, + \"lessThanInteger-cpu-arguments-intercept\": 208896, + \"lessThanInteger-cpu-arguments-slope\": 511, + \"lessThanInteger-memory-arguments\": 1, + \"listData-cpu-arguments\": 52467, + \"listData-memory-arguments\": 32, + \"mapData-cpu-arguments\": 64832, + \"mapData-memory-arguments\": 32, + \"mkCons-cpu-arguments\": 65493, + \"mkCons-memory-arguments\": 32, + \"mkNilData-cpu-arguments\": 22558, + \"mkNilData-memory-arguments\": 32, + \"mkNilPairData-cpu-arguments\": 16563, + \"mkNilPairData-memory-arguments\": 32, + \"mkPairData-cpu-arguments\": 76511, + \"mkPairData-memory-arguments\": 32, + \"modInteger-cpu-arguments-constant\": 196500, + \"modInteger-cpu-arguments-model-arguments-intercept\": 453240, + \"modInteger-cpu-arguments-model-arguments-slope\": 220, + \"modInteger-memory-arguments-intercept\": 0, + \"modInteger-memory-arguments-minimum\": 1, + \"modInteger-memory-arguments-slope\": 1, + \"multiplyInteger-cpu-arguments-intercept\": 69522, + \"multiplyInteger-cpu-arguments-slope\": 11687, + \"multiplyInteger-memory-arguments-intercept\": 0, + \"multiplyInteger-memory-arguments-slope\": 1, + \"nullList-cpu-arguments\": 60091, + \"nullList-memory-arguments\": 32, + \"quotientInteger-cpu-arguments-constant\": 196500, + \"quotientInteger-cpu-arguments-model-arguments-intercept\": 453240, + \"quotientInteger-cpu-arguments-model-arguments-slope\": 220, + \"quotientInteger-memory-arguments-intercept\": 0, + \"quotientInteger-memory-arguments-minimum\": 1, + \"quotientInteger-memory-arguments-slope\": 1, + \"remainderInteger-cpu-arguments-constant\": 196500, + \"remainderInteger-cpu-arguments-model-arguments-intercept\": 453240, + \"remainderInteger-cpu-arguments-model-arguments-slope\": 220, + \"remainderInteger-memory-arguments-intercept\": 0, + \"remainderInteger-memory-arguments-minimum\": 1, + \"remainderInteger-memory-arguments-slope\": 1, + \"serialiseData-cpu-arguments-intercept\": 1159724, + \"serialiseData-cpu-arguments-slope\": 392670, + \"serialiseData-memory-arguments-intercept\": 0, + \"serialiseData-memory-arguments-slope\": 2, + \"sha2_256-cpu-arguments-intercept\": 806990, + \"sha2_256-cpu-arguments-slope\": 30482, + \"sha2_256-memory-arguments\": 4, + \"sha3_256-cpu-arguments-intercept\": 1927926, + \"sha3_256-cpu-arguments-slope\": 82523, + \"sha3_256-memory-arguments\": 4, + \"sliceByteString-cpu-arguments-intercept\": 265318, + \"sliceByteString-cpu-arguments-slope\": 0, + \"sliceByteString-memory-arguments-intercept\": 4, + \"sliceByteString-memory-arguments-slope\": 0, + \"sndPair-cpu-arguments\": 85931, + \"sndPair-memory-arguments\": 32, + \"subtractInteger-cpu-arguments-intercept\": 205665, + \"subtractInteger-cpu-arguments-slope\": 812, + \"subtractInteger-memory-arguments-intercept\": 1, + \"subtractInteger-memory-arguments-slope\": 1, + \"tailList-cpu-arguments\": 41182, + \"tailList-memory-arguments\": 32, + \"trace-cpu-arguments\": 212342, + \"trace-memory-arguments\": 32, + \"unBData-cpu-arguments\": 31220, + \"unBData-memory-arguments\": 32, + \"unConstrData-cpu-arguments\": 32696, + \"unConstrData-memory-arguments\": 32, + \"unIData-cpu-arguments\": 43357, + \"unIData-memory-arguments\": 32, + \"unListData-cpu-arguments\": 32247, + \"unListData-memory-arguments\": 32, + \"unMapData-cpu-arguments\": 38314, + \"unMapData-memory-arguments\": 32, + \"verifyEcdsaSecp256k1Signature-cpu-arguments\": 35892428, + \"verifyEcdsaSecp256k1Signature-memory-arguments\": 10, + \"verifyEd25519Signature-cpu-arguments-intercept\": 57996947, + \"verifyEd25519Signature-cpu-arguments-slope\": 18975, + \"verifyEd25519Signature-memory-arguments\": 10, + \"verifySchnorrSecp256k1Signature-cpu-arguments-intercept\": 38887044, + \"verifySchnorrSecp256k1Signature-cpu-arguments-slope\": 32947, + \"verifySchnorrSecp256k1Signature-memory-arguments\": 10 + }, + \"PlutusV1\": { + \"addInteger-cpu-arguments-intercept\": 205665, + \"addInteger-cpu-arguments-slope\": 812, + \"addInteger-memory-arguments-intercept\": 1, + \"addInteger-memory-arguments-slope\": 1, + \"appendByteString-cpu-arguments-intercept\": 1000, + \"appendByteString-cpu-arguments-slope\": 571, + \"appendByteString-memory-arguments-intercept\": 0, + \"appendByteString-memory-arguments-slope\": 1, + \"appendString-cpu-arguments-intercept\": 1000, + \"appendString-cpu-arguments-slope\": 24177, + \"appendString-memory-arguments-intercept\": 4, + \"appendString-memory-arguments-slope\": 1, + \"bData-cpu-arguments\": 1000, + \"bData-memory-arguments\": 32, + \"blake2b_256-cpu-arguments-intercept\": 117366, + \"blake2b_256-cpu-arguments-slope\": 10475, + \"blake2b_256-memory-arguments\": 4, + \"cekApplyCost-exBudgetCPU\": 23000, + \"cekApplyCost-exBudgetMemory\": 100, + \"cekBuiltinCost-exBudgetCPU\": 23000, + \"cekBuiltinCost-exBudgetMemory\": 100, + \"cekConstCost-exBudgetCPU\": 23000, + \"cekConstCost-exBudgetMemory\": 100, + \"cekDelayCost-exBudgetCPU\": 23000, + \"cekDelayCost-exBudgetMemory\": 100, + \"cekForceCost-exBudgetCPU\": 23000, + \"cekForceCost-exBudgetMemory\": 100, + \"cekLamCost-exBudgetCPU\": 23000, + \"cekLamCost-exBudgetMemory\": 100, + \"cekStartupCost-exBudgetCPU\": 100, + \"cekStartupCost-exBudgetMemory\": 100, + \"cekVarCost-exBudgetCPU\": 23000, + \"cekVarCost-exBudgetMemory\": 100, + \"chooseData-cpu-arguments\": 19537, + \"chooseData-memory-arguments\": 32, + \"chooseList-cpu-arguments\": 175354, + \"chooseList-memory-arguments\": 32, + \"chooseUnit-cpu-arguments\": 46417, + \"chooseUnit-memory-arguments\": 4, + \"consByteString-cpu-arguments-intercept\": 221973, + \"consByteString-cpu-arguments-slope\": 511, + \"consByteString-memory-arguments-intercept\": 0, + \"consByteString-memory-arguments-slope\": 1, + \"constrData-cpu-arguments\": 89141, + \"constrData-memory-arguments\": 32, + \"decodeUtf8-cpu-arguments-intercept\": 497525, + \"decodeUtf8-cpu-arguments-slope\": 14068, + \"decodeUtf8-memory-arguments-intercept\": 4, + \"decodeUtf8-memory-arguments-slope\": 2, + \"divideInteger-cpu-arguments-constant\": 196500, + \"divideInteger-cpu-arguments-model-arguments-intercept\": 453240, + \"divideInteger-cpu-arguments-model-arguments-slope\": 220, + \"divideInteger-memory-arguments-intercept\": 0, + \"divideInteger-memory-arguments-minimum\": 1, + \"divideInteger-memory-arguments-slope\": 1, + \"encodeUtf8-cpu-arguments-intercept\": 1000, + \"encodeUtf8-cpu-arguments-slope\": 28662, + \"encodeUtf8-memory-arguments-intercept\": 4, + \"encodeUtf8-memory-arguments-slope\": 2, + \"equalsByteString-cpu-arguments-constant\": 245000, + \"equalsByteString-cpu-arguments-intercept\": 216773, + \"equalsByteString-cpu-arguments-slope\": 62, + \"equalsByteString-memory-arguments\": 1, + \"equalsData-cpu-arguments-intercept\": 1060367, + \"equalsData-cpu-arguments-slope\": 12586, + \"equalsData-memory-arguments\": 1, + \"equalsInteger-cpu-arguments-intercept\": 208512, + \"equalsInteger-cpu-arguments-slope\": 421, + \"equalsInteger-memory-arguments\": 1, + \"equalsString-cpu-arguments-constant\": 187000, + \"equalsString-cpu-arguments-intercept\": 1000, + \"equalsString-cpu-arguments-slope\": 52998, + \"equalsString-memory-arguments\": 1, + \"fstPair-cpu-arguments\": 80436, + \"fstPair-memory-arguments\": 32, + \"headList-cpu-arguments\": 43249, + \"headList-memory-arguments\": 32, + \"iData-cpu-arguments\": 1000, + \"iData-memory-arguments\": 32, + \"ifThenElse-cpu-arguments\": 80556, + \"ifThenElse-memory-arguments\": 1, + \"indexByteString-cpu-arguments\": 57667, + \"indexByteString-memory-arguments\": 4, + \"lengthOfByteString-cpu-arguments\": 1000, + \"lengthOfByteString-memory-arguments\": 10, + \"lessThanByteString-cpu-arguments-intercept\": 197145, + \"lessThanByteString-cpu-arguments-slope\": 156, + \"lessThanByteString-memory-arguments\": 1, + \"lessThanEqualsByteString-cpu-arguments-intercept\": 197145, + \"lessThanEqualsByteString-cpu-arguments-slope\": 156, + \"lessThanEqualsByteString-memory-arguments\": 1, + \"lessThanEqualsInteger-cpu-arguments-intercept\": 204924, + \"lessThanEqualsInteger-cpu-arguments-slope\": 473, + \"lessThanEqualsInteger-memory-arguments\": 1, + \"lessThanInteger-cpu-arguments-intercept\": 208896, + \"lessThanInteger-cpu-arguments-slope\": 511, + \"lessThanInteger-memory-arguments\": 1, + \"listData-cpu-arguments\": 52467, + \"listData-memory-arguments\": 32, + \"mapData-cpu-arguments\": 64832, + \"mapData-memory-arguments\": 32, + \"mkCons-cpu-arguments\": 65493, + \"mkCons-memory-arguments\": 32, + \"mkNilData-cpu-arguments\": 22558, + \"mkNilData-memory-arguments\": 32, + \"mkNilPairData-cpu-arguments\": 16563, + \"mkNilPairData-memory-arguments\": 32, + \"mkPairData-cpu-arguments\": 76511, + \"mkPairData-memory-arguments\": 32, + \"modInteger-cpu-arguments-constant\": 196500, + \"modInteger-cpu-arguments-model-arguments-intercept\": 453240, + \"modInteger-cpu-arguments-model-arguments-slope\": 220, + \"modInteger-memory-arguments-intercept\": 0, + \"modInteger-memory-arguments-minimum\": 1, + \"modInteger-memory-arguments-slope\": 1, + \"multiplyInteger-cpu-arguments-intercept\": 69522, + \"multiplyInteger-cpu-arguments-slope\": 11687, + \"multiplyInteger-memory-arguments-intercept\": 0, + \"multiplyInteger-memory-arguments-slope\": 1, + \"nullList-cpu-arguments\": 60091, + \"nullList-memory-arguments\": 32, + \"quotientInteger-cpu-arguments-constant\": 196500, + \"quotientInteger-cpu-arguments-model-arguments-intercept\": 453240, + \"quotientInteger-cpu-arguments-model-arguments-slope\": 220, + \"quotientInteger-memory-arguments-intercept\": 0, + \"quotientInteger-memory-arguments-minimum\": 1, + \"quotientInteger-memory-arguments-slope\": 1, + \"remainderInteger-cpu-arguments-constant\": 196500, + \"remainderInteger-cpu-arguments-model-arguments-intercept\": 453240, + \"remainderInteger-cpu-arguments-model-arguments-slope\": 220, + \"remainderInteger-memory-arguments-intercept\": 0, + \"remainderInteger-memory-arguments-minimum\": 1, + \"remainderInteger-memory-arguments-slope\": 1, + \"sha2_256-cpu-arguments-intercept\": 806990, + \"sha2_256-cpu-arguments-slope\": 30482, + \"sha2_256-memory-arguments\": 4, + \"sha3_256-cpu-arguments-intercept\": 1927926, + \"sha3_256-cpu-arguments-slope\": 82523, + \"sha3_256-memory-arguments\": 4, + \"sliceByteString-cpu-arguments-intercept\": 265318, + \"sliceByteString-cpu-arguments-slope\": 0, + \"sliceByteString-memory-arguments-intercept\": 4, + \"sliceByteString-memory-arguments-slope\": 0, + \"sndPair-cpu-arguments\": 85931, + \"sndPair-memory-arguments\": 32, + \"subtractInteger-cpu-arguments-intercept\": 205665, + \"subtractInteger-cpu-arguments-slope\": 812, + \"subtractInteger-memory-arguments-intercept\": 1, + \"subtractInteger-memory-arguments-slope\": 1, + \"tailList-cpu-arguments\": 41182, + \"tailList-memory-arguments\": 32, + \"trace-cpu-arguments\": 212342, + \"trace-memory-arguments\": 32, + \"unBData-cpu-arguments\": 31220, + \"unBData-memory-arguments\": 32, + \"unConstrData-cpu-arguments\": 32696, + \"unConstrData-memory-arguments\": 32, + \"unIData-cpu-arguments\": 43357, + \"unIData-memory-arguments\": 32, + \"unListData-cpu-arguments\": 32247, + \"unListData-memory-arguments\": 32, + \"unMapData-cpu-arguments\": 38314, + \"unMapData-memory-arguments\": 32, + \"verifyEd25519Signature-cpu-arguments-intercept\": 57996947, + \"verifyEd25519Signature-cpu-arguments-slope\": 18975, + \"verifyEd25519Signature-memory-arguments\": 10 + }, + \"PlutusV3\": { + \"0\": 205665, + \"1\": 812, + \"10\": 4, + \"100\": 32, + \"101\": 65493, + \"102\": 32, + \"103\": 22558, + \"104\": 32, + \"105\": 16563, + \"106\": 32, + \"107\": 76511, + \"108\": 32, + \"109\": 196500, + \"11\": 1, + \"110\": 453240, + \"111\": 220, + \"112\": 0, + \"113\": 1, + \"114\": 1, + \"115\": 69522, + \"116\": 11687, + \"117\": 0, + \"118\": 1, + \"119\": 60091, + \"12\": 1000, + \"120\": 32, + \"121\": 196500, + \"122\": 453240, + \"123\": 220, + \"124\": 0, + \"125\": 1, + \"126\": 1, + \"127\": 196500, + \"128\": 453240, + \"129\": 220, + \"13\": 32, + \"130\": 0, + \"131\": 1, + \"132\": 1, + \"133\": 1159724, + \"134\": 392670, + \"135\": 0, + \"136\": 2, + \"137\": 806990, + \"138\": 30482, + \"139\": 4, + \"14\": 117366, + \"140\": 1927926, + \"141\": 82523, + \"142\": 4, + \"143\": 265318, + \"144\": 0, + \"145\": 4, + \"146\": 0, + \"147\": 85931, + \"148\": 32, + \"149\": 205665, + \"15\": 10475, + \"150\": 812, + \"151\": 1, + \"152\": 1, + \"153\": 41182, + \"154\": 32, + \"155\": 212342, + \"156\": 32, + \"157\": 31220, + \"158\": 32, + \"159\": 32696, + \"16\": 4, + \"160\": 32, + \"161\": 43357, + \"162\": 32, + \"163\": 32247, + \"164\": 32, + \"165\": 38314, + \"166\": 32, + \"167\": 35190005, + \"168\": 10, + \"169\": 57996947, + \"17\": 23000, + \"170\": 18975, + \"171\": 10, + \"172\": 39121781, + \"173\": 32260, + \"174\": 10, + \"175\": 23000, + \"176\": 100, + \"177\": 23000, + \"178\": 100, + \"179\": 832808, + \"18\": 100, + \"180\": 18, + \"181\": 3209094, + \"182\": 6, + \"183\": 331451, + \"184\": 1, + \"185\": 65990684, + \"186\": 23097, + \"187\": 18, + \"188\": 114242, + \"189\": 18, + \"19\": 23000, + \"190\": 94393407, + \"191\": 87060, + \"192\": 18, + \"193\": 16420089, + \"194\": 18, + \"195\": 2145798, + \"196\": 36, + \"197\": 3795345, + \"198\": 12, + \"199\": 889023, + \"2\": 1, + \"20\": 100, + \"200\": 1, + \"201\": 204237282, + \"202\": 23271, + \"203\": 36, + \"204\": 129165, + \"205\": 36, + \"206\": 189977790, + \"207\": 85902, + \"208\": 36, + \"209\": 33012864, + \"21\": 23000, + \"210\": 36, + \"211\": 388443360, + \"212\": 1, + \"213\": 401885761, + \"214\": 72, + \"215\": 2331379, + \"216\": 72, + \"217\": 1927926, + \"218\": 82523, + \"219\": 4, + \"22\": 100, + \"220\": 117366, + \"221\": 10475, + \"222\": 4, + \"23\": 23000, + \"24\": 100, + \"25\": 23000, + \"26\": 100, + \"27\": 23000, + \"28\": 100, + \"29\": 100, + \"3\": 1, + \"30\": 100, + \"31\": 23000, + \"32\": 100, + \"33\": 19537, + \"34\": 32, + \"35\": 175354, + \"36\": 32, + \"37\": 46417, + \"38\": 4, + \"39\": 221973, + \"4\": 1000, + \"40\": 511, + \"41\": 0, + \"42\": 1, + \"43\": 89141, + \"44\": 32, + \"45\": 497525, + \"46\": 14068, + \"47\": 4, + \"48\": 2, + \"49\": 196500, + \"5\": 571, + \"50\": 453240, + \"51\": 220, + \"52\": 0, + \"53\": 1, + \"54\": 1, + \"55\": 1000, + \"56\": 28662, + \"57\": 4, + \"58\": 2, + \"59\": 245000, + \"6\": 0, + \"60\": 216773, + \"61\": 62, + \"62\": 1, + \"63\": 1060367, + \"64\": 12586, + \"65\": 1, + \"66\": 208512, + \"67\": 421, + \"68\": 1, + \"69\": 187000, + \"7\": 1, + \"70\": 1000, + \"71\": 52998, + \"72\": 1, + \"73\": 80436, + \"74\": 32, + \"75\": 43249, + \"76\": 32, + \"77\": 1000, + \"78\": 32, + \"79\": 80556, + \"8\": 1000, + \"80\": 1, + \"81\": 57667, + \"82\": 4, + \"83\": 1000, + \"84\": 10, + \"85\": 197145, + \"86\": 156, + \"87\": 1, + \"88\": 197145, + \"89\": 156, + \"9\": 24177, + \"90\": 1, + \"91\": 204924, + \"92\": 473, + \"93\": 1, + \"94\": 208896, + \"95\": 511, + \"96\": 1, + \"97\": 52467, + \"98\": 32, + \"99\": 64832 + } + }, + \"price_mem\": 0.0577, + \"price_step\": 0.0000721, + \"max_tx_ex_mem\": \"10000000\", + \"max_tx_ex_steps\": \"10000000000\", + \"max_block_ex_mem\": \"50000000\", + \"max_block_ex_steps\": \"40000000000\", + \"max_val_size\": \"5000\", + \"collateral_percent\": 150, + \"max_collateral_inputs\": 3, + \"coins_per_utxo_size\": \"34482\", + \"coins_per_utxo_word\": \"34482\" + }"; + // we can't unwrap(), print or even check is_ok() for Result<_, JsError> + // outside of wasm environments so we just test make_tx_builder_cfg_impl directly instead. + let params: serde_json::Value = serde_json::from_str(response_json).unwrap(); + let config_builder = make_tx_builder_cfg_impl(params).unwrap(); + let config = config_builder.build().unwrap(); + assert_eq!(config.fee_algo.coefficient, 44); + assert_eq!(config.fee_algo.constant, 155381); + assert_eq!(config.pool_deposit, 500000000); + assert_eq!(config.key_deposit, 2000000); + assert_eq!(config.max_value_size, 5000); + assert_eq!(config.max_tx_size, 16384); + assert_eq!(config.coins_per_utxo_byte, 34482); + assert_eq!(config.ex_unit_prices.mem_price.numerator, 577); + assert_eq!(config.ex_unit_prices.mem_price.denominator, 10000); + assert_eq!(config.ex_unit_prices.step_price.numerator, 721); + assert_eq!(config.ex_unit_prices.step_price.denominator, 10000000); + assert_eq!(config.max_collateral_inputs, 3); + let plutus_v1_cost_models = [ + 205665i64, 812, 1, 1, 1000, 571, 0, 1, 1000, 24177, 4, 1, 1000, 32, 117366, 10475, 4, + 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 100, 100, + 23000, 100, 19537, 32, 175354, 32, 46417, 4, 221973, 511, 0, 1, 89141, 32, 497525, + 14068, 4, 2, 196500, 453240, 220, 0, 1, 1, 1000, 28662, 4, 2, 245000, 216773, 62, 1, + 1060367, 12586, 1, 208512, 421, 1, 187000, 1000, 52998, 1, 80436, 32, 43249, 32, 1000, + 32, 80556, 1, 57667, 4, 1000, 10, 197145, 156, 1, 197145, 156, 1, 204924, 473, 1, + 208896, 511, 1, 52467, 32, 64832, 32, 65493, 32, 22558, 32, 16563, 32, 76511, 32, + 196500, 453240, 220, 0, 1, 1, 69522, 11687, 0, 1, 60091, 32, 196500, 453240, 220, 0, 1, + 1, 196500, 453240, 220, 0, 1, 1, 806990, 30482, 4, 1927926, 82523, 4, 265318, 0, 4, 0, + 85931, 32, 205665, 812, 1, 1, 41182, 32, 212342, 32, 31220, 32, 32696, 32, 43357, 32, + 32247, 32, 38314, 32, 57996947, 18975, 10, + ]; + let plutus_v2_cost_models = [ + 205665i64, 812, 1, 1, 1000, 571, 0, 1, 1000, 24177, 4, 1, 1000, 32, 117366, 10475, 4, + 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 100, 100, + 23000, 100, 19537, 32, 175354, 32, 46417, 4, 221973, 511, 0, 1, 89141, 32, 497525, + 14068, 4, 2, 196500, 453240, 220, 0, 1, 1, 1000, 28662, 4, 2, 245000, 216773, 62, 1, + 1060367, 12586, 1, 208512, 421, 1, 187000, 1000, 52998, 1, 80436, 32, 43249, 32, 1000, + 32, 80556, 1, 57667, 4, 1000, 10, 197145, 156, 1, 197145, 156, 1, 204924, 473, 1, + 208896, 511, 1, 52467, 32, 64832, 32, 65493, 32, 22558, 32, 16563, 32, 76511, 32, + 196500, 453240, 220, 0, 1, 1, 69522, 11687, 0, 1, 60091, 32, 196500, 453240, 220, 0, 1, + 1, 196500, 453240, 220, 0, 1, 1, 1159724, 392670, 0, 2, 806990, 30482, 4, 1927926, + 82523, 4, 265318, 0, 4, 0, 85931, 32, 205665, 812, 1, 1, 41182, 32, 212342, 32, 31220, + 32, 32696, 32, 43357, 32, 32247, 32, 38314, 32, 35892428, 10, 57996947, 18975, 10, + 38887044, 32947, 10, + ]; + let plutus_v3_cost_models = [ + 205665i64, 812, 1, 1, 1000, 571, 0, 1, 1000, 24177, 4, 1, 1000, 32, 117366, 10475, 4, + 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 100, 100, + 23000, 100, 19537, 32, 175354, 32, 46417, 4, 221973, 511, 0, 1, 89141, 32, 497525, + 14068, 4, 2, 196500, 453240, 220, 0, 1, 1, 1000, 28662, 4, 2, 245000, 216773, 62, 1, + 1060367, 12586, 1, 208512, 421, 1, 187000, 1000, 52998, 1, 80436, 32, 43249, 32, 1000, + 32, 80556, 1, 57667, 4, 1000, 10, 197145, 156, 1, 197145, 156, 1, 204924, 473, 1, + 208896, 511, 1, 52467, 32, 64832, 32, 65493, 32, 22558, 32, 16563, 32, 76511, 32, + 196500, 453240, 220, 0, 1, 1, 69522, 11687, 0, 1, 60091, 32, 196500, 453240, 220, 0, 1, + 1, 196500, 453240, 220, 0, 1, 1, 1159724, 392670, 0, 2, 806990, 30482, 4, 1927926, + 82523, 4, 265318, 0, 4, 0, 85931, 32, 205665, 812, 1, 1, 41182, 32, 212342, 32, 31220, + 32, 32696, 32, 43357, 32, 32247, 32, 38314, 32, 35190005, 10, 57996947, 18975, 10, + 39121781, 32260, 10, 23000, 100, 23000, 100, 832808, 18, 3209094, 6, 331451, 1, + 65990684, 23097, 18, 114242, 18, 94393407, 87060, 18, 16420089, 18, 2145798, 36, + 3795345, 12, 889023, 1, 204237282, 23271, 36, 129165, 36, 189977790, 85902, 36, + 33012864, 36, 388443360, 1, 401885761, 72, 2331379, 72, 1927926, 82523, 4, 117366, + 10475, 4, + ]; + assert_eq!( + *config + .cost_models + .inner + .get(&Language::PlutusV1.into()) + .unwrap(), + plutus_v1_cost_models + ); + assert_eq!( + *config + .cost_models + .inner + .get(&Language::PlutusV2.into()) + .unwrap(), + plutus_v2_cost_models + ); + assert_eq!( + *config + .cost_models + .inner + .get(&Language::PlutusV3.into()) + .unwrap(), + plutus_v3_cost_models[..CostModels::PLUTUS_V3_COUNT] + ); + } +} diff --git a/chain/rust/src/builders/tx_builder.rs b/chain/rust/src/builders/tx_builder.rs index b6223a32..be26d68a 100644 --- a/chain/rust/src/builders/tx_builder.rs +++ b/chain/rust/src/builders/tx_builder.rs @@ -168,6 +168,7 @@ pub enum TxBuilderConfigField { ExUnitPrices, CollateralPercentage, MaxCollateralInputs, + CostModels, } #[derive(Debug, thiserror::Error)] @@ -249,17 +250,17 @@ pub enum CoinSelectionStrategyCIP2 { #[derive(Clone, Debug)] pub struct TransactionBuilderConfig { - fee_algo: LinearFee, - pool_deposit: u64, // protocol parameter - key_deposit: u64, // protocol parameter - max_value_size: u32, // protocol parameter - max_tx_size: u32, // protocol parameter - coins_per_utxo_byte: Coin, // protocol parameter - ex_unit_prices: ExUnitPrices, // protocol parameter - cost_models: CostModels, // protocol parameter - _collateral_percentage: u32, // protocol parameter - max_collateral_inputs: u32, // protocol parameter - prefer_pure_change: bool, + pub fee_algo: LinearFee, + pub pool_deposit: u64, // protocol parameter + pub key_deposit: u64, // protocol parameter + pub max_value_size: u32, // protocol parameter + pub max_tx_size: u32, // protocol parameter + pub coins_per_utxo_byte: Coin, // protocol parameter + pub ex_unit_prices: ExUnitPrices, // protocol parameter + pub cost_models: CostModels, // protocol parameter + _collateral_percentage: u32, // protocol parameter + pub max_collateral_inputs: u32, // protocol parameter + pub prefer_pure_change: bool, } #[derive(Clone, Debug, Default)] diff --git a/chain/rust/src/plutus/utils.rs b/chain/rust/src/plutus/utils.rs index 300d4e63..f5fceb63 100644 --- a/chain/rust/src/plutus/utils.rs +++ b/chain/rust/src/plutus/utils.rs @@ -326,6 +326,61 @@ impl Deserialize for ConstrPlutusData { } impl CostModels { + pub const PLUTUS_V1_COUNT: usize = 166; + pub const PLUTUS_V2_COUNT: usize = 175; + pub const PLUTUS_V3_COUNT: usize = 179; + + pub fn set_plutus_v1(&mut self, costs: Vec) -> Result<(), DeserializeError> { + // on-chain there is no restriction on length but this will help users avoid problems + if costs.len() != Self::PLUTUS_V1_COUNT { + return Err(DeserializeFailure::RangeCheck { + found: costs.len() as isize, + min: Some(Self::PLUTUS_V1_COUNT as isize), + max: Some(Self::PLUTUS_V1_COUNT as isize), + } + .into()); + } + self.inner.insert(Language::PlutusV1.into(), costs); + Ok(()) + } + + pub fn set_plutus_v2(&mut self, costs: Vec) -> Result<(), DeserializeError> { + // on-chain there is no restriction on length but this will help users avoid problems + if costs.len() != Self::PLUTUS_V2_COUNT { + return Err(DeserializeFailure::RangeCheck { + found: costs.len() as isize, + min: Some(Self::PLUTUS_V2_COUNT as isize), + max: Some(Self::PLUTUS_V2_COUNT as isize), + } + .into()); + } + self.inner.insert(Language::PlutusV2.into(), costs); + Ok(()) + } + + pub fn set_plutus_v3(&mut self, costs: Vec) -> Result<(), DeserializeError> { + // on-chain there is no restriction on length but this will help users avoid problems + if costs.len() != Self::PLUTUS_V3_COUNT { + return Err(DeserializeFailure::RangeCheck { + found: costs.len() as isize, + min: Some(Self::PLUTUS_V3_COUNT as isize), + max: Some(Self::PLUTUS_V3_COUNT as isize), + } + .into()); + } + self.inner.insert(Language::PlutusV3.into(), costs); + Ok(()) + } + + /// Total number of operations for the cost model of the given language + pub fn op_count(language: Language) -> usize { + match language { + Language::PlutusV1 => Self::PLUTUS_V1_COUNT, + Language::PlutusV2 => Self::PLUTUS_V2_COUNT, + Language::PlutusV3 => Self::PLUTUS_V3_COUNT, + } + } + pub(crate) fn language_views_encoding(&self) -> Result, cbor_event::Error> { // ; language views CDDL: // ; { * language => script_integrity_data } diff --git a/chain/rust/src/utils.rs b/chain/rust/src/utils.rs index 41914ecd..119f4c32 100644 --- a/chain/rust/src/utils.rs +++ b/chain/rust/src/utils.rs @@ -12,7 +12,7 @@ use std::iter::IntoIterator; use crate::{ crypto::hash::{hash_script, ScriptHashNamespace}, plutus::{Language, PlutusScript, PlutusV1Script, PlutusV2Script}, - NativeScript, Script, + NativeScript, Script, SubCoin, }; impl Script { @@ -621,6 +621,28 @@ impl Deserialize for NetworkId { } } +impl SubCoin { + /// Converts base 10 floats to SubCoin. + /// This is the format used by blockfrost for ex units + /// Warning: If the passed in float was not meant to be base 10 + /// this might result in a slightly inaccurate fraction. + pub fn from_base10_f32(f: f32) -> Self { + let mut denom = 1u64; + while (f * (denom as f32)).fract().abs() > f32::EPSILON { + denom *= 10; + } + // we check against episilon to be sure we get all info + // but this could result in over-extending with respect to the original float + // so run it back after the fact. + let mut numerator = (f * (denom as f32)).ceil() as u64; + while numerator % 10 == 0 && denom % 10 == 0 { + numerator /= 10; + denom /= 10; + } + Self::new(numerator, denom) + } +} + // Represents the cddl: #6.258([+ T]) / [* T] // it DOES NOT and CAN NOT have any encoding detials per element! // so you can NOT use it on any primitives so must be serializable directly diff --git a/chain/wasm/src/plutus/utils.rs b/chain/wasm/src/plutus/utils.rs index 2b458235..86a29635 100644 --- a/chain/wasm/src/plutus/utils.rs +++ b/chain/wasm/src/plutus/utils.rs @@ -1,5 +1,5 @@ use crate::{ - plutus::{PlutusData, Redeemers}, + plutus::{CostModels, PlutusData, Redeemers}, LegacyRedeemerList, PlutusDataList, }; use cml_chain::plutus::Language; @@ -37,6 +37,21 @@ impl ConstrPlutusData { } } +#[wasm_bindgen] +impl CostModels { + pub fn set_plutus_v1(&mut self, costs: Vec) -> Result<(), JsError> { + self.0.set_plutus_v1(costs).map_err(Into::into) + } + + pub fn set_plutus_v2(&mut self, costs: Vec) -> Result<(), JsError> { + self.0.set_plutus_v2(costs).map_err(Into::into) + } + + pub fn set_plutus_v3(&mut self, costs: Vec) -> Result<(), JsError> { + self.0.set_plutus_v3(costs).map_err(Into::into) + } +} + #[derive(Clone, Debug)] #[wasm_bindgen] pub struct PlutusMap(cml_chain::plutus::PlutusMap); diff --git a/chain/wasm/src/utils.rs b/chain/wasm/src/utils.rs index ce9c6751..512c90cd 100644 --- a/chain/wasm/src/utils.rs +++ b/chain/wasm/src/utils.rs @@ -1,4 +1,4 @@ -use super::{Int, Script, ScriptHash}; +use super::{Int, Script, ScriptHash, SubCoin}; use cml_chain::plutus::Language; use wasm_bindgen::prelude::{wasm_bindgen, JsError, JsValue}; @@ -86,6 +86,17 @@ impl NetworkId { } } +#[wasm_bindgen] +impl SubCoin { + /// Converts base 10 floats to SubCoin. + /// This is the format used by blockfrost for ex units + /// Warning: If the passed in float was not meant to be base 10 + /// this might result in a slightly inaccurate fraction. + pub fn from_base10_f32(f: f32) -> Self { + cml_chain::SubCoin::from_base10_f32(f).into() + } +} + // we provide direct From/Into conversions between NonemptySet and TList // to allow the auto-generated code to work directly without changes macro_rules! impl_wasm_conversions_into { diff --git a/cml/wasm/Cargo.toml b/cml/wasm/Cargo.toml index 42ae2dc2..12a1f49f 100644 --- a/cml/wasm/Cargo.toml +++ b/cml/wasm/Cargo.toml @@ -13,6 +13,7 @@ readme = "../../README.md" crate-type = ["cdylib", "rlib"] [dependencies] +cml-blockfrost-wasm = { path = "../../blockfrost/wasm", version = "0.1.0" } cml-chain-wasm = { path = "../../chain/wasm", version = "5.3.1" } cml-cip25-wasm = { path = "../../cip25/wasm", version = "5.3.1" } cml-cip36-wasm = { path = "../../cip36/wasm", version = "5.3.1" } diff --git a/cml/wasm/src/lib.rs b/cml/wasm/src/lib.rs index 52971eef..20ca3fe3 100644 --- a/cml/wasm/src/lib.rs +++ b/cml/wasm/src/lib.rs @@ -4,6 +4,7 @@ // multiple of them including a utils module so we just import an arbitrary type. // We don't need to worry about cml_core_wasm and cml_crypto_wasm since they // will be exported by the other crates here. +pub use cml_blockfrost_wasm::blockfrost_make_tx_builder_cfg; pub use cml_chain_wasm::AssetNameList; pub use cml_cip25_wasm::CIP25Metadata; pub use cml_cip36_wasm::CIP36DeregistrationCbor;