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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//!
//! Find my vote
//!

use clap::Parser;
use lib::find::{all_voters, batch_key_check, convert_key_formats, find_vote};
use tracing::{info, Level};

use color_eyre::Result;

use std::{fs::File, io::BufWriter};

use std::{error::Error, path::PathBuf};

///
/// Args defines and declares CLI behaviour within the context of clap
///
#[derive(Parser, Debug, Clone)]
#[clap(about, version, author)]
pub struct Args {
    /// Obtain fragments by providing path to historical fund data.
    #[clap(short, long)]
    pub fragments: Option<String>,
    /// voting key
    #[clap(short, long, requires = "fragments")]
    voting_key: Option<String>,
    /// aggregate voting keys
    #[clap(short, long, requires = "fragments")]
    aggregate: Option<bool>,
    ///convert key formats
    #[clap(short, long)]
    key_to_convert: Option<String>,
    /// check batch of keys and write history to file
    #[clap(short, long, requires = "fragments")]
    key_file: Option<String>,
}

fn main() -> Result<(), Box<dyn Error>> {
    color_eyre::install()?;

    let args = Args::parse();

    // Configure a custom event formatter
    let format = tracing_subscriber::fmt::format()
        .with_level(true) // don't include levels in formatted output
        .with_target(true) // don't include targets
        .with_thread_ids(true) // include the thread ID of the current thread
        .with_thread_names(true) // include the name of the current thread
        .compact(); // use the `Compact` formatting style.

    // Create a `fmt` subscriber that uses our custom event format, and set it
    // as the default.
    tracing_subscriber::fmt()
        .event_format(format)
        .with_max_level(Level::INFO /*DEBUG*/)
        .init();

    info!("Audit Tool.");
    info!("Find my vote");

    if let Some(voting_key) = args.voting_key {
        // Load and replay fund fragments from storage
        let storage_path = PathBuf::from(
            args.fragments
                .clone()
                .expect("enforced by clap: infallible"),
        );

        // all fragments including tally fragments
        info!("finding vote history of voter {:?}", voting_key);

        let matched_votes = find_vote(&storage_path, voting_key.clone())?;

        // record of casters votes
        let matched_votes_path = PathBuf::from("/tmp/offline")
            .with_extension(format!("voting_history_of_{}.json", voting_key));

        let file = File::options()
            .write(true)
            .create(true)
            .truncate(true)
            .open(matched_votes_path.clone())?;
        let writer = BufWriter::new(file);

        info!(
            "writing voting history of voter {:?} to {:?}",
            voting_key, matched_votes_path
        );

        serde_json::to_writer_pretty(writer, &matched_votes)?;
    }

    if let Some(_aggregate) = args.aggregate {
        // Load and replay fund fragments from storage
        let storage_path = PathBuf::from(
            args.fragments
                .clone()
                .expect("enforced by clap: infallible"),
        );

        info!("collecting all voting keys in ca and 0x format");

        let (unique_voters_ca, unique_voters_0x) = all_voters(&storage_path)?;

        let voters_file_0x =
            PathBuf::from("/tmp/inspect").with_extension("validated_voters_0x.json");
        let voters_file_ca =
            PathBuf::from("/tmp/inspect").with_extension("validated_voters_ca.json");

        let file = File::options()
            .write(true)
            .create(true)
            .truncate(true)
            .open(voters_file_ca)
            .unwrap();
        let writer = BufWriter::new(file);

        serde_json::to_writer_pretty(writer, &unique_voters_ca)?;

        let file = File::options()
            .write(true)
            .create(true)
            .truncate(true)
            .open(voters_file_0x)
            .unwrap();
        let writer = BufWriter::new(file);

        serde_json::to_writer_pretty(writer, &unique_voters_0x)?;

        info!("keys written to /tmp/inspect/validated_voters_*.json");
    }

    if let Some(keyfile) = args.key_file {
        let storage_path = PathBuf::from(args.fragments.expect("enforced by clap: infallible"));
        batch_key_check(&storage_path, keyfile)?;
    }

    if let Some(voting_key) = args.key_to_convert {
        let converted_key = convert_key_formats(voting_key)?;
        info!("Converted key: {}", converted_key);
    }

    Ok(())
}