1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use assert_fs::{fixture::PathChild, prelude::*, TempDir};
use chain_impl_mockchain::account::SpendingCounter;
use jormungandr_lib::crypto::hash::Hash;
use std::{fmt, path::PathBuf};

#[derive(Debug, Copy, Clone)]
pub enum WitnessType {
    Account,
    UTxO,
    //needed for negative testing
    Unknown,
}

impl fmt::Display for WitnessType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::Account => write!(f, "account"),
            Self::UTxO => write!(f, "utxo"),
            Self::Unknown => write!(f, "unknown"),
        }
    }
}

#[derive(Debug)]
pub struct Witness {
    pub block_hash: Hash,
    pub transaction_id: Hash,
    pub addr_type: WitnessType,
    pub private_key_path: PathBuf,
    pub account_spending_counter: Option<SpendingCounter>,
    pub file: PathBuf,
}

impl Witness {
    pub fn new(
        temp_dir: &impl PathChild,
        block_hash: &Hash,
        transaction_id: &Hash,
        addr_type: WitnessType,
        private_key: &str,
        account_spending_counter: Option<SpendingCounter>,
    ) -> Witness {
        Witness {
            block_hash: *block_hash,
            transaction_id: *transaction_id,
            addr_type,
            private_key_path: write_witness_key(temp_dir, private_key),
            file: temp_dir.child("witness").path().into(),
            account_spending_counter,
        }
    }
}

fn write_witness_key(temp_dir: &impl PathChild, witness_key: &str) -> PathBuf {
    let file = temp_dir.child("witness_key.secret");
    file.write_str(witness_key).unwrap();
    let path = file.path().to_path_buf();
    println!("Witness key saved into: {:?}", path);
    path
}

pub struct WitnessData {
    pub secret_bech32: String,
    pub addr_type: WitnessType,
    pub spending_counter: Option<SpendingCounter>,
}

impl WitnessData {
    pub fn new_account(signing_key: &str, spending_counter: SpendingCounter) -> Self {
        Self {
            secret_bech32: signing_key.to_owned(),
            addr_type: WitnessType::Account,
            spending_counter: Some(spending_counter),
        }
    }

    pub fn new_utxo(signing_key: &str) -> Self {
        Self {
            secret_bech32: signing_key.to_owned(),
            addr_type: WitnessType::UTxO,
            spending_counter: None,
        }
    }

    pub fn spending_counter(&self) -> Option<SpendingCounter> {
        self.spending_counter
    }

    pub fn into_witness(
        &self,
        staging_dir: &TempDir,
        genesis_hash: &Hash,
        transaction_id: &Hash,
    ) -> Witness {
        Witness::new(
            staging_dir,
            genesis_hash,
            transaction_id,
            self.addr_type,
            &self.secret_bech32,
            self.spending_counter(),
        )
    }
}