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
//! Module with structs for handling gas reports.
use crate::prelude::*;
use crate::{Address, CallDef};
use casper_types::U512;
use core::fmt::{Debug, Display, Formatter, Result};
use serde::{Deserialize, Serialize};

/// A Vector of deploy reports makes a full gas report.
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct GasReport(Vec<DeployReport>);

impl GasReport {
    /// Adds a deploy report to the gas report.
    pub fn push(&mut self, report: DeployReport) {
        self.0.push(report)
    }

    /// Returns new, empty gas report.
    pub fn new() -> Self {
        GasReport::default()
    }

    /// Returns an iterator over the gas report.
    pub fn iter(&self) -> Iter<'_, DeployReport> {
        self.0.iter()
    }
}

impl Display for GasReport {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        for report in &self.0 {
            writeln!(f, "{}", report)?;
        }
        Ok(())
    }
}

impl IntoIterator for GasReport {
    type Item = DeployReport;
    type IntoIter = IntoIter<DeployReport>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

/// Represents a deploy report, which includes the gas used and the deploy details.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum DeployReport {
    /// Represents a Wasm deploy.
    WasmDeploy {
        /// The gas used for the deploy.
        gas: U512,
        /// The file name of the deployed WASM.
        file_name: String
    },
    /// Represents a contract call.
    ContractCall {
        /// The gas used for the call.
        gas: U512,
        /// The address of the contract called.
        contract_address: Address,
        /// The call definition.
        call_def: CallDef
    }
}

impl Display for DeployReport {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        match self {
            DeployReport::WasmDeploy { gas, file_name } => {
                write!(
                    f,
                    "Wasm deploy: {} - {} CSPR",
                    file_name,
                    cspr_pretty_string(gas)
                )
            }
            DeployReport::ContractCall { gas, call_def, .. } => {
                write!(
                    f,
                    "Contract call: {} - {} CSPR",
                    call_def.entry_point(),
                    cspr_pretty_string(gas)
                )
            }
        }
    }
}

/// Render 1234567890 as 1.23456789
fn cspr_pretty_string(cspr: &U512) -> String {
    let cspr_top = cspr / U512::from(1_000_000_000);
    let cspr_bottom = cspr % U512::from(1_000_000_000); // Use modulo to get the remainder
    let cspr_bottom_str = format!("{:09}", cspr_bottom);
    let mut cspr_bottom_str = cspr_bottom_str.trim_end_matches('0');
    if cspr_bottom_str.is_empty() {
        cspr_bottom_str = "0";
    }
    format!("{}.{}", cspr_top, cspr_bottom_str)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Address::Account;
    use casper_types::account::AccountHash;
    use casper_types::RuntimeArgs;

    #[test]
    fn test_deploy_report_display() {
        let wasm_deploy = DeployReport::WasmDeploy {
            gas: U512::from(1000),
            file_name: String::from("test.wasm")
        };
        assert_eq!(
            format!("{}", wasm_deploy),
            "Wasm deploy: test.wasm - 0.000001 CSPR"
        );

        let contract_call = DeployReport::ContractCall {
            gas: U512::from(1_000_000_000),
            contract_address: Account(AccountHash([0; 32])),
            call_def: CallDef::new("test", false, RuntimeArgs::new())
        };
        assert_eq!(
            format!("{}", contract_call),
            "Contract call: test - 1.0 CSPR"
        );
    }
}