1use linked_hash_map::LinkedHashMap;
2use std::{
3 collections::{BTreeSet, HashMap},
4 fmt::Debug,
5};
6
7use crate::{
8 byron::ByronAddress,
9 certs::Credential,
10 crypto::{hash::hash_plutus_data, BootstrapWitness, Vkey, Vkeywitness},
11 plutus::{
12 LegacyRedeemer, PlutusData, PlutusScript, PlutusV1Script, PlutusV2Script, PlutusV3Script,
13 Redeemers,
14 },
15 transaction::TransactionWitnessSet,
16 NativeScript, RequiredSigners, Script,
17};
18use cml_crypto::{
19 DatumHash, Ed25519KeyHash, Ed25519Signature, PublicKey, RawBytesEncoding, ScriptHash,
20};
21
22use super::{
23 redeemer_builder::{MissingExunitError, RedeemerBuilderError, RedeemerWitnessKey},
24 tx_builder::TransactionUnspentOutput,
25};
26
27#[derive(Debug, thiserror::Error)]
28pub enum WitnessBuilderError {
29 #[error("Missing the following witnesses: {0:?}")]
30 MissingWitnesses(RequiredWitnessSet),
31 #[error("Missing ExUnit: {0}")]
32 MissingExUnit(#[from] MissingExunitError),
33 #[error("LegacyRedeemer build failed: {0}")]
34 RedeemBuildFailed(#[from] RedeemerBuilderError),
35}
36
37#[derive(Debug, Clone)] pub enum PlutusScriptWitness {
39 Ref(ScriptHash),
40 Script(PlutusScript),
41}
42
43impl PlutusScriptWitness {
44 pub fn hash(&self) -> ScriptHash {
52 match self {
53 Self::Ref(hash) => *hash,
54 Self::Script(script) => script.hash(),
55 }
56 }
57}
58
59impl From<PlutusScript> for PlutusScriptWitness {
60 fn from(script: PlutusScript) -> Self {
61 PlutusScriptWitness::Script(script)
62 }
63}
64
65impl From<ScriptHash> for PlutusScriptWitness {
66 fn from(hash: ScriptHash) -> Self {
67 PlutusScriptWitness::Ref(hash)
68 }
69}
70
71#[derive(Clone, Debug)]
76pub struct PartialPlutusWitness {
77 pub script: PlutusScriptWitness,
78 pub redeemer: PlutusData,
79}
80
81impl PartialPlutusWitness {
82 pub fn new(script: PlutusScriptWitness, redeemer: PlutusData) -> Self {
83 Self { script, redeemer }
84 }
85}
86
87#[derive(Clone, Debug)]
88pub enum InputAggregateWitnessData {
89 NativeScript(NativeScript, NativeScriptWitnessInfo),
90 PlutusScript(PartialPlutusWitness, RequiredSigners, Option<PlutusData>),
91}
92
93impl InputAggregateWitnessData {
94 pub fn redeemer_plutus_data(&self) -> Option<&PlutusData> {
95 match self {
96 InputAggregateWitnessData::PlutusScript(witness, _, _) => Some(&witness.redeemer),
97 _ => None,
98 }
99 }
100}
101
102#[derive(Clone, Debug, Default)]
103pub struct RequiredWitnessSet {
104 pub vkeys: BTreeSet<Ed25519KeyHash>,
107 pub bootstraps: BTreeSet<ByronAddress>,
111 pub scripts: BTreeSet<ScriptHash>,
113 pub plutus_data: BTreeSet<DatumHash>,
114 pub redeemers: BTreeSet<RedeemerWitnessKey>,
115 pub script_refs: BTreeSet<ScriptHash>,
116}
117
118impl RequiredWitnessSet {
119 pub fn add_vkey_key_hash(&mut self, hash: Ed25519KeyHash) {
126 self.vkeys.insert(hash);
127 }
128
129 pub fn add_bootstrap(&mut self, address: ByronAddress) {
130 self.bootstraps.insert(address);
131 }
132
133 pub fn add_script_ref(&mut self, script_hash: ScriptHash) {
134 self.scripts.remove(&script_hash);
135 self.script_refs.insert(script_hash);
136 }
137
138 pub fn add_script_hash(&mut self, script_hash: ScriptHash) {
143 match self.script_refs.get(&script_hash) {
144 None => {
145 self.scripts.insert(script_hash);
146 }
147 Some(_) => {}
148 }
149 }
150
151 pub(crate) fn add_from_credential(&mut self, credential: Credential) {
152 match credential {
153 Credential::PubKey { hash, .. } => self.add_vkey_key_hash(hash),
154 Credential::Script { hash, .. } => self.add_script_hash(hash),
155 }
156 }
157
158 pub fn add_plutus_datum_hash(&mut self, plutus_datum: DatumHash) {
166 self.plutus_data.insert(plutus_datum);
167 }
168
169 pub fn add_redeemer_tag(&mut self, redeemer: RedeemerWitnessKey) {
173 self.redeemers.insert(redeemer);
174 }
175
176 pub fn add_all(&mut self, requirements: RequiredWitnessSet) {
177 self.vkeys.extend(requirements.vkeys);
178 self.bootstraps.extend(requirements.bootstraps);
179 self.scripts.extend(requirements.scripts);
180 self.plutus_data.extend(requirements.plutus_data);
181 self.redeemers.extend(requirements.redeemers);
182 }
183
184 pub fn remove_ref_scripts(&mut self, ref_inputs: &[TransactionUnspentOutput]) {
185 ref_inputs.iter().for_each(|utxo| {
186 utxo.output.script_ref().inspect(|script_ref| {
187 self.scripts.remove(&script_ref.hash());
188 });
189 })
190 }
191
192 pub(crate) fn len(&self) -> usize {
193 self.vkeys.len()
194 + self.bootstraps.len()
195 + self.scripts.len()
196 + self.plutus_data.len()
197 + self.redeemers.len()
198 }
199
200 pub(crate) fn add_fake_vkey_witnesses_by_num(&mut self, num: usize) {
206 for _ in 0..num {
207 self.add_vkey_key_hash(fake_key_hash(self.vkeys.len() as u8));
208 }
209 }
210
211 pub(crate) fn add_input_aggregate_fake_witness_data(
212 &mut self,
213 data: &InputAggregateWitnessData,
214 ) {
215 match data {
216 InputAggregateWitnessData::NativeScript(script, info) => {
217 match info {
218 NativeScriptWitnessInfo::Count(num) => {
219 self.add_fake_vkey_witnesses_by_num(*num)
220 }
221 NativeScriptWitnessInfo::Vkeys(ref vkeys) => {
222 vkeys
223 .iter()
224 .cloned()
225 .for_each(|vkey| self.add_vkey_key_hash(vkey));
226 }
227 NativeScriptWitnessInfo::AssumeWorst => {
228 let num = script.get_required_signers().len();
231 self.add_fake_vkey_witnesses_by_num(num);
232 }
233 }
234 }
235 InputAggregateWitnessData::PlutusScript(_witness, required_signers, _option) => {
236 required_signers
237 .iter()
238 .cloned()
239 .for_each(|vkey| self.add_vkey_key_hash(vkey));
240 }
241 }
242 }
243
244 pub fn new() -> Self {
245 Self::default()
247 }
248}
249
250#[derive(Clone, Default, Debug)]
252pub struct TransactionWitnessSetBuilder {
253 pub vkeys: HashMap<Vkey, Vkeywitness>,
255 pub bootstraps: HashMap<Vkey, BootstrapWitness>,
256 pub scripts: HashMap<ScriptHash, Script>,
257 pub plutus_data: LinkedHashMap<DatumHash, PlutusData>,
258 pub redeemers: LinkedHashMap<RedeemerWitnessKey, LegacyRedeemer>,
259
260 pub required_wits: RequiredWitnessSet,
264}
265
266impl TransactionWitnessSetBuilder {
267 pub fn add_vkey(&mut self, vkey_witness: Vkeywitness) {
272 let vkey = vkey_witness.vkey.clone();
273 self.vkeys.insert(vkey, vkey_witness);
274 }
275
276 pub fn add_bootstrap(&mut self, bootstrap: BootstrapWitness) {
277 self.bootstraps
278 .insert(bootstrap.public_key.clone(), bootstrap);
279 }
280
281 pub fn add_script(&mut self, script: Script) {
286 self.scripts.insert(script.hash(), script);
287 }
288
289 pub fn get_native_script(&self) -> Vec<NativeScript> {
290 self.scripts
291 .iter()
292 .filter(|entry| !self.required_wits.script_refs.contains(entry.0))
293 .fold(
294 Vec::<NativeScript>::new(),
295 |mut acc, script| match &script.1 {
296 Script::Native { script, .. } => {
297 acc.push(script.clone());
298 acc
299 }
300 _ => acc,
301 },
302 )
303 }
304
305 pub fn get_plutus_v1_script(&self) -> Vec<PlutusV1Script> {
306 self.scripts
307 .iter()
308 .filter(|entry| !self.required_wits.script_refs.contains(entry.0))
309 .fold(
310 Vec::<PlutusV1Script>::new(),
311 |mut acc, script| match &script.1 {
312 Script::PlutusV1 { script, .. } => {
313 acc.push(script.clone());
314 acc
315 }
316 _ => acc,
317 },
318 )
319 }
320
321 pub fn get_plutus_v2_script(&self) -> Vec<PlutusV2Script> {
322 self.scripts
323 .iter()
324 .filter(|entry| !self.required_wits.script_refs.contains(entry.0))
325 .fold(
326 Vec::<PlutusV2Script>::new(),
327 |mut acc, script| match &script.1 {
328 &Script::PlutusV2 { script, .. } => {
329 acc.push(script.clone());
330 acc
331 }
332 _ => acc,
333 },
334 )
335 }
336
337 pub fn get_plutus_v3_script(&self) -> Vec<PlutusV3Script> {
338 self.scripts
339 .iter()
340 .filter(|entry| !self.required_wits.script_refs.contains(entry.0))
341 .fold(
342 Vec::<PlutusV3Script>::new(),
343 |mut acc, script| match &script.1 {
344 &Script::PlutusV3 { script, .. } => {
345 acc.push(script.clone());
346 acc
347 }
348 _ => acc,
349 },
350 )
351 }
352
353 pub fn add_plutus_datum(&mut self, plutus_datum: PlutusData) {
354 self.plutus_data
355 .insert(hash_plutus_data(&plutus_datum), plutus_datum);
356 }
357
358 pub fn get_plutus_datum(&self) -> Vec<PlutusData> {
359 self.plutus_data.values().cloned().collect()
360 }
361
362 pub fn add_redeemer(&mut self, redeemer: LegacyRedeemer) {
363 self.redeemers
364 .insert(RedeemerWitnessKey::from(&redeemer), redeemer);
365 }
366
367 pub fn get_redeemer(&self) -> Vec<LegacyRedeemer> {
368 self.redeemers.values().cloned().collect()
369 }
370
371 pub fn add_required_wits(&mut self, required_wits: RequiredWitnessSet) {
372 self.required_wits.add_all(required_wits)
373 }
374
375 pub fn new() -> Self {
376 Self::default()
378 }
379
380 pub fn add_existing(&mut self, wit_set: TransactionWitnessSet) {
381 if let Some(vkeys) = wit_set.vkeywitnesses {
382 vkeys.iter().for_each(|vkey| {
383 self.add_vkey(vkey.clone());
384 });
385 }
386 if let Some(bootstraps) = wit_set.bootstrap_witnesses {
387 bootstraps.iter().for_each(|bootstrap| {
388 self.add_bootstrap(bootstrap.clone());
389 });
390 }
391 if let Some(native_scripts) = wit_set.native_scripts {
392 native_scripts.iter().for_each(|native_script| {
393 self.add_script(native_script.clone().into());
394 });
395 }
396 if let Some(plutus_scripts) = wit_set.plutus_v1_scripts {
397 plutus_scripts.iter().for_each(|plutus_script| {
398 self.add_script(plutus_script.clone().into());
399 });
400 }
401 if let Some(plutus_scripts) = wit_set.plutus_v2_scripts {
402 plutus_scripts.iter().for_each(|plutus_script| {
403 self.add_script(plutus_script.clone().into());
404 });
405 }
406 if let Some(plutus_scripts) = wit_set.plutus_v3_scripts {
407 plutus_scripts.iter().for_each(|plutus_script| {
408 self.add_script(plutus_script.clone().into());
409 });
410 }
411 if let Some(redeemers) = wit_set.redeemers {
412 redeemers.to_flat_format().into_iter().for_each(|redeemer| {
413 self.add_redeemer(redeemer);
414 });
415 }
416 if let Some(plutus_datums) = wit_set.plutus_datums {
417 plutus_datums.iter().for_each(|plutus_datum| {
418 self.add_plutus_datum(plutus_datum.clone());
419 });
420 }
421 }
422
423 pub(crate) fn add_input_aggregate_real_witness_data(
424 &mut self,
425 data: &InputAggregateWitnessData,
426 ) {
427 match data {
428 InputAggregateWitnessData::NativeScript(script, _info) => {
429 self.add_script(script.clone().into());
430 }
431 InputAggregateWitnessData::PlutusScript(witness, _info, option) => {
432 match &witness.script {
433 PlutusScriptWitness::Script(plutus_script) => {
434 self.add_script(plutus_script.clone().into());
435 }
436 PlutusScriptWitness::Ref(_) => {
437 }
439 }
440 if let Some(data) = option {
441 self.add_plutus_datum(data.clone());
442 }
443 }
444 }
445 }
446
447 pub fn build(self) -> TransactionWitnessSet {
448 let mut result = TransactionWitnessSet::new();
449 let native_scripts = self.get_native_script();
450 let plutus_v1_scripts = self.get_plutus_v1_script();
451 let plutus_v2_scripts = self.get_plutus_v2_script();
452 let plutus_v3_scripts = self.get_plutus_v3_script();
453 let plutus_datums = self.get_plutus_datum();
454
455 if !self.vkeys.is_empty() {
456 result.vkeywitnesses = Some(self.vkeys.into_values().collect::<Vec<_>>().into());
457 }
458
459 if !self.bootstraps.is_empty() {
460 result.bootstrap_witnesses =
461 Some(self.bootstraps.into_values().collect::<Vec<_>>().into());
462 }
463
464 if !native_scripts.is_empty() {
465 result.native_scripts = Some(native_scripts.into());
466 }
467
468 if !plutus_v1_scripts.is_empty() {
469 result.plutus_v1_scripts = Some(plutus_v1_scripts.into());
470 }
471
472 if !plutus_v2_scripts.is_empty() {
473 result.plutus_v2_scripts = Some(plutus_v2_scripts.into());
474 }
475
476 if !plutus_v3_scripts.is_empty() {
477 result.plutus_v3_scripts = Some(plutus_v3_scripts.into());
478 }
479
480 if !self.plutus_data.is_empty() {
481 result.plutus_datums = Some(plutus_datums.into());
482 }
483
484 if !self.redeemers.is_empty() {
485 result.redeemers = Some(Redeemers::new_arr_legacy_redeemer(
486 self.redeemers.values().cloned().collect::<Vec<_>>(),
487 ));
488 }
489
490 result
491 }
492
493 pub fn remaining_wits(&self) -> RequiredWitnessSet {
494 let mut remaining_wits = self.required_wits.clone();
495
496 self.vkeys.keys().for_each(|key| {
497 remaining_wits.vkeys.remove(&key.hash());
498 });
499 self.bootstraps.values().for_each(|wit| {
500 remaining_wits
501 .bootstraps
502 .remove(&wit.to_address().unwrap().to_address());
503 });
504 self.scripts.keys().for_each(|hash| {
505 remaining_wits.scripts.remove(hash);
506 });
507 self.plutus_data.keys().for_each(|hash| {
508 remaining_wits.plutus_data.remove(hash);
509 });
510 self.redeemers.keys().for_each(|key| {
511 remaining_wits.redeemers.remove(key);
512 });
513
514 remaining_wits
515 }
516
517 pub fn try_build(&self) -> Result<TransactionWitnessSet, WitnessBuilderError> {
518 let remaining_wits = self.remaining_wits();
519
520 if remaining_wits.len() > 0 {
521 return Err(WitnessBuilderError::MissingWitnesses(remaining_wits));
522 }
523
524 Ok(self.clone().build())
525 }
526}
527
528pub fn merge_fake_witness(
529 builder: &mut TransactionWitnessSetBuilder,
530 required_wits: &RequiredWitnessSet,
531) {
532 let mut remaining_wits = required_wits.clone();
533 builder.vkeys.keys().for_each(|key| {
534 remaining_wits.vkeys.remove(&key.hash());
535 });
536 builder.bootstraps.values().for_each(|wit| {
537 remaining_wits
538 .bootstraps
539 .remove(&wit.to_address().unwrap().to_address());
540 });
541
542 let fake_prefix = [0u8; 4];
546
547 for remaining_vkey in remaining_wits.vkeys.iter() {
548 let fake_vkey =
549 PublicKey::from_raw_bytes(&[&fake_prefix, remaining_vkey.to_raw_bytes()].concat())
550 .unwrap();
551 let fake_sig = fake_raw_key_sig(0);
552 let fake_vkey_witness = Vkeywitness::new(fake_vkey, fake_sig);
553
554 if !builder.vkeys.contains_key(&fake_vkey_witness.vkey) {
556 builder.add_vkey(fake_vkey_witness);
557 }
558 }
559 for remaining_bootstrap in remaining_wits.bootstraps.iter() {
560 let address_content = &remaining_bootstrap.content;
561 let fake_vkey = PublicKey::from_raw_bytes(
562 &[&fake_prefix, address_content.address_id.to_raw_bytes()].concat(),
563 )
564 .unwrap();
565 let fake_sig = fake_raw_key_sig(0);
566 let fake_chaincode = [0u8; 32]; let fake_witness = BootstrapWitness::new(
568 fake_vkey,
569 fake_sig,
570 fake_chaincode.to_vec(),
571 address_content.addr_attributes.clone(),
572 )
573 .unwrap();
574
575 if !builder.bootstraps.contains_key(&fake_witness.public_key) {
577 builder.add_bootstrap(fake_witness);
578 }
579 }
580}
581
582fn fake_raw_key_sig(id: u8) -> Ed25519Signature {
583 Ed25519Signature::from_raw_bytes(&[
584 id, 248, 153, 211, 155, 23, 253, 93, 102, 193, 146, 196, 181, 13, 52, 62, 66, 247, 35, 91,
585 48, 80, 76, 138, 231, 97, 159, 147, 200, 40, 220, 109, 206, 69, 104, 221, 105, 23, 124, 85,
586 24, 40, 73, 45, 119, 122, 103, 39, 253, 102, 194, 251, 204, 189, 168, 194, 174, 237, 146,
587 3, 44, 153, 121, 10,
588 ])
589 .unwrap()
590}
591
592fn fake_key_hash(x: u8) -> Ed25519KeyHash {
593 Ed25519KeyHash::from_raw_bytes(&[
594 x, 239, 181, 120, 142, 135, 19, 200, 68, 223, 211, 43, 46, 145, 222, 30, 48, 159, 239, 255,
595 213, 85, 248, 39, 204, 158, 225, 100,
596 ])
597 .unwrap()
598}
599
600#[derive(Clone, Debug)]
601pub enum NativeScriptWitnessInfo {
602 Count(usize),
603 Vkeys(Vec<Ed25519KeyHash>),
604 AssumeWorst,
605}
606
607impl NativeScriptWitnessInfo {
608 pub fn num_signatures(num: usize) -> Self {
610 NativeScriptWitnessInfo::Count(num)
611 }
612
613 pub fn vkeys(vkeys: Vec<Ed25519KeyHash>) -> Self {
615 NativeScriptWitnessInfo::Vkeys(vkeys)
616 }
617
618 pub fn assume_signature_count() -> Self {
620 NativeScriptWitnessInfo::AssumeWorst
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 use cml_crypto::{Bip32PrivateKey, Deserialize, Serialize, TransactionHash};
627
628 use crate::byron::make_icarus_bootstrap_witness;
629
630 use super::*;
631
632 fn fake_raw_key_public(id: u8) -> PublicKey {
633 PublicKey::from_raw_bytes(&[
634 id, 118, 57, 154, 33, 13, 232, 114, 14, 159, 168, 148, 228, 94, 65, 226, 154, 181, 37,
635 227, 11, 196, 2, 128, 28, 7, 98, 80, 209, 88, 91, 205,
636 ])
637 .unwrap()
638 }
639
640 fn fake_private_key1() -> Bip32PrivateKey {
641 Bip32PrivateKey::from_raw_bytes(&[
642 0xb8, 0xf2, 0xbe, 0xce, 0x9b, 0xdf, 0xe2, 0xb0, 0x28, 0x2f, 0x5b, 0xad, 0x70, 0x55,
643 0x62, 0xac, 0x99, 0x6e, 0xfb, 0x6a, 0xf9, 0x6b, 0x64, 0x8f, 0x44, 0x45, 0xec, 0x44,
644 0xf4, 0x7a, 0xd9, 0x5c, 0x10, 0xe3, 0xd7, 0x2f, 0x26, 0xed, 0x07, 0x54, 0x22, 0xa3,
645 0x6e, 0xd8, 0x58, 0x5c, 0x74, 0x5a, 0x0e, 0x11, 0x50, 0xbc, 0xce, 0xba, 0x23, 0x57,
646 0xd0, 0x58, 0x63, 0x69, 0x91, 0xf3, 0x8a, 0x37, 0x91, 0xe2, 0x48, 0xde, 0x50, 0x9c,
647 0x07, 0x0d, 0x81, 0x2a, 0xb2, 0xfd, 0xa5, 0x78, 0x60, 0xac, 0x87, 0x6b, 0xc4, 0x89,
648 0x19, 0x2c, 0x1e, 0xf4, 0xce, 0x25, 0x3c, 0x19, 0x7e, 0xe2, 0x19, 0xa4,
649 ])
650 .unwrap()
651 }
652
653 fn fake_private_key2() -> Bip32PrivateKey {
654 Bip32PrivateKey::from_raw_bytes(
655 &hex::decode("d84c65426109a36edda5375ea67f1b738e1dacf8629f2bb5a2b0b20f3cd5075873bf5cdfa7e533482677219ac7d639e30a38e2e645ea9140855f44ff09e60c52c8b95d0d35fe75a70f9f5633a3e2439b2994b9e2bc851c49e9f91d1a5dcbb1a3").unwrap()
656 ).unwrap()
657 }
658
659 #[test]
660 fn test_add_fake_vkey_witnesses_by_num() {
661 let mut builder = RequiredWitnessSet::new();
662 builder.add_fake_vkey_witnesses_by_num(2);
663 assert_eq!(builder.vkeys.len(), 2);
664 builder.add_fake_vkey_witnesses_by_num(1);
665 assert_eq!(builder.vkeys.len(), 3);
666 }
667
668 #[test]
669 fn test_add_input_aggregate_witness_data() {
670 let mut required_wits = RequiredWitnessSet::new();
671 let data = {
672 let witness = {
673 let script = PlutusScript::PlutusV1(PlutusV1Script::new(vec![0]));
674 PartialPlutusWitness {
675 script: PlutusScriptWitness::Script(script),
676 redeemer: PlutusData::new_integer(0u64.into()),
677 }
678 };
679 let missing_signers = vec![fake_raw_key_public(0).hash()];
680 InputAggregateWitnessData::PlutusScript(witness, missing_signers.into(), None)
681 };
682
683 assert_eq!(required_wits.vkeys.len(), 0);
684 required_wits.add_input_aggregate_fake_witness_data(&data);
685 assert_eq!(required_wits.vkeys.len(), 1);
686 }
687
688 #[test]
689 fn test_add_input_aggregate_witness_data_with_existing_key_hash() {
690 let mut required_wits = RequiredWitnessSet::new();
691 let key = fake_raw_key_public(0);
692 let hash = key.hash();
693 required_wits.add_vkey_key_hash(hash);
694
695 let data = {
696 let witness = {
697 let script = PlutusScript::PlutusV1(PlutusV1Script::new(vec![0]));
698 PartialPlutusWitness {
699 script: PlutusScriptWitness::Script(script),
700 redeemer: PlutusData::new_integer(0u64.into()),
701 }
702 };
703 let missing_signers = vec![hash];
704 InputAggregateWitnessData::PlutusScript(witness, missing_signers.into(), None)
705 };
706
707 assert_eq!(required_wits.vkeys.len(), 1);
708 required_wits.add_input_aggregate_fake_witness_data(&data);
709 assert_eq!(required_wits.vkeys.len(), 1);
710 }
711
712 #[test]
713 fn vkey_test() {
714 let mut builder = TransactionWitnessSetBuilder::new();
715 let raw_key_public = fake_raw_key_public(0);
716 let fake_sig = fake_raw_key_sig(0);
717
718 builder.add_vkey(Vkeywitness::new(raw_key_public.clone(), fake_sig.clone()));
720 builder.add_vkey(Vkeywitness::new(raw_key_public, fake_sig));
721
722 builder.add_vkey(Vkeywitness::new(
724 fake_raw_key_public(1),
725 fake_raw_key_sig(1),
726 ));
727
728 let wit_set = builder.build();
729 assert_eq!(wit_set.vkeywitnesses.unwrap().len(), 2);
730 }
731
732 #[test]
733 fn bootstrap_test() {
734 let mut builder = TransactionWitnessSetBuilder::new();
735
736 let wit1 = make_icarus_bootstrap_witness(
738 TransactionHash::from([0u8; TransactionHash::BYTE_COUNT]),
739 ByronAddress::from_base58(
740 "Ae2tdPwUPEZGUEsuMAhvDcy94LKsZxDjCbgaiBBMgYpR8sKf96xJmit7Eho",
741 )
742 .unwrap(),
743 &fake_private_key1(),
744 );
745 builder.add_bootstrap(wit1.clone());
746 builder.add_bootstrap(wit1);
747
748 builder.add_bootstrap(make_icarus_bootstrap_witness(
750 TransactionHash::from([0u8; TransactionHash::BYTE_COUNT]),
751 ByronAddress::from_base58(
752 "Ae2tdPwUPEZGUEsuMAhvDcy94LKsZxDjCbgaiBBMgYpR8sKf96xJmit7Eho",
753 )
754 .unwrap(),
755 &fake_private_key2(),
756 ));
757
758 let wit_set = builder.build();
759 assert_eq!(wit_set.bootstrap_witnesses.unwrap().len(), 2);
760 }
761
762 #[test]
763 fn native_script_test() {
764 let mut builder = TransactionWitnessSetBuilder::new();
765
766 let wit1: Script = NativeScript::new_script_invalid_before(1).into();
768 builder.add_script(wit1.clone());
769 builder.add_script(wit1);
770
771 builder.add_script(NativeScript::new_script_invalid_before(2).into());
773
774 let wit_set = builder.build();
775 assert_eq!(wit_set.native_scripts.unwrap().len(), 2);
776 }
777
778 #[test]
781 fn requirement_test_fail() {
782 let mut builder = TransactionWitnessSetBuilder::new();
783
784 let mut required_wits = RequiredWitnessSet::new();
785 required_wits.add_vkey_key_hash(fake_raw_key_public(0).hash());
786 required_wits.add_script_hash(NativeScript::new_script_invalid_before(2).hash());
787 builder.add_required_wits(required_wits);
788
789 builder.add_vkey(Vkeywitness::new(
791 fake_raw_key_public(1),
792 fake_raw_key_sig(1),
793 ));
794
795 assert!(builder.try_build().is_err());
796 }
797
798 #[test]
799 fn requirement_test_pass() {
800 let mut builder = TransactionWitnessSetBuilder::new();
801
802 let mut required_wits = RequiredWitnessSet::new();
803 required_wits.add_vkey_key_hash(fake_raw_key_public(0).hash());
804 builder.add_required_wits(required_wits);
805
806 builder.add_vkey(Vkeywitness::new(
808 fake_raw_key_public(0),
809 fake_raw_key_sig(0),
810 ));
811
812 assert!(builder.try_build().is_ok());
813 }
814
815 #[test]
816 fn tx_witness_set_roundtrip_test() {
817 let data = "a102818458205e8379f58f0838234af67f73738f0fee0d8185232e200b8e42887f4f06544a9a5840f5cfea560d2f8645ed624b65bf08cf83346eb5168ee4df0f63ce2d0d5f677db88fef2d5d9f032f09223889b5e85504ab44dd0a0cde1f1fd8f57deefde8c2080658202d3b7d9b806f88f10f1193e94ef97e5c02370c1464f61a30a8f1ac1a46115b2d5829a201581e581c072931653330243cf126aea85d39e73c6bd04601fe77424efb9e371002451a4170cb17";
818 let witness_set =
819 TransactionWitnessSet::from_cbor_bytes(&hex::decode(data).unwrap()).unwrap();
820 let round_trip = witness_set.to_cbor_bytes();
821
822 assert_eq!(data, hex::encode(round_trip));
823 }
824}