Skip to content

Commit

Permalink
feat: (wip) add support of Maestro to compute for execution units
Browse files Browse the repository at this point in the history
Related to spacebudz#109.
  • Loading branch information
sourabhxyz committed Aug 1, 2024
1 parent 3350dbd commit 139b55e
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/core/libs/cardano_multiplatform_lib/src/tx_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ pub struct TransactionBuilderConfig {
max_collateral_inputs: u32, // protocol parameter
slot_config: (BigNum, BigNum, u32), // (zero_time, zero_slot, slot_length)
blockfrost: Blockfrost,
maestro: Maestro,
}

#[wasm_bindgen]
Expand All @@ -329,6 +330,7 @@ pub struct TransactionBuilderConfigBuilder {
max_collateral_inputs: Option<u32>, // protocol parameter
slot_config: Option<(BigNum, BigNum, u32)>, // (zero_time, zero_slot, slot_length)
blockfrost: Option<Blockfrost>,
maestro: Option<Maestro>,
}

#[wasm_bindgen]
Expand All @@ -348,6 +350,7 @@ impl TransactionBuilderConfigBuilder {
max_collateral_inputs: None,
slot_config: None,
blockfrost: None,
maestro: None,
}
}

Expand Down Expand Up @@ -429,6 +432,12 @@ impl TransactionBuilderConfigBuilder {
cfg
}

pub fn maestro(&self, maestro: &Maestro) -> Self {
let mut cfg = self.clone();
cfg.maestro = Some(maestro.clone());
cfg
}

pub fn build(&self) -> Result<TransactionBuilderConfig, JsError> {
let cfg = self.clone();
Ok(TransactionBuilderConfig {
Expand Down Expand Up @@ -479,6 +488,11 @@ impl TransactionBuilderConfigBuilder {
} else {
Blockfrost::new("".to_string(), "".to_string())
},
maestro: if cfg.maestro.is_some() {
cfg.maestro.unwrap()
} else {
Maestro::new("".to_string(), "".to_string())
},
})
}
}
Expand Down
114 changes: 114 additions & 0 deletions src/core/libs/cardano_multiplatform_lib/src/tx_builder_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ pub struct Blockfrost {
project_id: String,
}

#[wasm_bindgen]
#[derive(
Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
)]
pub struct Maestro {
url: String,
api_key: String,
}

#[wasm_bindgen]
impl Blockfrost {
pub fn new(url: String, project_id: String) -> Self {
Expand All @@ -75,6 +84,22 @@ impl Blockfrost {
}
}

#[wasm_bindgen]
impl Maestro {
pub fn new(url: String, api_key: String) -> Self {
Self {
url: url.clone(),
api_key: api_key.clone(),
}
}
pub fn url(&self) -> String {
self.url.clone()
}
pub fn api_key(&self) -> String {
self.api_key.clone()
}
}

#[wasm_bindgen]
pub fn apply_params_to_plutus_script(
params: &PlutusList,
Expand Down Expand Up @@ -143,6 +168,14 @@ pub async fn get_ex_units_blockfrost(
Ok(Redeemers::new())
}

#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
pub async fn get_ex_units_maestro(
tx: Transaction,
ms: &Maestro,
) -> Result<Redeemers, JsError> {
Ok(Redeemers::new())
}

#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub async fn get_ex_units_blockfrost(
tx: Transaction,
Expand Down Expand Up @@ -224,6 +257,87 @@ pub async fn get_ex_units_blockfrost(
}
}

#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub async fn get_ex_units_maestro(
tx: Transaction,
ms: &Maestro,
) -> Result<Redeemers, JsError> {
if ms.url.is_empty() || ms.api_key.is_empty() {
return Err(JsError::from_str(
"Maestro not set. Can't calculate ex units",
));
}

let mut opts = RequestInit::new();
opts.method("POST");
let tx_hex = hex::encode(tx.to_bytes());
opts.body(Some(&JsValue::from(tx_hex)));

let url = &ms.url;

let request = Request::new_with_str_and_init(&url, &opts)?;
request.headers().set("Content-Type", "application/cbor")?;
request.headers().set("api_key", &ms.api_key)?;

let window = js_sys::global().unchecked_into::<globalThis>();
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;

// `resp_value` is a `Response` object.
assert!(resp_value.is_instance_of::<Response>());
let resp: Response = resp_value.dyn_into().unwrap();

// Convert this other `Promise` into a rust `Future`.
let json = JsFuture::from(resp.json()?).await?;

// Use serde to parse the JSON into a struct.
let redeemer_result: RedeemerResult = json.into_serde().unwrap();

match redeemer_result.result {
Some(res) => {
if let Some(e) = &res.EvaluationFailure {
return Err(JsError::from_str(
&serde_json::to_string_pretty(&e).unwrap(),
));
}
let mut redeemers: BTreeMap<RedeemerWitnessKey, Redeemer> = BTreeMap::new();
for (pointer, eu) in &res.EvaluationResult.unwrap() {
let r: Vec<&str> = pointer.split(":").collect();
let tag = match r[0] {
"spend" => RedeemerTag::new_spend(),
"mint" => RedeemerTag::new_mint(),
"certificate" => RedeemerTag::new_cert(),
"withdrawal" => RedeemerTag::new_reward(),
_ => return Err(JsValue::NULL),
};
let index = &to_bignum(r[1].parse::<u64>().unwrap());
let ex_units = ExUnits::new(&to_bignum(eu.memory), &to_bignum(eu.steps));

for tx_redeemer in &tx.witness_set.redeemers.clone().unwrap().0 {
if tx_redeemer.tag() == tag && tx_redeemer.index() == *index {
let updated_redeemer = Redeemer::new(
&tx_redeemer.tag(),
&tx_redeemer.index(),
&tx_redeemer.data(),
&ex_units,
);
redeemers.insert(
RedeemerWitnessKey::new(
&updated_redeemer.tag(),
&updated_redeemer.index(),
),
updated_redeemer.clone(),
);
}
}
}

Ok(Redeemers(redeemers.values().cloned().collect()))
}

None => Err(JsValue::NULL),
}
}

#[wasm_bindgen]
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum ScriptWitnessKind {
Expand Down

0 comments on commit 139b55e

Please sign in to comment.