From 4299c233be185eeb79b82e335a81f84f3602e1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C5=A9=20Ho=C3=A0ng?= <127402781+hadelive@users.noreply.github.com> Date: Wed, 12 Jun 2024 02:42:04 +0700 Subject: [PATCH] feat: add native-script verify function (#332) * feat: add native-script verify function --- chain/rust/src/builders/tx_builder.rs | 5 +- chain/rust/src/builders/witness_builder.rs | 6 +-- chain/rust/src/utils.rs | 55 +++++++++++++++++++++- chain/wasm/src/transaction/mod.rs | 1 - chain/wasm/src/transaction/utils.rs | 10 ++++ multi-era/rust/src/alonzo/utils.rs | 6 +-- multi-era/rust/src/babbage/utils.rs | 8 ++-- 7 files changed, 75 insertions(+), 16 deletions(-) diff --git a/chain/rust/src/builders/tx_builder.rs b/chain/rust/src/builders/tx_builder.rs index 7a6dd4bd..a5eeb9f4 100644 --- a/chain/rust/src/builders/tx_builder.rs +++ b/chain/rust/src/builders/tx_builder.rs @@ -720,13 +720,12 @@ impl TransactionBuilder { match &script_witness.script { PlutusScriptWitness::Ref(ref_script) => { - if self + if !self .witness_builders .witness_set_builder .required_wits .script_refs - .get(ref_script) - .is_none() + .contains(ref_script) { Err(TxBuilderError::RefScriptNotFound( *ref_script, diff --git a/chain/rust/src/builders/witness_builder.rs b/chain/rust/src/builders/witness_builder.rs index 3baebe67..299f9955 100644 --- a/chain/rust/src/builders/witness_builder.rs +++ b/chain/rust/src/builders/witness_builder.rs @@ -275,7 +275,7 @@ impl TransactionWitnessSetBuilder { pub fn get_native_script(&self) -> Vec { self.scripts .iter() - .filter(|entry| self.required_wits.script_refs.get(entry.0).is_none()) + .filter(|entry| !self.required_wits.script_refs.contains(entry.0)) .fold( Vec::::new(), |mut acc, script| match &script.1 { @@ -291,7 +291,7 @@ impl TransactionWitnessSetBuilder { pub fn get_plutus_v1_script(&self) -> Vec { self.scripts .iter() - .filter(|entry| self.required_wits.script_refs.get(entry.0).is_none()) + .filter(|entry| !self.required_wits.script_refs.contains(entry.0)) .fold( Vec::::new(), |mut acc, script| match &script.1 { @@ -307,7 +307,7 @@ impl TransactionWitnessSetBuilder { pub fn get_plutus_v2_script(&self) -> Vec { self.scripts .iter() - .filter(|entry| self.required_wits.script_refs.get(entry.0).is_none()) + .filter(|entry| !self.required_wits.script_refs.contains(entry.0)) .fold( Vec::::new(), |mut acc, script| match &script.1 { diff --git a/chain/rust/src/utils.rs b/chain/rust/src/utils.rs index ab3b184c..41914ecd 100644 --- a/chain/rust/src/utils.rs +++ b/chain/rust/src/utils.rs @@ -2,9 +2,9 @@ use cbor_event::{de::Deserializer, se::Serializer, Sz}; use cml_core::{ error::{DeserializeError, DeserializeFailure}, serialization::{fit_sz, sz_max, Deserialize, LenEncoding, Serialize}, - Int, + Int, Slot, }; -use cml_crypto::{RawBytesEncoding, ScriptHash}; +use cml_crypto::{Ed25519KeyHash, RawBytesEncoding, ScriptHash}; use derivative::Derivative; use std::io::{BufRead, Seek, Write}; use std::iter::IntoIterator; @@ -41,6 +41,57 @@ impl NativeScript { pub fn hash(&self) -> ScriptHash { hash_script(ScriptHashNamespace::NativeScript, &self.to_cbor_bytes()) } + + pub fn verify( + &self, + lower_bound: Option, + upper_bound: Option, + key_hashes: &Vec, + ) -> bool { + fn verify_helper( + script: &NativeScript, + lower_bound: Option, + upper_bound: Option, + key_hashes: &Vec, + ) -> bool { + match &script { + NativeScript::ScriptPubkey(pub_key) => { + key_hashes.contains(&pub_key.ed25519_key_hash) + } + NativeScript::ScriptAll(script_all) => { + script_all.native_scripts.iter().all(|sub_script| { + verify_helper(sub_script, lower_bound, upper_bound, key_hashes) + }) + } + NativeScript::ScriptAny(script_any) => { + script_any.native_scripts.iter().any(|sub_script| { + verify_helper(sub_script, lower_bound, upper_bound, key_hashes) + }) + } + NativeScript::ScriptNOfK(script_atleast) => { + script_atleast + .native_scripts + .iter() + .map(|sub_script| { + verify_helper(sub_script, lower_bound, upper_bound, key_hashes) + }) + .filter(|r| *r) + .count() + >= script_atleast.n as usize + } + NativeScript::ScriptInvalidBefore(timelock_start) => match lower_bound { + Some(tx_slot) => tx_slot >= timelock_start.before, + _ => false, + }, + NativeScript::ScriptInvalidHereafter(timelock_expiry) => match upper_bound { + Some(tx_slot) => tx_slot < timelock_expiry.after, + _ => false, + }, + } + } + + verify_helper(self, lower_bound, upper_bound, key_hashes) + } } impl From for Script { diff --git a/chain/wasm/src/transaction/mod.rs b/chain/wasm/src/transaction/mod.rs index e4fb2a94..f8aca0f6 100644 --- a/chain/wasm/src/transaction/mod.rs +++ b/chain/wasm/src/transaction/mod.rs @@ -18,7 +18,6 @@ use cml_crypto_wasm::{ AuxiliaryDataHash, DatumHash, Ed25519KeyHash, ScriptDataHash, TransactionHash, }; use wasm_bindgen::prelude::{wasm_bindgen, JsError, JsValue}; - pub mod utils; #[derive(Clone, Debug)] diff --git a/chain/wasm/src/transaction/utils.rs b/chain/wasm/src/transaction/utils.rs index 67932bf5..5d2ddffc 100644 --- a/chain/wasm/src/transaction/utils.rs +++ b/chain/wasm/src/transaction/utils.rs @@ -4,6 +4,7 @@ use crate::{ utils::LanguageList, Ed25519KeyHashList, NativeScript, Value, }; +use cml_core::Slot; use cml_crypto_wasm::{DatumHash, ScriptHash}; use wasm_bindgen::prelude::wasm_bindgen; @@ -68,6 +69,15 @@ impl NativeScript { pub fn hash(&self) -> ScriptHash { self.0.hash().into() } + + pub fn verify( + &self, + lower_bound: Option, + upper_bound: Option, + key_hashes: &Ed25519KeyHashList, + ) -> bool { + self.0.verify(lower_bound, upper_bound, key_hashes.as_ref()) + } } #[wasm_bindgen] diff --git a/multi-era/rust/src/alonzo/utils.rs b/multi-era/rust/src/alonzo/utils.rs index 802d8207..43a6ea18 100644 --- a/multi-era/rust/src/alonzo/utils.rs +++ b/multi-era/rust/src/alonzo/utils.rs @@ -25,9 +25,9 @@ impl From for AuxiliaryData { AlonzoAuxiliaryData::ShelleyMA(md) => AuxiliaryData::new_shelley_m_a(md.clone()), AlonzoAuxiliaryData::Alonzo(md) => AuxiliaryData::new_conway({ let mut conway = ConwayFormatAuxData::new(); - conway.metadata = md.metadata.clone(); - conway.native_scripts = md.native_scripts.clone(); - conway.plutus_v1_scripts = md.plutus_v1_scripts.clone(); + conway.metadata.clone_from(&md.metadata); + conway.native_scripts.clone_from(&md.native_scripts); + conway.plutus_v1_scripts.clone_from(&md.plutus_v1_scripts); conway }), } diff --git a/multi-era/rust/src/babbage/utils.rs b/multi-era/rust/src/babbage/utils.rs index 9d060ecd..050a97d2 100644 --- a/multi-era/rust/src/babbage/utils.rs +++ b/multi-era/rust/src/babbage/utils.rs @@ -66,10 +66,10 @@ impl From for AuxiliaryData { BabbageAuxiliaryData::ShelleyMA(md) => AuxiliaryData::new_shelley_m_a(md.clone()), BabbageAuxiliaryData::Babbage(md) => AuxiliaryData::new_conway({ let mut conway = ConwayFormatAuxData::new(); - conway.metadata = md.metadata.clone(); - conway.native_scripts = md.native_scripts.clone(); - conway.plutus_v1_scripts = md.plutus_v1_scripts.clone(); - conway.plutus_v2_scripts = md.plutus_v2_scripts.clone(); + conway.metadata.clone_from(&md.metadata); + conway.native_scripts.clone_from(&md.native_scripts); + conway.plutus_v1_scripts.clone_from(&md.plutus_v1_scripts); + conway.plutus_v2_scripts.clone_from(&md.plutus_v2_scripts); conway }), }