From 197b1d48d07720154f63334555b064cc2bb05c36 Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Sat, 25 Dec 2021 10:41:05 +0900 Subject: [PATCH 01/12] Add Witness builder --- rust/pkg/cardano_serialization_lib.js.flow | 69 +++++++ rust/src/crypto.rs | 8 +- rust/src/lib.rs | 17 +- rust/src/plutus.rs | 22 +- rust/src/utils.rs | 22 +- rust/src/witness_builder.rs | 225 +++++++++++++++++++++ 6 files changed, 338 insertions(+), 25 deletions(-) create mode 100644 rust/src/witness_builder.rs diff --git a/rust/pkg/cardano_serialization_lib.js.flow b/rust/pkg/cardano_serialization_lib.js.flow index 2a66c8ec..3359e850 100644 --- a/rust/pkg/cardano_serialization_lib.js.flow +++ b/rust/pkg/cardano_serialization_lib.js.flow @@ -251,10 +251,13 @@ declare export var NativeScriptKind: {| * This is because you could have a language where the same bytes have different semantics * So this avoids scripts in different languages mapping to the same hash * Note that the enum value here is different than the enum value for deciding the cost model of a script + * https://github.com/input-output-hk/cardano-ledger/blob/9c3b4737b13b30f71529e76c5330f403165e28a6/eras/alonzo/impl/src/Cardano/Ledger/Alonzo.hs#L127 */ declare export var ScriptHashNamespace: {| +NativeScript: 0, // 0 + +PlutusV1: 1, // 1 + +PlutusV2: 2, // 2 |}; /** @@ -278,6 +281,7 @@ declare export var StakeCredKind: {| declare export var LanguageKind: {| +PlutusV1: 0, // 0 + +PlutusV2: 1, // 1 |}; /** @@ -2173,6 +2177,11 @@ declare export class Language { */ static new_plutus_v1(): Language; + /** + * @returns {Language} + */ + static new_plutus_v2(): Language; + /** * @returns {number} */ @@ -3115,6 +3124,12 @@ declare export class PlutusScript { */ static from_bytes(bytes: Uint8Array): PlutusScript; + /** + * @param {number} namespace + * @returns {ScriptHash} + */ + hash(namespace: number): ScriptHash; + /** * @param {Uint8Array} bytes * @returns {PlutusScript} @@ -5821,6 +5836,60 @@ declare export class TransactionWitnessSet { */ static new(): TransactionWitnessSet; } +/** + * Builder de-duplicates witnesses as they are added + */ +declare export class TransactionWitnessSetBuilder { + free(): void; + + /** + * @param {Vkeywitness} vkey + */ + add_vkey(vkey: Vkeywitness): void; + + /** + * @param {BootstrapWitness} bootstrap + */ + add_bootstrap(bootstrap: BootstrapWitness): void; + + /** + * @param {NativeScript} native_script + */ + add_native_script(native_script: NativeScript): void; + + /** + * @param {PlutusScript} plutus_script + */ + add_plutus_script(plutus_script: PlutusScript): void; + + /** + * @param {PlutusData} plutus_datum + */ + add_plutus_datum(plutus_datum: PlutusData): void; + + /** + * @param {Redeemer} redeemer + */ + add_redeemer(redeemer: Redeemer): void; + + /** + * @returns {TransactionWitnessSetBuilder} + */ + static new(): TransactionWitnessSetBuilder; + + /** + * @param {TransactionWitnessSet} wit_set + * @returns {TransactionWitnessSetBuilder} + */ + static from_existing( + wit_set: TransactionWitnessSet + ): TransactionWitnessSetBuilder; + + /** + * @returns {TransactionWitnessSet} + */ + build(): TransactionWitnessSet; +} /** */ declare export class TransactionWitnessSets { diff --git a/rust/src/crypto.rs b/rust/src/crypto.rs index 93144db3..88740bdd 100644 --- a/rust/src/crypto.rs +++ b/rust/src/crypto.rs @@ -283,7 +283,7 @@ impl PrivateKey { /// ED25519 key used as public key #[wasm_bindgen] -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct PublicKey(crypto::PublicKey); impl From> for PublicKey { @@ -329,7 +329,7 @@ impl PublicKey { } #[wasm_bindgen] -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct Vkey(PublicKey); to_from_bytes!(Vkey); @@ -471,7 +471,7 @@ impl Deserialize for Vkeywitness { #[wasm_bindgen] #[derive(Clone)] -pub struct Vkeywitnesses(Vec); +pub struct Vkeywitnesses(pub (crate) Vec); #[wasm_bindgen] impl Vkeywitnesses { @@ -613,7 +613,7 @@ impl DeserializeEmbeddedGroup for BootstrapWitness { #[wasm_bindgen] #[derive(Clone)] -pub struct BootstrapWitnesses(Vec); +pub struct BootstrapWitnesses(pub (crate) Vec); #[wasm_bindgen] impl BootstrapWitnesses { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 600d91a4..00c2a761 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -50,6 +50,7 @@ pub mod typed_bytes; pub mod emip3; #[macro_use] pub mod utils; +pub mod witness_builder; use address::*; use crypto::*; @@ -1613,24 +1614,10 @@ pub struct NativeScript(NativeScriptEnum); to_from_bytes!(NativeScript); -/// Each new language uses a different namespace for hashing its script -/// This is because you could have a language where the same bytes have different semantics -/// So this avoids scripts in different languages mapping to the same hash -/// Note that the enum value here is different than the enum value for deciding the cost model of a script -#[wasm_bindgen] -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub enum ScriptHashNamespace { - NativeScript, - // TODO: do we need to update this for Plutus? -} - #[wasm_bindgen] impl NativeScript { pub fn hash(&self, namespace: ScriptHashNamespace) -> ScriptHash { - let mut bytes = Vec::with_capacity(self.to_bytes().len() + 1); - bytes.extend_from_slice(&vec![namespace as u8]); - bytes.extend_from_slice(&self.to_bytes()); - ScriptHash::from(blake2b224(bytes.as_ref())) + hash_script(namespace, self.to_bytes()) } pub fn new_script_pubkey(script_pubkey: &ScriptPubkey) -> Self { diff --git a/rust/src/plutus.rs b/rust/src/plutus.rs index 8c67a573..f3df55c5 100644 --- a/rust/src/plutus.rs +++ b/rust/src/plutus.rs @@ -15,6 +15,10 @@ to_from_bytes!(PlutusScript); #[wasm_bindgen] impl PlutusScript { + pub fn hash(&self, namespace: ScriptHashNamespace) -> ScriptHash { + hash_script(namespace, self.to_bytes()) + } + pub fn new(bytes: Vec) -> PlutusScript { Self(bytes) } @@ -26,7 +30,7 @@ impl PlutusScript { #[wasm_bindgen] #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct PlutusScripts(Vec); +pub struct PlutusScripts(pub (crate) Vec); to_from_bytes!(PlutusScripts); @@ -258,6 +262,7 @@ impl ExUnits { #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LanguageKind { PlutusV1, + PlutusV2, } #[wasm_bindgen] @@ -272,6 +277,10 @@ impl Language { Self(LanguageKind::PlutusV1) } + pub fn new_plutus_v2() -> Self { + Self(LanguageKind::PlutusV1) + } + pub fn kind(&self) -> LanguageKind { self.0 } @@ -424,7 +433,7 @@ impl PlutusData { #[wasm_bindgen] #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct PlutusList(Vec); +pub struct PlutusList(pub (crate) Vec); to_from_bytes!(PlutusList); @@ -487,7 +496,7 @@ impl Redeemer { } #[wasm_bindgen] -#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub enum RedeemerTagKind { Spend, Mint, @@ -496,7 +505,7 @@ pub enum RedeemerTagKind { } #[wasm_bindgen] -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] pub struct RedeemerTag(RedeemerTagKind); to_from_bytes!(RedeemerTag); @@ -526,7 +535,7 @@ impl RedeemerTag { #[wasm_bindgen] #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub struct Redeemers(Vec); +pub struct Redeemers(pub (crate) Vec); to_from_bytes!(Redeemers); @@ -832,6 +841,9 @@ impl cbor_event::se::Serialize for Language { LanguageKind::PlutusV1 => { serializer.write_unsigned_integer(0u64) }, + LanguageKind::PlutusV2 => { + serializer.write_unsigned_integer(1u64) + }, } } } diff --git a/rust/src/utils.rs b/rust/src/utils.rs index fd5dc13f..030ebe5f 100644 --- a/rust/src/utils.rs +++ b/rust/src/utils.rs @@ -1045,6 +1045,26 @@ fn bundle_size( } } +/// Each new language uses a different namespace for hashing its script +/// This is because you could have a language where the same bytes have different semantics +/// So this avoids scripts in different languages mapping to the same hash +/// Note that the enum value here is different than the enum value for deciding the cost model of a script +/// https://github.com/input-output-hk/cardano-ledger/blob/9c3b4737b13b30f71529e76c5330f403165e28a6/eras/alonzo/impl/src/Cardano/Ledger/Alonzo.hs#L127 +#[wasm_bindgen] +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum ScriptHashNamespace { + NativeScript, + PlutusV1, + PlutusV2 +} + +pub (crate) fn hash_script(namespace: ScriptHashNamespace, script: Vec) -> ScriptHash { + let mut bytes = Vec::with_capacity(script.len() + 1); + bytes.extend_from_slice(&vec![namespace as u8]); + bytes.extend_from_slice(&script); + ScriptHash::from(blake2b224(bytes.as_ref())) +} + #[wasm_bindgen] pub fn min_ada_required( assets: &Value, @@ -1089,7 +1109,7 @@ pub fn min_pure_ada(coins_per_utxo_word: &BigNum) -> Result { ) } -/// Used to choosed the schema for a script JSON string +/// Used to choose the schema for a script JSON string #[wasm_bindgen] pub enum ScriptSchema { Wallet, diff --git a/rust/src/witness_builder.rs b/rust/src/witness_builder.rs new file mode 100644 index 00000000..e6ffeedf --- /dev/null +++ b/rust/src/witness_builder.rs @@ -0,0 +1,225 @@ +use std::collections::HashMap; +use super::*; + +/// Builder de-duplicates witnesses as they are added +#[wasm_bindgen] +#[derive(Clone)] +pub struct TransactionWitnessSetBuilder { + // See Alonzo spec section 3.1 which defines the keys for these types + vkeys: HashMap, + bootstraps: HashMap, + native_scripts: HashMap, + plutus_scripts: HashMap, + plutus_data: HashMap, + redeemers: HashMap, +} + +#[wasm_bindgen] +impl TransactionWitnessSetBuilder { + pub fn add_vkey(&mut self, vkey: &Vkeywitness) { + self.vkeys.insert(vkey.vkey(), vkey.clone()); + } + + pub fn add_bootstrap(&mut self, bootstrap: &BootstrapWitness) { + self.bootstraps.insert(bootstrap.vkey(), bootstrap.clone()); + } + + pub fn add_native_script(&mut self, native_script: &NativeScript) { + self.native_scripts.insert(native_script.hash(ScriptHashNamespace::NativeScript), native_script.clone()); + } + + pub fn add_plutus_script(&mut self, plutus_script: &PlutusScript) { + // TODO: don't assume PlutusV1 and instead somehow calculate this + self.plutus_scripts.insert(plutus_script.hash(ScriptHashNamespace::PlutusV1), plutus_script.clone()); + } + + pub fn add_plutus_datum(&mut self, plutus_datum: &PlutusData) { + self.plutus_data.insert(hash_plutus_data(&plutus_datum), plutus_datum.clone()); + } + + pub fn add_redeemer(&mut self, redeemer: &Redeemer) { + self.redeemers.insert(redeemer.tag().clone(), redeemer.clone()); + } + + pub fn new() -> Self { + Self { + vkeys: HashMap::new(), + bootstraps: HashMap::new(), + native_scripts: HashMap::new(), + plutus_scripts: HashMap::new(), + plutus_data: HashMap::new(), + redeemers: HashMap::new(), + } + } + + pub fn from_existing(wit_set: &TransactionWitnessSet) -> Self { + let mut builder = TransactionWitnessSetBuilder::new(); + match &wit_set.vkeys() { + None => (), + Some(vkeys) => vkeys.0.iter().for_each(|vkey| { builder.add_vkey(vkey); } ), + }; + match &wit_set.bootstraps() { + None => (), + Some(bootstraps) => bootstraps.0.iter().for_each(|bootstrap| { builder.add_bootstrap(bootstrap); } ), + }; + match &wit_set.native_scripts() { + None => (), + Some(native_scripts) => native_scripts.0.iter().for_each(|native_script| { builder.add_native_script(native_script); } ), + }; + match &wit_set.plutus_scripts() { + None => (), + Some(plutus_scripts) => plutus_scripts.0.iter().for_each(|plutus_script| { builder.add_plutus_script(plutus_script); } ), + }; + match &wit_set.plutus_data() { + None => (), + Some(plutus_data) => plutus_data.0.iter().for_each(|plutus_datum| { builder.add_plutus_datum(plutus_datum); } ), + }; + match &wit_set.redeemers() { + None => (), + Some(redeemers) => redeemers.0.iter().for_each(|redeemer| { builder.add_redeemer(redeemer); } ), + }; + + builder + } + + pub fn build(&self) -> TransactionWitnessSet { + let mut result = TransactionWitnessSet::new(); + + if self.vkeys.len() > 0 { + result.set_vkeys(&Vkeywitnesses(self.vkeys.values().cloned().collect())); + } + if self.bootstraps.len() > 0 { + result.set_bootstraps(&BootstrapWitnesses(self.bootstraps.values().cloned().collect())); + } + if self.native_scripts.len() > 0 { + result.set_native_scripts(&NativeScripts(self.native_scripts.values().cloned().collect())); + } + if self.plutus_scripts.len() > 0 { + result.set_plutus_scripts(&PlutusScripts(self.plutus_scripts.values().cloned().collect())); + } + if self.plutus_data.len() > 0 { + result.set_plutus_data(&PlutusList(self.plutus_data.values().cloned().collect())); + } + if self.redeemers.len() > 0 { + result.set_redeemers(&Redeemers(self.redeemers.values().cloned().collect())); + } + + result + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn fake_raw_key_sig(id: u8) -> Ed25519Signature { + Ed25519Signature::from_bytes( + vec![id, 248, 153, 211, 155, 23, 253, 93, 102, 193, 146, 196, 181, 13, 52, 62, 66, 247, 35, 91, 48, 80, 76, 138, 231, 97, 159, 147, 200, 40, 220, 109, 206, 69, 104, 221, 105, 23, 124, 85, 24, 40, 73, 45, 119, 122, 103, 39, 253, 102, 194, 251, 204, 189, 168, 194, 174, 237, 146, 3, 44, 153, 121, 10] + ).unwrap() + } + + fn fake_raw_key_public(id: u8) -> PublicKey { + PublicKey::from_bytes( + &[id, 118, 57, 154, 33, 13, 232, 114, 14, 159, 168, 148, 228, 94, 65, 226, 154, 181, 37, 227, 11, 196, 2, 128, 28, 7, 98, 80, 209, 88, 91, 205] + ).unwrap() + } + + fn fake_private_key1() -> Bip32PrivateKey { + Bip32PrivateKey::from_bytes( + &[0xb8, 0xf2, 0xbe, 0xce, 0x9b, 0xdf, 0xe2, 0xb0, 0x28, 0x2f, 0x5b, 0xad, 0x70, 0x55, 0x62, 0xac, 0x99, 0x6e, 0xfb, 0x6a, 0xf9, 0x6b, 0x64, 0x8f, + 0x44, 0x45, 0xec, 0x44, 0xf4, 0x7a, 0xd9, 0x5c, 0x10, 0xe3, 0xd7, 0x2f, 0x26, 0xed, 0x07, 0x54, 0x22, 0xa3, 0x6e, 0xd8, 0x58, 0x5c, 0x74, 0x5a, + 0x0e, 0x11, 0x50, 0xbc, 0xce, 0xba, 0x23, 0x57, 0xd0, 0x58, 0x63, 0x69, 0x91, 0xf3, 0x8a, 0x37, 0x91, 0xe2, 0x48, 0xde, 0x50, 0x9c, 0x07, 0x0d, + 0x81, 0x2a, 0xb2, 0xfd, 0xa5, 0x78, 0x60, 0xac, 0x87, 0x6b, 0xc4, 0x89, 0x19, 0x2c, 0x1e, 0xf4, 0xce, 0x25, 0x3c, 0x19, 0x7e, 0xe2, 0x19, 0xa4] + ).unwrap() + } + + fn fake_private_key2() -> Bip32PrivateKey { + Bip32PrivateKey::from_bytes( + &hex::decode("d84c65426109a36edda5375ea67f1b738e1dacf8629f2bb5a2b0b20f3cd5075873bf5cdfa7e533482677219ac7d639e30a38e2e645ea9140855f44ff09e60c52c8b95d0d35fe75a70f9f5633a3e2439b2994b9e2bc851c49e9f91d1a5dcbb1a3").unwrap() + ).unwrap() + } + + + #[test] + fn vkey_test() { + let mut builder = TransactionWitnessSetBuilder::new(); + + let raw_key_public = fake_raw_key_public(0); + let fake_sig = fake_raw_key_sig(0); + + // add the same element twice + builder.add_vkey(&Vkeywitness::new( + &Vkey::new(&raw_key_public), + &fake_sig + )); + builder.add_vkey(&Vkeywitness::new( + &Vkey::new(&raw_key_public), + &fake_sig + )); + + // add a different element + builder.add_vkey(&Vkeywitness::new( + &Vkey::new(&fake_raw_key_public(1)), + &fake_raw_key_sig(1) + )); + + let wit_set = builder.build(); + assert_eq!( + wit_set.vkeys().unwrap().len(), + 2 + ); + } + + #[test] + fn bootstrap_test() { + let mut builder = TransactionWitnessSetBuilder::new(); + + // add the same element twice + let wit1 = make_icarus_bootstrap_witness( + &TransactionHash::from([0u8; TransactionHash::BYTE_COUNT]), + &ByronAddress::from_base58("Ae2tdPwUPEZGUEsuMAhvDcy94LKsZxDjCbgaiBBMgYpR8sKf96xJmit7Eho").unwrap(), + &fake_private_key1() + ); + builder.add_bootstrap(&wit1); + builder.add_bootstrap(&wit1); + + // add a different element + builder.add_bootstrap(&make_icarus_bootstrap_witness( + &TransactionHash::from([0u8; TransactionHash::BYTE_COUNT]), + &ByronAddress::from_base58("Ae2tdPwUPEZGUEsuMAhvDcy94LKsZxDjCbgaiBBMgYpR8sKf96xJmit7Eho").unwrap(), + &fake_private_key2() + )); + + let wit_set = builder.build(); + assert_eq!( + wit_set.bootstraps().unwrap().len(), + 2 + ); + } + + #[test] + fn native_script_test() { + let mut builder = TransactionWitnessSetBuilder::new(); + + // add the same element twice + let wit1 = NativeScript::new_timelock_start( + &TimelockStart::new(1), + ); + builder.add_native_script(&wit1); + builder.add_native_script(&wit1); + + // add a different element + builder.add_native_script(&NativeScript::new_timelock_start( + &TimelockStart::new(2), + )); + + let wit_set = builder.build(); + assert_eq!( + wit_set.native_scripts().unwrap().len(), + 2 + ); + } + + // TODO: tests for plutus_scripts, plutus_data, redeemers + // once we have mock data for them +} \ No newline at end of file From 4549aeeafe4e8b8d58f71f63513bb0492e7f9903 Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Sun, 26 Dec 2021 01:03:41 +0900 Subject: [PATCH 02/12] Fix plutus_v2 enum --- rust/src/plutus.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/src/plutus.rs b/rust/src/plutus.rs index f3df55c5..b29e09e4 100644 --- a/rust/src/plutus.rs +++ b/rust/src/plutus.rs @@ -278,7 +278,7 @@ impl Language { } pub fn new_plutus_v2() -> Self { - Self(LanguageKind::PlutusV1) + Self(LanguageKind::PlutusV2) } pub fn kind(&self) -> LanguageKind { From fbd6f83804e41d515ce4ce4fb8011fd346d3942b Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Sun, 26 Dec 2021 01:09:50 +0900 Subject: [PATCH 03/12] Add RequiredSignatureSet support --- rust/pkg/cardano_serialization_lib.js.flow | 112 ++++++++++- rust/src/witness_builder.rs | 204 +++++++++++++++++++-- 2 files changed, 295 insertions(+), 21 deletions(-) diff --git a/rust/pkg/cardano_serialization_lib.js.flow b/rust/pkg/cardano_serialization_lib.js.flow index 3359e850..0e80b24c 100644 --- a/rust/pkg/cardano_serialization_lib.js.flow +++ b/rust/pkg/cardano_serialization_lib.js.flow @@ -4031,6 +4031,28 @@ declare export class RedeemerTag { */ kind(): number; } +/** + */ +declare export class RedeemerWitnessKey { + free(): void; + + /** + * @returns {RedeemerTag} + */ + tag(): RedeemerTag; + + /** + * @returns {BigNum} + */ + index(): BigNum; + + /** + * @param {RedeemerTag} tag + * @param {BigNum} index + * @returns {RedeemerWitnessKey} + */ + static new(tag: RedeemerTag, index: BigNum): RedeemerWitnessKey; +} /** */ declare export class Redeemers { @@ -4159,6 +4181,81 @@ declare export class Relays { */ add(elem: Relay): void; } +/** + */ +declare export class RequiredSignatureSet { + free(): void; + + /** + * @param {Vkeywitness} vkey + */ + add_vkey(vkey: Vkeywitness): void; + + /** + * @param {Vkey} vkey + */ + add_vkey_key(vkey: Vkey): void; + + /** + * @param {BootstrapWitness} bootstrap + */ + add_bootstrap(bootstrap: BootstrapWitness): void; + + /** + * @param {Vkey} bootstrap + */ + add_bootstrap_key(bootstrap: Vkey): void; + + /** + * @param {NativeScript} native_script + */ + add_native_script(native_script: NativeScript): void; + + /** + * @param {ScriptHash} native_script + */ + add_native_script_hash(native_script: ScriptHash): void; + + /** + * @param {PlutusScript} plutus_script + */ + add_plutus_script(plutus_script: PlutusScript): void; + + /** + * @param {ScriptHash} plutus_script + */ + add_plutus_hash(plutus_script: ScriptHash): void; + + /** + * @param {PlutusData} plutus_datum + */ + add_plutus_datum(plutus_datum: PlutusData): void; + + /** + * @param {DataHash} plutus_datum + */ + add_plutus_datum_hash(plutus_datum: DataHash): void; + + /** + * @param {Redeemer} redeemer + */ + add_redeemer(redeemer: Redeemer): void; + + /** + * @param {RedeemerWitnessKey} redeemer + */ + add_redeemer_tag(redeemer: RedeemerWitnessKey): void; + + /** + * @param {RequiredSignatureSet} requirements + */ + add_all(requirements: RequiredSignatureSet): void; + + /** + * @returns {RequiredSignatureSet} + */ + static new(): RequiredSignatureSet; +} /** */ declare export class RewardAddress { @@ -5872,6 +5969,16 @@ declare export class TransactionWitnessSetBuilder { */ add_redeemer(redeemer: Redeemer): void; + /** + * @param {RequiredSignatureSet} required_sigs + */ + set_required_sigs(required_sigs: RequiredSignatureSet): void; + + /** + * @returns {RequiredSignatureSet} + */ + get_required_sigs(): RequiredSignatureSet; + /** * @returns {TransactionWitnessSetBuilder} */ @@ -5879,11 +5986,10 @@ declare export class TransactionWitnessSetBuilder { /** * @param {TransactionWitnessSet} wit_set - * @returns {TransactionWitnessSetBuilder} */ - static from_existing( + static add_existing( wit_set: TransactionWitnessSet - ): TransactionWitnessSetBuilder; + ): void; /** * @returns {TransactionWitnessSet} diff --git a/rust/src/witness_builder.rs b/rust/src/witness_builder.rs index e6ffeedf..d20845bd 100644 --- a/rust/src/witness_builder.rs +++ b/rust/src/witness_builder.rs @@ -1,6 +1,130 @@ -use std::collections::HashMap; +use std::collections::{HashSet, HashMap}; use super::*; +#[wasm_bindgen] +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct RedeemerWitnessKey { + tag: RedeemerTag, + index: BigNum, +} + +#[wasm_bindgen] +impl RedeemerWitnessKey { + + pub fn tag(&self) -> RedeemerTag { + self.tag.clone() + } + + pub fn index(&self) -> BigNum { + self.index.clone() + } + + pub fn new(tag: &RedeemerTag, index: &BigNum) -> Self { + Self { + tag: tag.clone(), + index: index.clone(), + } + } + +} + +#[wasm_bindgen] +#[derive(Clone)] +pub struct RequiredSignatureSet { + vkeys: HashSet, + bootstraps: HashSet, + native_scripts: HashSet, + plutus_scripts: HashSet, + plutus_data: HashSet, + redeemers: HashSet, +} + +#[wasm_bindgen] +impl RequiredSignatureSet { + pub fn add_vkey(&mut self, vkey: &Vkeywitness) { + self.add_vkey_key(&vkey.vkey()); + } + pub fn add_vkey_key(&mut self, vkey: &Vkey) { + self.vkeys.insert(vkey.clone()); + } + + pub fn add_bootstrap(&mut self, bootstrap: &BootstrapWitness) { + self.add_bootstrap_key(&bootstrap.vkey()); + } + pub fn add_bootstrap_key(&mut self, bootstrap: &Vkey) { + self.bootstraps.insert(bootstrap.clone()); + } + + pub fn add_native_script(&mut self, native_script: &NativeScript) { + self.add_native_script_hash(&native_script.hash(ScriptHashNamespace::NativeScript)); + } + pub fn add_native_script_hash(&mut self, native_script: &ScriptHash) { + self.native_scripts.insert(native_script.clone()); + } + + pub fn add_plutus_script(&mut self, plutus_script: &PlutusScript) { + // TODO: don't assume PlutusV1 and instead somehow calculate this + self.add_plutus_hash(&plutus_script.hash(ScriptHashNamespace::PlutusV1)); + } + pub fn add_plutus_hash(&mut self, plutus_script: &ScriptHash) { + self.plutus_scripts.insert(plutus_script.clone()); + } + + pub fn add_plutus_datum(&mut self, plutus_datum: &PlutusData) { + self.add_plutus_datum_hash(&hash_plutus_data(&plutus_datum)); + } + pub fn add_plutus_datum_hash(&mut self, plutus_datum: &DataHash) { + self.plutus_data.insert(plutus_datum.clone()); + } + + pub fn add_redeemer(&mut self, redeemer: &Redeemer) { + self.add_redeemer_tag(&RedeemerWitnessKey::new(&redeemer.tag(), &redeemer.index())); + } + pub fn add_redeemer_tag(&mut self, redeemer: &RedeemerWitnessKey) { + self.redeemers.insert(redeemer.clone()); + } + + pub fn add_all(&mut self, requirements: &RequiredSignatureSet) { + self.vkeys.extend(requirements.vkeys.iter().cloned()); + self.bootstraps.extend(requirements.bootstraps.iter().cloned()); + self.native_scripts.extend(requirements.native_scripts.iter().cloned()); + self.plutus_scripts.extend(requirements.plutus_scripts.iter().cloned()); + self.plutus_data.extend(requirements.plutus_data.iter().cloned()); + self.redeemers.extend(requirements.redeemers.iter().cloned()); + } + + pub (crate) fn to_str(&self) -> String { + let vkeys = self.vkeys.iter().map(|key| format!("Vkey:{}", hex::encode(key.to_bytes()))).collect::>().join(","); + let bootstraps = self.bootstraps.iter().map(|key| format!("Legacy Bootstraps:{}", hex::encode(key.to_bytes()))).collect::>().join(","); + let native_scripts = self.native_scripts.iter().map(|hash| format!("Native script hash:{}", hex::encode(hash.to_bytes()))).collect::>().join(","); + let plutus_scripts = self.plutus_scripts.iter().map(|hash| format!("Plutus script hash:{}", hex::encode(hash.to_bytes()))).collect::>().join(","); + let plutus_data = self.plutus_data.iter().map(|hash| format!("Plutus data hash:{}", hex::encode(hash.to_bytes()))).collect::>().join(","); + let redeemers = self.redeemers.iter().map(|key| format!("Redeemer:{}-{}", hex::encode(key.tag().to_bytes()), key.index().to_str())).collect::>().join(","); + + [vkeys, bootstraps, native_scripts, plutus_scripts, plutus_data, redeemers].iter().filter(|msg| msg.len() > 0).cloned().collect::>().join("\n") + } + + pub (crate) fn len(&self) -> usize { + self.vkeys.len() + + self.bootstraps.len() + + self.native_scripts.len() + + self.plutus_scripts.len() + + self.plutus_data.len() + + self.redeemers.len() + } + + pub fn new() -> Self { + Self { + vkeys: HashSet::new(), + bootstraps: HashSet::new(), + native_scripts: HashSet::new(), + plutus_scripts: HashSet::new(), + plutus_data: HashSet::new(), + redeemers: HashSet::new(), + } + } +} + /// Builder de-duplicates witnesses as they are added #[wasm_bindgen] #[derive(Clone)] @@ -11,7 +135,10 @@ pub struct TransactionWitnessSetBuilder { native_scripts: HashMap, plutus_scripts: HashMap, plutus_data: HashMap, - redeemers: HashMap, + redeemers: HashMap, + + // signatures that need to be added for the build function to succeed + required_sigs: RequiredSignatureSet, } #[wasm_bindgen] @@ -38,7 +165,18 @@ impl TransactionWitnessSetBuilder { } pub fn add_redeemer(&mut self, redeemer: &Redeemer) { - self.redeemers.insert(redeemer.tag().clone(), redeemer.clone()); + self.redeemers.insert( + RedeemerWitnessKey::new(&redeemer.tag(), &redeemer.index()), + redeemer.clone() + ); + } + + pub fn set_required_sigs(&mut self, required_sigs: &RequiredSignatureSet) { + self.required_sigs = required_sigs.clone() + } + + pub fn get_required_sigs(&self) -> RequiredSignatureSet { + self.required_sigs.clone() } pub fn new() -> Self { @@ -49,62 +187,71 @@ impl TransactionWitnessSetBuilder { plutus_scripts: HashMap::new(), plutus_data: HashMap::new(), redeemers: HashMap::new(), + required_sigs: RequiredSignatureSet::new(), } } - pub fn from_existing(wit_set: &TransactionWitnessSet) -> Self { - let mut builder = TransactionWitnessSetBuilder::new(); + pub fn add_existing(&mut self, wit_set: &TransactionWitnessSet) { match &wit_set.vkeys() { None => (), - Some(vkeys) => vkeys.0.iter().for_each(|vkey| { builder.add_vkey(vkey); } ), + Some(vkeys) => vkeys.0.iter().for_each(|vkey| { self.add_vkey(vkey); } ), }; match &wit_set.bootstraps() { None => (), - Some(bootstraps) => bootstraps.0.iter().for_each(|bootstrap| { builder.add_bootstrap(bootstrap); } ), + Some(bootstraps) => bootstraps.0.iter().for_each(|bootstrap| { self.add_bootstrap(bootstrap); } ), }; match &wit_set.native_scripts() { None => (), - Some(native_scripts) => native_scripts.0.iter().for_each(|native_script| { builder.add_native_script(native_script); } ), + Some(native_scripts) => native_scripts.0.iter().for_each(|native_script| { self.add_native_script(native_script); } ), }; match &wit_set.plutus_scripts() { None => (), - Some(plutus_scripts) => plutus_scripts.0.iter().for_each(|plutus_script| { builder.add_plutus_script(plutus_script); } ), + Some(plutus_scripts) => plutus_scripts.0.iter().for_each(|plutus_script| { self.add_plutus_script(plutus_script); } ), }; match &wit_set.plutus_data() { None => (), - Some(plutus_data) => plutus_data.0.iter().for_each(|plutus_datum| { builder.add_plutus_datum(plutus_datum); } ), + Some(plutus_data) => plutus_data.0.iter().for_each(|plutus_datum| { self.add_plutus_datum(plutus_datum); } ), }; match &wit_set.redeemers() { None => (), - Some(redeemers) => redeemers.0.iter().for_each(|redeemer| { builder.add_redeemer(redeemer); } ), + Some(redeemers) => redeemers.0.iter().for_each(|redeemer| { self.add_redeemer(redeemer); } ), }; - - builder } - pub fn build(&self) -> TransactionWitnessSet { + pub fn build(&self) -> Result { let mut result = TransactionWitnessSet::new(); + let mut remaining_sigs = self.required_sigs.clone(); if self.vkeys.len() > 0 { result.set_vkeys(&Vkeywitnesses(self.vkeys.values().cloned().collect())); + self.vkeys.keys().for_each(|key| { remaining_sigs.vkeys.remove(key); }); } if self.bootstraps.len() > 0 { result.set_bootstraps(&BootstrapWitnesses(self.bootstraps.values().cloned().collect())); + self.bootstraps.keys().for_each(|key| { remaining_sigs.bootstraps.remove(key); }); } if self.native_scripts.len() > 0 { result.set_native_scripts(&NativeScripts(self.native_scripts.values().cloned().collect())); + self.native_scripts.keys().for_each(|hash| { remaining_sigs.native_scripts.remove(hash); }); } if self.plutus_scripts.len() > 0 { result.set_plutus_scripts(&PlutusScripts(self.plutus_scripts.values().cloned().collect())); + self.plutus_scripts.keys().for_each(|hash| { remaining_sigs.plutus_scripts.remove(hash); }); } if self.plutus_data.len() > 0 { result.set_plutus_data(&PlutusList(self.plutus_data.values().cloned().collect())); + self.plutus_data.keys().for_each(|hash| { remaining_sigs.plutus_data.remove(hash); }); } if self.redeemers.len() > 0 { result.set_redeemers(&Redeemers(self.redeemers.values().cloned().collect())); + self.redeemers.keys().for_each(|key| { remaining_sigs.redeemers.remove(key); }); + } + + if remaining_sigs.len() > 0 { + return Err(JsError::from_str(&format!("Missing following witnesses:\n{}", remaining_sigs.to_str()))) } - result + Ok(result) } } @@ -163,7 +310,7 @@ mod tests { &fake_raw_key_sig(1) )); - let wit_set = builder.build(); + let wit_set = builder.build().unwrap(); assert_eq!( wit_set.vkeys().unwrap().len(), 2 @@ -190,7 +337,7 @@ mod tests { &fake_private_key2() )); - let wit_set = builder.build(); + let wit_set = builder.build().unwrap(); assert_eq!( wit_set.bootstraps().unwrap().len(), 2 @@ -213,7 +360,7 @@ mod tests { &TimelockStart::new(2), )); - let wit_set = builder.build(); + let wit_set = builder.build().unwrap(); assert_eq!( wit_set.native_scripts().unwrap().len(), 2 @@ -222,4 +369,25 @@ mod tests { // TODO: tests for plutus_scripts, plutus_data, redeemers // once we have mock data for them + + #[test] + fn requirement_test() { + let mut builder = TransactionWitnessSetBuilder::new(); + + let mut required_sigs = RequiredSignatureSet::new(); + required_sigs.add_vkey_key(&Vkey::new(&fake_raw_key_public(0))); + required_sigs.add_native_script(&NativeScript::new_timelock_start( + &TimelockStart::new(2), + )); + builder.set_required_sigs(&required_sigs); + + // add a different element + builder.add_vkey(&Vkeywitness::new( + &Vkey::new(&fake_raw_key_public(1)), + &fake_raw_key_sig(1) + )); + + assert!(builder.build().is_err() + ); + } } \ No newline at end of file From 844e049db67ba7b0f943d4b4435aace2bad4e227 Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Sun, 26 Dec 2021 02:22:09 +0900 Subject: [PATCH 04/12] Rename signature -> witness --- rust/pkg/cardano_serialization_lib.js.flow | 23 ++++------- rust/src/witness_builder.rs | 46 ++++++++++------------ 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/rust/pkg/cardano_serialization_lib.js.flow b/rust/pkg/cardano_serialization_lib.js.flow index 0e80b24c..d0db2636 100644 --- a/rust/pkg/cardano_serialization_lib.js.flow +++ b/rust/pkg/cardano_serialization_lib.js.flow @@ -4183,7 +4183,7 @@ declare export class Relays { } /** */ -declare export class RequiredSignatureSet { +declare export class RequiredWitnessSet { free(): void; /** @@ -4247,14 +4247,14 @@ declare export class RequiredSignatureSet { add_redeemer_tag(redeemer: RedeemerWitnessKey): void; /** - * @param {RequiredSignatureSet} requirements + * @param {RequiredWitnessSet} requirements */ - add_all(requirements: RequiredSignatureSet): void; + add_all(requirements: RequiredWitnessSet): void; /** - * @returns {RequiredSignatureSet} + * @returns {RequiredWitnessSet} */ - static new(): RequiredSignatureSet; + static new(): RequiredWitnessSet; } /** */ @@ -5970,14 +5970,9 @@ declare export class TransactionWitnessSetBuilder { add_redeemer(redeemer: Redeemer): void; /** - * @param {RequiredSignatureSet} required_sigs + * @param {RequiredWitnessSet} required_wits */ - set_required_sigs(required_sigs: RequiredSignatureSet): void; - - /** - * @returns {RequiredSignatureSet} - */ - get_required_sigs(): RequiredSignatureSet; + set_required_wits(required_wits: RequiredWitnessSet): void; /** * @returns {TransactionWitnessSetBuilder} @@ -5987,9 +5982,7 @@ declare export class TransactionWitnessSetBuilder { /** * @param {TransactionWitnessSet} wit_set */ - static add_existing( - wit_set: TransactionWitnessSet - ): void; + add_existing(wit_set: TransactionWitnessSet): void; /** * @returns {TransactionWitnessSet} diff --git a/rust/src/witness_builder.rs b/rust/src/witness_builder.rs index d20845bd..2477a590 100644 --- a/rust/src/witness_builder.rs +++ b/rust/src/witness_builder.rs @@ -30,7 +30,7 @@ impl RedeemerWitnessKey { #[wasm_bindgen] #[derive(Clone)] -pub struct RequiredSignatureSet { +pub struct RequiredWitnessSet { vkeys: HashSet, bootstraps: HashSet, native_scripts: HashSet, @@ -40,7 +40,7 @@ pub struct RequiredSignatureSet { } #[wasm_bindgen] -impl RequiredSignatureSet { +impl RequiredWitnessSet { pub fn add_vkey(&mut self, vkey: &Vkeywitness) { self.add_vkey_key(&vkey.vkey()); } @@ -84,7 +84,7 @@ impl RequiredSignatureSet { self.redeemers.insert(redeemer.clone()); } - pub fn add_all(&mut self, requirements: &RequiredSignatureSet) { + pub fn add_all(&mut self, requirements: &RequiredWitnessSet) { self.vkeys.extend(requirements.vkeys.iter().cloned()); self.bootstraps.extend(requirements.bootstraps.iter().cloned()); self.native_scripts.extend(requirements.native_scripts.iter().cloned()); @@ -137,8 +137,8 @@ pub struct TransactionWitnessSetBuilder { plutus_data: HashMap, redeemers: HashMap, - // signatures that need to be added for the build function to succeed - required_sigs: RequiredSignatureSet, + // witnesses that need to be added for the build function to succeed + required_wits: RequiredWitnessSet, } #[wasm_bindgen] @@ -171,12 +171,8 @@ impl TransactionWitnessSetBuilder { ); } - pub fn set_required_sigs(&mut self, required_sigs: &RequiredSignatureSet) { - self.required_sigs = required_sigs.clone() - } - - pub fn get_required_sigs(&self) -> RequiredSignatureSet { - self.required_sigs.clone() + pub fn set_required_wits(&mut self, required_wits: &RequiredWitnessSet) { + self.required_wits = required_wits.clone() } pub fn new() -> Self { @@ -187,7 +183,7 @@ impl TransactionWitnessSetBuilder { plutus_scripts: HashMap::new(), plutus_data: HashMap::new(), redeemers: HashMap::new(), - required_sigs: RequiredSignatureSet::new(), + required_wits: RequiredWitnessSet::new(), } } @@ -220,35 +216,35 @@ impl TransactionWitnessSetBuilder { pub fn build(&self) -> Result { let mut result = TransactionWitnessSet::new(); - let mut remaining_sigs = self.required_sigs.clone(); + let mut remaining_wits = self.required_wits.clone(); if self.vkeys.len() > 0 { result.set_vkeys(&Vkeywitnesses(self.vkeys.values().cloned().collect())); - self.vkeys.keys().for_each(|key| { remaining_sigs.vkeys.remove(key); }); + self.vkeys.keys().for_each(|key| { remaining_wits.vkeys.remove(key); }); } if self.bootstraps.len() > 0 { result.set_bootstraps(&BootstrapWitnesses(self.bootstraps.values().cloned().collect())); - self.bootstraps.keys().for_each(|key| { remaining_sigs.bootstraps.remove(key); }); + self.bootstraps.keys().for_each(|key| { remaining_wits.bootstraps.remove(key); }); } if self.native_scripts.len() > 0 { result.set_native_scripts(&NativeScripts(self.native_scripts.values().cloned().collect())); - self.native_scripts.keys().for_each(|hash| { remaining_sigs.native_scripts.remove(hash); }); + self.native_scripts.keys().for_each(|hash| { remaining_wits.native_scripts.remove(hash); }); } if self.plutus_scripts.len() > 0 { result.set_plutus_scripts(&PlutusScripts(self.plutus_scripts.values().cloned().collect())); - self.plutus_scripts.keys().for_each(|hash| { remaining_sigs.plutus_scripts.remove(hash); }); + self.plutus_scripts.keys().for_each(|hash| { remaining_wits.plutus_scripts.remove(hash); }); } if self.plutus_data.len() > 0 { result.set_plutus_data(&PlutusList(self.plutus_data.values().cloned().collect())); - self.plutus_data.keys().for_each(|hash| { remaining_sigs.plutus_data.remove(hash); }); + self.plutus_data.keys().for_each(|hash| { remaining_wits.plutus_data.remove(hash); }); } if self.redeemers.len() > 0 { result.set_redeemers(&Redeemers(self.redeemers.values().cloned().collect())); - self.redeemers.keys().for_each(|key| { remaining_sigs.redeemers.remove(key); }); + self.redeemers.keys().for_each(|key| { remaining_wits.redeemers.remove(key); }); } - if remaining_sigs.len() > 0 { - return Err(JsError::from_str(&format!("Missing following witnesses:\n{}", remaining_sigs.to_str()))) + if remaining_wits.len() > 0 { + return Err(JsError::from_str(&format!("Missing following witnesses:\n{}", remaining_wits.to_str()))) } Ok(result) @@ -374,12 +370,12 @@ mod tests { fn requirement_test() { let mut builder = TransactionWitnessSetBuilder::new(); - let mut required_sigs = RequiredSignatureSet::new(); - required_sigs.add_vkey_key(&Vkey::new(&fake_raw_key_public(0))); - required_sigs.add_native_script(&NativeScript::new_timelock_start( + let mut required_wits = RequiredWitnessSet::new(); + required_wits.add_vkey_key(&Vkey::new(&fake_raw_key_public(0))); + required_wits.add_native_script(&NativeScript::new_timelock_start( &TimelockStart::new(2), )); - builder.set_required_sigs(&required_sigs); + builder.set_required_wits(&required_wits); // add a different element builder.add_vkey(&Vkeywitness::new( From 66a293edcfbf7f0e670256ac4233da4bfbd1706f Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Sun, 26 Dec 2021 09:41:53 +0900 Subject: [PATCH 05/12] Change set -> add_required_wits --- rust/pkg/cardano_serialization_lib.js.flow | 2 +- rust/src/witness_builder.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/pkg/cardano_serialization_lib.js.flow b/rust/pkg/cardano_serialization_lib.js.flow index d0db2636..97ad0fb3 100644 --- a/rust/pkg/cardano_serialization_lib.js.flow +++ b/rust/pkg/cardano_serialization_lib.js.flow @@ -5972,7 +5972,7 @@ declare export class TransactionWitnessSetBuilder { /** * @param {RequiredWitnessSet} required_wits */ - set_required_wits(required_wits: RequiredWitnessSet): void; + add_required_wits(required_wits: RequiredWitnessSet): void; /** * @returns {TransactionWitnessSetBuilder} diff --git a/rust/src/witness_builder.rs b/rust/src/witness_builder.rs index 2477a590..fcfec3ed 100644 --- a/rust/src/witness_builder.rs +++ b/rust/src/witness_builder.rs @@ -171,8 +171,8 @@ impl TransactionWitnessSetBuilder { ); } - pub fn set_required_wits(&mut self, required_wits: &RequiredWitnessSet) { - self.required_wits = required_wits.clone() + pub fn add_required_wits(&mut self, required_wits: &RequiredWitnessSet) { + self.required_wits.add_all(&required_wits) } pub fn new() -> Self { @@ -375,7 +375,7 @@ mod tests { required_wits.add_native_script(&NativeScript::new_timelock_start( &TimelockStart::new(2), )); - builder.set_required_wits(&required_wits); + builder.add_required_wits(&required_wits); // add a different element builder.add_vkey(&Vkeywitness::new( From 9180f8bc0529866793879d44a48fda2b1f7203b9 Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Sat, 1 Jan 2022 18:15:05 +0900 Subject: [PATCH 06/12] PR feedback --- rust/pkg/cardano_serialization_lib.js.flow | 10 +++++ rust/src/witness_builder.rs | 45 ++++++++++++++++------ 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/rust/pkg/cardano_serialization_lib.js.flow b/rust/pkg/cardano_serialization_lib.js.flow index 97ad0fb3..eea7644c 100644 --- a/rust/pkg/cardano_serialization_lib.js.flow +++ b/rust/pkg/cardano_serialization_lib.js.flow @@ -4196,6 +4196,11 @@ declare export class RequiredWitnessSet { */ add_vkey_key(vkey: Vkey): void; + /** + * @param {Ed25519KeyHash} hash + */ + add_vkey_key_hash(hash: Ed25519KeyHash): void; + /** * @param {BootstrapWitness} bootstrap */ @@ -4206,6 +4211,11 @@ declare export class RequiredWitnessSet { */ add_bootstrap_key(bootstrap: Vkey): void; + /** + * @param {Ed25519KeyHash} hash + */ + add_bootstrap_key_hash(hash: Ed25519KeyHash): void; + /** * @param {NativeScript} native_script */ diff --git a/rust/src/witness_builder.rs b/rust/src/witness_builder.rs index fcfec3ed..625ba98c 100644 --- a/rust/src/witness_builder.rs +++ b/rust/src/witness_builder.rs @@ -31,8 +31,11 @@ impl RedeemerWitnessKey { #[wasm_bindgen] #[derive(Clone)] pub struct RequiredWitnessSet { - vkeys: HashSet, - bootstraps: HashSet, + // note: the real key type for these is Vkey + // but cryptographically these should be equivalent and Ed25519KeyHash is more flexible + vkeys: HashSet, + bootstraps: HashSet, + native_scripts: HashSet, plutus_scripts: HashSet, plutus_data: HashSet, @@ -45,14 +48,20 @@ impl RequiredWitnessSet { self.add_vkey_key(&vkey.vkey()); } pub fn add_vkey_key(&mut self, vkey: &Vkey) { - self.vkeys.insert(vkey.clone()); + self.add_vkey_key_hash(&vkey.public_key().hash()); + } + pub fn add_vkey_key_hash(&mut self, hash: &Ed25519KeyHash) { + self.vkeys.insert(hash.clone()); } pub fn add_bootstrap(&mut self, bootstrap: &BootstrapWitness) { self.add_bootstrap_key(&bootstrap.vkey()); } pub fn add_bootstrap_key(&mut self, bootstrap: &Vkey) { - self.bootstraps.insert(bootstrap.clone()); + self.add_bootstrap_key_hash(&bootstrap.public_key().hash()); + } + pub fn add_bootstrap_key_hash(&mut self, hash: &Ed25519KeyHash) { + self.bootstraps.insert(hash.clone()); } pub fn add_native_script(&mut self, native_script: &NativeScript) { @@ -63,7 +72,6 @@ impl RequiredWitnessSet { } pub fn add_plutus_script(&mut self, plutus_script: &PlutusScript) { - // TODO: don't assume PlutusV1 and instead somehow calculate this self.add_plutus_hash(&plutus_script.hash(ScriptHashNamespace::PlutusV1)); } pub fn add_plutus_hash(&mut self, plutus_script: &ScriptHash) { @@ -156,7 +164,6 @@ impl TransactionWitnessSetBuilder { } pub fn add_plutus_script(&mut self, plutus_script: &PlutusScript) { - // TODO: don't assume PlutusV1 and instead somehow calculate this self.plutus_scripts.insert(plutus_script.hash(ScriptHashNamespace::PlutusV1), plutus_script.clone()); } @@ -220,11 +227,11 @@ impl TransactionWitnessSetBuilder { if self.vkeys.len() > 0 { result.set_vkeys(&Vkeywitnesses(self.vkeys.values().cloned().collect())); - self.vkeys.keys().for_each(|key| { remaining_wits.vkeys.remove(key); }); + self.vkeys.keys().for_each(|key| { remaining_wits.vkeys.remove(&key.public_key().hash()); }); } if self.bootstraps.len() > 0 { result.set_bootstraps(&BootstrapWitnesses(self.bootstraps.values().cloned().collect())); - self.bootstraps.keys().for_each(|key| { remaining_wits.bootstraps.remove(key); }); + self.bootstraps.keys().for_each(|key| { remaining_wits.bootstraps.remove(&key.public_key().hash()); }); } if self.native_scripts.len() > 0 { result.set_native_scripts(&NativeScripts(self.native_scripts.values().cloned().collect())); @@ -367,7 +374,7 @@ mod tests { // once we have mock data for them #[test] - fn requirement_test() { + fn requirement_test_fail() { let mut builder = TransactionWitnessSetBuilder::new(); let mut required_wits = RequiredWitnessSet::new(); @@ -383,7 +390,23 @@ mod tests { &fake_raw_key_sig(1) )); - assert!(builder.build().is_err() - ); + assert!(builder.build().is_err()); + } + + #[test] + fn requirement_test_pass() { + let mut builder = TransactionWitnessSetBuilder::new(); + + let mut required_wits = RequiredWitnessSet::new(); + required_wits.add_vkey_key(&Vkey::new(&fake_raw_key_public(0))); + builder.add_required_wits(&required_wits); + + // add a different element + builder.add_vkey(&Vkeywitness::new( + &Vkey::new(&fake_raw_key_public(0)), + &fake_raw_key_sig(0) + )); + + assert!(builder.build().is_ok()); } } \ No newline at end of file From ce411941e7099009ca6cd84d57b4ffe3e27f36b5 Mon Sep 17 00:00:00 2001 From: vantuz-subhuman Date: Sun, 6 Feb 2022 00:02:30 +0300 Subject: [PATCH 07/12] flowgen update and merge fixes --- rust/Cargo.lock | 2 - rust/pkg/cardano_serialization_lib.js.flow | 290 +++++++++++++++++---- rust/src/plutus.rs | 4 +- rust/src/witness_builder.rs | 7 +- 4 files changed, 241 insertions(+), 62 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 80bed476..3dc18532 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "aho-corasick" version = "0.7.15" diff --git a/rust/pkg/cardano_serialization_lib.js.flow b/rust/pkg/cardano_serialization_lib.js.flow index 13ea2a51..bbcf811f 100644 --- a/rust/pkg/cardano_serialization_lib.js.flow +++ b/rust/pkg/cardano_serialization_lib.js.flow @@ -5,42 +5,6 @@ * @flow */ -/** - * @param {Uint8Array} bytes - * @returns {TransactionMetadatum} - */ -declare export function encode_arbitrary_bytes_as_metadatum( - bytes: Uint8Array -): TransactionMetadatum; - -/** - * @param {TransactionMetadatum} metadata - * @returns {Uint8Array} - */ -declare export function decode_arbitrary_bytes_from_metadatum( - metadata: TransactionMetadatum -): Uint8Array; - -/** - * @param {string} json - * @param {number} schema - * @returns {TransactionMetadatum} - */ -declare export function encode_json_str_to_metadatum( - json: string, - schema: number -): TransactionMetadatum; - -/** - * @param {TransactionMetadatum} metadatum - * @param {number} schema - * @returns {string} - */ -declare export function decode_metadatum_to_json_str( - metadatum: TransactionMetadatum, - schema: number -): string; - /** * @param {TransactionHash} tx_body_hash * @param {ByronAddress} addr @@ -165,6 +129,42 @@ declare export function encode_json_str_to_native_script( schema: number ): NativeScript; +/** + * @param {Uint8Array} bytes + * @returns {TransactionMetadatum} + */ +declare export function encode_arbitrary_bytes_as_metadatum( + bytes: Uint8Array +): TransactionMetadatum; + +/** + * @param {TransactionMetadatum} metadata + * @returns {Uint8Array} + */ +declare export function decode_arbitrary_bytes_from_metadatum( + metadata: TransactionMetadatum +): Uint8Array; + +/** + * @param {string} json + * @param {number} schema + * @returns {TransactionMetadatum} + */ +declare export function encode_json_str_to_metadatum( + json: string, + schema: number +): TransactionMetadatum; + +/** + * @param {TransactionMetadatum} metadatum + * @param {number} schema + * @returns {string} + */ +declare export function decode_metadatum_to_json_str( + metadatum: TransactionMetadatum, + schema: number +): string; + /** * @param {string} password * @param {string} salt @@ -246,17 +246,6 @@ declare export var NativeScriptKind: {| +TimelockExpiry: 5, // 5 |}; -/** - * Each new language uses a different namespace for hashing its script - * This is because you could have a language where the same bytes have different semantics - * So this avoids scripts in different languages mapping to the same hash - * Note that the enum value here is different than the enum value for deciding the cost model of a script - */ - -declare export var ScriptHashNamespace: {| - +NativeScript: 0, // 0 -|}; - /** */ @@ -278,6 +267,7 @@ declare export var StakeCredKind: {| declare export var LanguageKind: {| +PlutusV1: 0, // 0 + +PlutusV2: 1, // 1 |}; /** @@ -301,6 +291,29 @@ declare export var RedeemerTagKind: {| +Reward: 3, // 3 |}; +/** + * Each new language uses a different namespace for hashing its script + * This is because you could have a language where the same bytes have different semantics + * So this avoids scripts in different languages mapping to the same hash + * Note that the enum value here is different than the enum value for deciding the cost model of a script + * https://github.com/input-output-hk/cardano-ledger/blob/9c3b4737b13b30f71529e76c5330f403165e28a6/eras/alonzo/impl/src/Cardano/Ledger/Alonzo.hs#L127 + */ + +declare export var ScriptHashNamespace: {| + +NativeScript: 0, // 0 + +PlutusV1: 1, // 1 + +PlutusV2: 2, // 2 +|}; + +/** + * Used to choose the schema for a script JSON string + */ + +declare export var ScriptSchema: {| + +Wallet: 0, // 0 + +Node: 1, // 1 +|}; + /** */ @@ -321,15 +334,6 @@ declare export var MetadataJsonSchema: {| +DetailedSchema: 2, // 2 |}; -/** - * Used to choosed the schema for a script JSON string - */ - -declare export var ScriptSchema: {| - +Wallet: 0, // 0 - +Node: 1, // 1 -|}; - /** */ @@ -2175,6 +2179,11 @@ declare export class Language { */ static new_plutus_v1(): Language; + /** + * @returns {Language} + */ + static new_plutus_v2(): Language; + /** * @returns {number} */ @@ -3145,6 +3154,12 @@ declare export class PlutusScript { */ static from_bytes(bytes: Uint8Array): PlutusScript; + /** + * @param {number} namespace + * @returns {ScriptHash} + */ + hash(namespace: number): ScriptHash; + /** * Creates a new Plutus script from the RAW bytes of the compiled script. * This does NOT include any CBOR encoding around these bytes (e.g. from "cborBytes" in cardano-cli) @@ -4071,6 +4086,28 @@ declare export class RedeemerTag { */ kind(): number; } +/** + */ +declare export class RedeemerWitnessKey { + free(): void; + + /** + * @returns {RedeemerTag} + */ + tag(): RedeemerTag; + + /** + * @returns {BigNum} + */ + index(): BigNum; + + /** + * @param {RedeemerTag} tag + * @param {BigNum} index + * @returns {RedeemerWitnessKey} + */ + static new(tag: RedeemerTag, index: BigNum): RedeemerWitnessKey; +} /** */ declare export class Redeemers { @@ -4199,6 +4236,91 @@ declare export class Relays { */ add(elem: Relay): void; } +/** + */ +declare export class RequiredWitnessSet { + free(): void; + + /** + * @param {Vkeywitness} vkey + */ + add_vkey(vkey: Vkeywitness): void; + + /** + * @param {Vkey} vkey + */ + add_vkey_key(vkey: Vkey): void; + + /** + * @param {Ed25519KeyHash} hash + */ + add_vkey_key_hash(hash: Ed25519KeyHash): void; + + /** + * @param {BootstrapWitness} bootstrap + */ + add_bootstrap(bootstrap: BootstrapWitness): void; + + /** + * @param {Vkey} bootstrap + */ + add_bootstrap_key(bootstrap: Vkey): void; + + /** + * @param {Ed25519KeyHash} hash + */ + add_bootstrap_key_hash(hash: Ed25519KeyHash): void; + + /** + * @param {NativeScript} native_script + */ + add_native_script(native_script: NativeScript): void; + + /** + * @param {ScriptHash} native_script + */ + add_native_script_hash(native_script: ScriptHash): void; + + /** + * @param {PlutusScript} plutus_script + */ + add_plutus_script(plutus_script: PlutusScript): void; + + /** + * @param {ScriptHash} plutus_script + */ + add_plutus_hash(plutus_script: ScriptHash): void; + + /** + * @param {PlutusData} plutus_datum + */ + add_plutus_datum(plutus_datum: PlutusData): void; + + /** + * @param {DataHash} plutus_datum + */ + add_plutus_datum_hash(plutus_datum: DataHash): void; + + /** + * @param {Redeemer} redeemer + */ + add_redeemer(redeemer: Redeemer): void; + + /** + * @param {RedeemerWitnessKey} redeemer + */ + add_redeemer_tag(redeemer: RedeemerWitnessKey): void; + + /** + * @param {RequiredWitnessSet} requirements + */ + add_all(requirements: RequiredWitnessSet): void; + + /** + * @returns {RequiredWitnessSet} + */ + static new(): RequiredWitnessSet; +} /** */ declare export class RewardAddress { @@ -5933,6 +6055,62 @@ declare export class TransactionWitnessSet { */ static new(): TransactionWitnessSet; } +/** + * Builder de-duplicates witnesses as they are added + */ +declare export class TransactionWitnessSetBuilder { + free(): void; + + /** + * @param {Vkeywitness} vkey + */ + add_vkey(vkey: Vkeywitness): void; + + /** + * @param {BootstrapWitness} bootstrap + */ + add_bootstrap(bootstrap: BootstrapWitness): void; + + /** + * @param {NativeScript} native_script + */ + add_native_script(native_script: NativeScript): void; + + /** + * @param {PlutusScript} plutus_script + */ + add_plutus_script(plutus_script: PlutusScript): void; + + /** + * @param {PlutusData} plutus_datum + */ + add_plutus_datum(plutus_datum: PlutusData): void; + + /** + * @param {Redeemer} redeemer + */ + add_redeemer(redeemer: Redeemer): void; + + /** + * @param {RequiredWitnessSet} required_wits + */ + add_required_wits(required_wits: RequiredWitnessSet): void; + + /** + * @returns {TransactionWitnessSetBuilder} + */ + static new(): TransactionWitnessSetBuilder; + + /** + * @param {TransactionWitnessSet} wit_set + */ + add_existing(wit_set: TransactionWitnessSet): void; + + /** + * @returns {TransactionWitnessSet} + */ + build(): TransactionWitnessSet; +} /** */ declare export class TransactionWitnessSets { diff --git a/rust/src/plutus.rs b/rust/src/plutus.rs index 3a5afc5e..2c5f2b1c 100644 --- a/rust/src/plutus.rs +++ b/rust/src/plutus.rs @@ -466,11 +466,11 @@ impl PlutusData { #[wasm_bindgen] #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct PlutusList { - elems: Vec, + pub(crate) elems: Vec, // We should always preserve the original datums when deserialized as this is NOT canonicized // before computing datum hashes. This field will default to cardano-cli behavior if None // and will re-use the provided one if deserialized, unless the list is modified. - definite_encoding: Option, + pub(crate) definite_encoding: Option, } to_from_bytes!(PlutusList); diff --git a/rust/src/witness_builder.rs b/rust/src/witness_builder.rs index 625ba98c..08fee1cf 100644 --- a/rust/src/witness_builder.rs +++ b/rust/src/witness_builder.rs @@ -213,7 +213,7 @@ impl TransactionWitnessSetBuilder { }; match &wit_set.plutus_data() { None => (), - Some(plutus_data) => plutus_data.0.iter().for_each(|plutus_datum| { self.add_plutus_datum(plutus_datum); } ), + Some(plutus_data) => plutus_data.elems.iter().for_each(|plutus_datum| { self.add_plutus_datum(plutus_datum); } ), }; match &wit_set.redeemers() { None => (), @@ -242,7 +242,10 @@ impl TransactionWitnessSetBuilder { self.plutus_scripts.keys().for_each(|hash| { remaining_wits.plutus_scripts.remove(hash); }); } if self.plutus_data.len() > 0 { - result.set_plutus_data(&PlutusList(self.plutus_data.values().cloned().collect())); + result.set_plutus_data(&PlutusList { + elems: self.plutus_data.values().cloned().collect(), + definite_encoding: None, + }); self.plutus_data.keys().for_each(|hash| { remaining_wits.plutus_data.remove(hash); }); } if self.redeemers.len() > 0 { From 1c6beaa9e920432283b4120896c07ddc9722233c Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Mon, 7 Feb 2022 15:14:44 +0900 Subject: [PATCH 08/12] Expand on comment --- rust/src/witness_builder.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust/src/witness_builder.rs b/rust/src/witness_builder.rs index 08fee1cf..a65ece50 100644 --- a/rust/src/witness_builder.rs +++ b/rust/src/witness_builder.rs @@ -145,7 +145,9 @@ pub struct TransactionWitnessSetBuilder { plutus_data: HashMap, redeemers: HashMap, - // witnesses that need to be added for the build function to succeed + /// witnesses that need to be added for the build function to succeed + /// this allows checking that witnesses are present at build time (instead of when submitting to a node) + /// This is useful for APIs that can keep track of which witnesses will be required (like transaction builders) required_wits: RequiredWitnessSet, } From 9d70565df4e8b5b66e7c5482a450d351c5a12b52 Mon Sep 17 00:00:00 2001 From: vantuz-subhuman Date: Sat, 9 Jul 2022 22:23:33 +0300 Subject: [PATCH 09/12] Removed duplicate conflicting definition --- rust/src/plutus.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rust/src/plutus.rs b/rust/src/plutus.rs index f0763ae7..1b585151 100644 --- a/rust/src/plutus.rs +++ b/rust/src/plutus.rs @@ -15,10 +15,6 @@ to_from_bytes!(PlutusScript); #[wasm_bindgen] impl PlutusScript { - pub fn hash(&self, namespace: ScriptHashNamespace) -> ScriptHash { - hash_script(namespace, self.to_bytes()) - } - /** * Creates a new Plutus script from the RAW bytes of the compiled script. * This does NOT include any CBOR encoding around these bytes (e.g. from "cborBytes" in cardano-cli) From 5826c3efc22da4449b30e7addf5bcc168723f37a Mon Sep 17 00:00:00 2001 From: vantuz-subhuman Date: Sat, 9 Jul 2022 22:38:17 +0300 Subject: [PATCH 10/12] resolving merge issues --- rust/src/utils.rs | 28 +++++++--------------------- rust/src/witness_builder.rs | 8 ++++---- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/rust/src/utils.rs b/rust/src/utils.rs index 4b4d34db..7d5ce625 100644 --- a/rust/src/utils.rs +++ b/rust/src/utils.rs @@ -1085,16 +1085,15 @@ pub struct MinOutputAdaCalculator { } impl MinOutputAdaCalculator { - pub fn new(output: &TransactionOutput, data_cost: &DataCost) -> Self { - Self{ + Self { output: output.clone(), data_cost: data_cost.clone() } } pub fn new_empty(data_cost: &DataCost) -> Result { - Ok(Self{ + Ok(Self { output: MinOutputAdaCalculator::create_fake_output()?, data_cost: data_cost.clone() }) @@ -1142,17 +1141,11 @@ impl MinOutputAdaCalculator { Ok(calc_required_coin(&output, &coins_per_byte)?) } -/// Each new language uses a different namespace for hashing its script -/// This is because you could have a language where the same bytes have different semantics -/// So this avoids scripts in different languages mapping to the same hash -/// Note that the enum value here is different than the enum value for deciding the cost model of a script -/// https://github.com/input-output-hk/cardano-ledger/blob/9c3b4737b13b30f71529e76c5330f403165e28a6/eras/alonzo/impl/src/Cardano/Ledger/Alonzo.hs#L127 -#[wasm_bindgen] -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub enum ScriptHashNamespace { - NativeScript, - PlutusV1, - PlutusV2 + fn create_fake_output() -> Result { + let fake_base_address: Address = Address::from_bech32("addr_test1qpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5ewvxwdrt70qlcpeeagscasafhffqsxy36t90ldv06wqrk2qum8x5w")?; + let fake_value: Value = Value::new(&to_bignum(1000000)); + Ok(TransactionOutput::new(&fake_base_address, &fake_value)) + } } pub (crate) fn hash_script(namespace: ScriptHashNamespace, script: Vec) -> ScriptHash { @@ -1162,13 +1155,6 @@ pub (crate) fn hash_script(namespace: ScriptHashNamespace, script: Vec) -> S ScriptHash::from(blake2b224(bytes.as_ref())) } - fn create_fake_output() -> Result { - let fake_base_address: Address = Address::from_bech32("addr_test1qpu5vlrf4xkxv2qpwngf6cjhtw542ayty80v8dyr49rf5ewvxwdrt70qlcpeeagscasafhffqsxy36t90ldv06wqrk2qum8x5w")?; - let fake_value: Value = Value::new(&to_bignum(1000000)); - Ok(TransactionOutput::new(&fake_base_address, &fake_value)) - } -} - ///returns minimal amount of ada for the output for case when the amount is included to the output #[wasm_bindgen] pub fn min_ada_for_output(output: &TransactionOutput, data_cost: &DataCost) -> Result { diff --git a/rust/src/witness_builder.rs b/rust/src/witness_builder.rs index a65ece50..e2bbe6b6 100644 --- a/rust/src/witness_builder.rs +++ b/rust/src/witness_builder.rs @@ -65,14 +65,14 @@ impl RequiredWitnessSet { } pub fn add_native_script(&mut self, native_script: &NativeScript) { - self.add_native_script_hash(&native_script.hash(ScriptHashNamespace::NativeScript)); + self.add_native_script_hash(&native_script.hash()); } pub fn add_native_script_hash(&mut self, native_script: &ScriptHash) { self.native_scripts.insert(native_script.clone()); } pub fn add_plutus_script(&mut self, plutus_script: &PlutusScript) { - self.add_plutus_hash(&plutus_script.hash(ScriptHashNamespace::PlutusV1)); + self.add_plutus_hash(&plutus_script.hash()); } pub fn add_plutus_hash(&mut self, plutus_script: &ScriptHash) { self.plutus_scripts.insert(plutus_script.clone()); @@ -162,11 +162,11 @@ impl TransactionWitnessSetBuilder { } pub fn add_native_script(&mut self, native_script: &NativeScript) { - self.native_scripts.insert(native_script.hash(ScriptHashNamespace::NativeScript), native_script.clone()); + self.native_scripts.insert(native_script.hash(), native_script.clone()); } pub fn add_plutus_script(&mut self, plutus_script: &PlutusScript) { - self.plutus_scripts.insert(plutus_script.hash(ScriptHashNamespace::PlutusV1), plutus_script.clone()); + self.plutus_scripts.insert(plutus_script.hash(), plutus_script.clone()); } pub fn add_plutus_datum(&mut self, plutus_datum: &PlutusData) { From cf6e00196ae30dcda7d2d54e84ee013c3fdfa260 Mon Sep 17 00:00:00 2001 From: vantuz-subhuman Date: Sat, 9 Jul 2022 22:43:16 +0300 Subject: [PATCH 11/12] flowjs update --- rust/pkg/cardano_serialization_lib.js.flow | 235 +++++++++++++++++---- 1 file changed, 199 insertions(+), 36 deletions(-) diff --git a/rust/pkg/cardano_serialization_lib.js.flow b/rust/pkg/cardano_serialization_lib.js.flow index ca6e0bd6..a942c0ed 100644 --- a/rust/pkg/cardano_serialization_lib.js.flow +++ b/rust/pkg/cardano_serialization_lib.js.flow @@ -302,79 +302,79 @@ declare export var NetworkIdKind: {| |}; /** - * Used to choosed the schema for a script JSON string */ -declare export var ScriptSchema: {| - +Wallet: 0, // 0 - +Node: 1, // 1 +declare export var LanguageKind: {| + +PlutusV1: 0, // 0 + +PlutusV2: 1, // 1 |}; /** */ -declare export var TransactionMetadatumKind: {| - +MetadataMap: 0, // 0 - +MetadataList: 1, // 1 - +Int: 2, // 2 - +Bytes: 3, // 3 - +Text: 4, // 4 +declare export var PlutusDataKind: {| + +ConstrPlutusData: 0, // 0 + +Map: 1, // 1 + +List: 2, // 2 + +Integer: 3, // 3 + +Bytes: 4, // 4 |}; /** */ -declare export var MetadataJsonSchema: {| - +NoConversions: 0, // 0 - +BasicConversions: 1, // 1 - +DetailedSchema: 2, // 2 +declare export var RedeemerTagKind: {| + +Spend: 0, // 0 + +Mint: 1, // 1 + +Cert: 2, // 2 + +Reward: 3, // 3 |}; /** */ -declare export var CoinSelectionStrategyCIP2: {| - +LargestFirst: 0, // 0 - +RandomImprove: 1, // 1 - +LargestFirstMultiAsset: 2, // 2 - +RandomImproveMultiAsset: 3, // 3 +declare export var StakeCredKind: {| + +Key: 0, // 0 + +Script: 1, // 1 |}; /** + * Used to choose the schema for a script JSON string */ -declare export var LanguageKind: {| - +PlutusV1: 0, // 0 - +PlutusV2: 1, // 1 +declare export var ScriptSchema: {| + +Wallet: 0, // 0 + +Node: 1, // 1 |}; /** */ -declare export var PlutusDataKind: {| - +ConstrPlutusData: 0, // 0 - +Map: 1, // 1 - +List: 2, // 2 - +Integer: 3, // 3 - +Bytes: 4, // 4 +declare export var TransactionMetadatumKind: {| + +MetadataMap: 0, // 0 + +MetadataList: 1, // 1 + +Int: 2, // 2 + +Bytes: 3, // 3 + +Text: 4, // 4 |}; /** */ -declare export var RedeemerTagKind: {| - +Spend: 0, // 0 - +Mint: 1, // 1 - +Cert: 2, // 2 - +Reward: 3, // 3 +declare export var MetadataJsonSchema: {| + +NoConversions: 0, // 0 + +BasicConversions: 1, // 1 + +DetailedSchema: 2, // 2 |}; /** */ -declare export var StakeCredKind: {| - +Key: 0, // 0 - +Script: 1, // 1 +declare export var CoinSelectionStrategyCIP2: {| + +LargestFirst: 0, // 0 + +RandomImprove: 1, // 1 + +LargestFirstMultiAsset: 2, // 2 + +RandomImproveMultiAsset: 3, // 3 |}; /** @@ -4376,6 +4376,28 @@ declare export class RedeemerTag { */ kind(): number; } +/** + */ +declare export class RedeemerWitnessKey { + free(): void; + + /** + * @returns {RedeemerTag} + */ + tag(): RedeemerTag; + + /** + * @returns {BigNum} + */ + index(): BigNum; + + /** + * @param {RedeemerTag} tag + * @param {BigNum} index + * @returns {RedeemerWitnessKey} + */ + static new(tag: RedeemerTag, index: BigNum): RedeemerWitnessKey; +} /** */ declare export class Redeemers { @@ -4509,6 +4531,91 @@ declare export class Relays { */ add(elem: Relay): void; } +/** + */ +declare export class RequiredWitnessSet { + free(): void; + + /** + * @param {Vkeywitness} vkey + */ + add_vkey(vkey: Vkeywitness): void; + + /** + * @param {Vkey} vkey + */ + add_vkey_key(vkey: Vkey): void; + + /** + * @param {Ed25519KeyHash} hash + */ + add_vkey_key_hash(hash: Ed25519KeyHash): void; + + /** + * @param {BootstrapWitness} bootstrap + */ + add_bootstrap(bootstrap: BootstrapWitness): void; + + /** + * @param {Vkey} bootstrap + */ + add_bootstrap_key(bootstrap: Vkey): void; + + /** + * @param {Ed25519KeyHash} hash + */ + add_bootstrap_key_hash(hash: Ed25519KeyHash): void; + + /** + * @param {NativeScript} native_script + */ + add_native_script(native_script: NativeScript): void; + + /** + * @param {ScriptHash} native_script + */ + add_native_script_hash(native_script: ScriptHash): void; + + /** + * @param {PlutusScript} plutus_script + */ + add_plutus_script(plutus_script: PlutusScript): void; + + /** + * @param {ScriptHash} plutus_script + */ + add_plutus_hash(plutus_script: ScriptHash): void; + + /** + * @param {PlutusData} plutus_datum + */ + add_plutus_datum(plutus_datum: PlutusData): void; + + /** + * @param {DataHash} plutus_datum + */ + add_plutus_datum_hash(plutus_datum: DataHash): void; + + /** + * @param {Redeemer} redeemer + */ + add_redeemer(redeemer: Redeemer): void; + + /** + * @param {RedeemerWitnessKey} redeemer + */ + add_redeemer_tag(redeemer: RedeemerWitnessKey): void; + + /** + * @param {RequiredWitnessSet} requirements + */ + add_all(requirements: RequiredWitnessSet): void; + + /** + * @returns {RequiredWitnessSet} + */ + static new(): RequiredWitnessSet; +} /** */ declare export class RewardAddress { @@ -6671,6 +6778,62 @@ declare export class TransactionWitnessSet { */ static new(): TransactionWitnessSet; } +/** + * Builder de-duplicates witnesses as they are added + */ +declare export class TransactionWitnessSetBuilder { + free(): void; + + /** + * @param {Vkeywitness} vkey + */ + add_vkey(vkey: Vkeywitness): void; + + /** + * @param {BootstrapWitness} bootstrap + */ + add_bootstrap(bootstrap: BootstrapWitness): void; + + /** + * @param {NativeScript} native_script + */ + add_native_script(native_script: NativeScript): void; + + /** + * @param {PlutusScript} plutus_script + */ + add_plutus_script(plutus_script: PlutusScript): void; + + /** + * @param {PlutusData} plutus_datum + */ + add_plutus_datum(plutus_datum: PlutusData): void; + + /** + * @param {Redeemer} redeemer + */ + add_redeemer(redeemer: Redeemer): void; + + /** + * @param {RequiredWitnessSet} required_wits + */ + add_required_wits(required_wits: RequiredWitnessSet): void; + + /** + * @returns {TransactionWitnessSetBuilder} + */ + static new(): TransactionWitnessSetBuilder; + + /** + * @param {TransactionWitnessSet} wit_set + */ + add_existing(wit_set: TransactionWitnessSet): void; + + /** + * @returns {TransactionWitnessSet} + */ + build(): TransactionWitnessSet; +} /** */ declare export class TransactionWitnessSets { From a2739f8604bd16062c2e3360e761f71e42eae93a Mon Sep 17 00:00:00 2001 From: vantuz-subhuman Date: Sat, 9 Jul 2022 22:50:01 +0300 Subject: [PATCH 12/12] Fixed usage of the introduced `hash_script` function --- rust/src/lib.rs | 7 +------ rust/src/plutus.rs | 5 +---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index b1d8b5df..56c6909d 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1960,12 +1960,7 @@ pub enum ScriptHashNamespace { impl NativeScript { pub fn hash(&self) -> ScriptHash { - let mut bytes = Vec::with_capacity(self.to_bytes().len() + 1); - bytes.extend_from_slice(&vec![ - ScriptHashNamespace::NativeScript as u8, - ]); - bytes.extend_from_slice(&self.to_bytes()); - ScriptHash::from(blake2b224(bytes.as_ref())) + hash_script(ScriptHashNamespace::NativeScript, self.to_bytes()) } pub fn new_script_pubkey(script_pubkey: &ScriptPubkey) -> Self { diff --git a/rust/src/plutus.rs b/rust/src/plutus.rs index f436ca1e..662e64c4 100644 --- a/rust/src/plutus.rs +++ b/rust/src/plutus.rs @@ -64,11 +64,8 @@ impl PlutusScript { } pub fn hash(&self) -> ScriptHash { - let mut bytes = Vec::with_capacity(self.bytes.len() + 1); // https://github.com/input-output-hk/cardano-ledger/blob/master/eras/babbage/test-suite/cddl-files/babbage.cddl#L413 - bytes.extend_from_slice(&vec![self.script_namespace() as u8]); - bytes.extend_from_slice(&self.bytes); - ScriptHash::from(blake2b224(bytes.as_ref())) + hash_script(self.script_namespace(), self.bytes()) } pub fn language_version(&self) -> Language {