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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    client_proxy::ClientProxy,
    commands::{report_error, subcommand_execute, Command},
};

/// Major command for query operations.
pub struct QueryCommand {}

impl Command for QueryCommand {
    fn get_aliases(&self) -> Vec<&'static str> {
        vec!["query", "q"]
    }
    fn get_description(&self) -> &'static str {
        "Query operations"
    }
    fn execute(&self, client: &mut ClientProxy, params: &[&str]) {
        let commands: Vec<Box<dyn Command>> = vec![
            Box::new(QueryCommandGetBalance {}),
            Box::new(QueryCommandGetSeqNum {}),
            Box::new(QueryCommandGetLatestAccountState {}),
            Box::new(QueryCommandGetTxnByAccountSeq {}),
            Box::new(QueryCommandGetTxnByRange {}),
            Box::new(QueryCommandGetEvent {}),
            Box::new(QueryCommandGetLatestAccountResources {}),
        ];

        subcommand_execute(params[0], commands, client, &params[1..]);
    }
}

/// Sub commands to query balance for the account specified.
pub struct QueryCommandGetBalance {}

impl Command for QueryCommandGetBalance {
    fn get_aliases(&self) -> Vec<&'static str> {
        vec!["balance", "b"]
    }
    fn get_params_help(&self) -> &'static str {
        "<account_ref_id>|<account_address>"
    }
    fn get_description(&self) -> &'static str {
        "Get the current balances of an account"
    }
    fn execute(&self, client: &mut ClientProxy, params: &[&str]) {
        if params.len() != 2 {
            println!("Invalid number of arguments for balance query");
            return;
        }
        match client.get_balances(params) {
            Ok(balances) => balances
                .iter()
                .for_each(|balance| println!("Balance is: {}", balance)),
            Err(e) => report_error("Failed to get balances", e),
        }
    }
}

/// Sub command to get the latest sequence number from validator for the account specified.
pub struct QueryCommandGetSeqNum {}

impl Command for QueryCommandGetSeqNum {
    fn get_aliases(&self) -> Vec<&'static str> {
        vec!["sequence", "s"]
    }
    fn get_params_help(&self) -> &'static str {
        "<account_ref_id>|<account_address> [reset_sequence_number=true|false]"
    }
    fn get_description(&self) -> &'static str {
        "Get the current sequence number for an account, \
         and reset current sequence number in CLI (optional, default is false)"
    }
    fn execute(&self, client: &mut ClientProxy, params: &[&str]) {
        println!(">> Getting current sequence number");
        match client.get_sequence_number(params) {
            Ok(sn) => println!("Sequence number is: {}", sn),
            Err(e) => report_error("Error getting sequence number", e),
        }
    }
}

/// Command to query latest account state from validator.
pub struct QueryCommandGetLatestAccountState {}

impl Command for QueryCommandGetLatestAccountState {
    fn get_aliases(&self) -> Vec<&'static str> {
        vec!["account_state", "as"]
    }
    fn get_params_help(&self) -> &'static str {
        "<account_ref_id>|<account_address>"
    }
    fn get_description(&self) -> &'static str {
        "Get the latest state for an account"
    }
    fn execute(&self, client: &mut ClientProxy, params: &[&str]) {
        println!(">> Getting latest account state");
        match client.get_latest_account(params) {
            Ok(acc) => println!(
                "Latest account state is: \n \
                 Account: {:#?}\n \
                 State: {:#?}\n \
                 Blockchain Version: {}\n",
                client
                    .get_account_address_from_parameter(params[1])
                    .expect("Unable to parse account parameter"),
                acc,
                client.get_latest_version(),
            ),
            Err(e) => report_error("Error getting latest account state", e),
        }
    }
}

/// Command to query latest account state from validator.
pub struct QueryCommandGetLatestAccountResources {}

impl Command for QueryCommandGetLatestAccountResources {
    fn get_aliases(&self) -> Vec<&'static str> {
        vec!["account_resources", "ar"]
    }
    fn get_params_help(&self) -> &'static str {
        "<account_ref_id>|<account_address>"
    }
    fn get_description(&self) -> &'static str {
        "Get the latest annotated resources in an account"
    }
    fn execute(&self, client: &mut ClientProxy, params: &[&str]) {
        println!(">> Getting latest account state");
        match client.get_latest_account_resources(params) {
            Ok((Some(acc), version)) => println!(
                "Latest account state is: \n \
                 Account: {:#?}\n \
                 State: {}\n \
                 Blockchain Version: {}\n",
                client
                    .get_account_address_from_parameter(params[1])
                    .expect("Unable to parse account parameter"),
                acc,
                version,
            ),
            Ok((None, _version)) => println!(
                "No Account found for {:#?}",
                client
                    .get_account_address_from_parameter(params[1])
                    .expect("Unable to parse account parameter")
            ),
            Err(e) => report_error("Error getting latest account state", e),
        }
    }
}

/// Sub command  to get transaction by account and sequence number from validator.
pub struct QueryCommandGetTxnByAccountSeq {}

impl Command for QueryCommandGetTxnByAccountSeq {
    fn get_aliases(&self) -> Vec<&'static str> {
        vec!["txn_acc_seq", "ts"]
    }
    fn get_params_help(&self) -> &'static str {
        "<account_ref_id>|<account_address> <sequence_number> <fetch_events=true|false>"
    }
    fn get_description(&self) -> &'static str {
        "Get the committed transaction by account and sequence number.  \
         Optionally also fetch events emitted by this transaction."
    }
    fn execute(&self, client: &mut ClientProxy, params: &[&str]) {
        println!(">> Getting committed transaction by account and sequence number");
        match client.get_committed_txn_by_acc_seq(params) {
            Ok(txn_view) => {
                match txn_view {
                    Some(txn_view) => {
                        println!("Committed transaction: {:#?}", txn_view);
                    }
                    None => println!("Transaction not available"),
                };
            }
            Err(e) => report_error(
                "Error getting committed transaction by account and sequence number",
                e,
            ),
        }
    }
}

/// Sub command to query transactions by range from validator.
pub struct QueryCommandGetTxnByRange {}

impl Command for QueryCommandGetTxnByRange {
    fn get_aliases(&self) -> Vec<&'static str> {
        vec!["txn_range", "tr"]
    }
    fn get_params_help(&self) -> &'static str {
        "<start_version> <limit> <fetch_events=true|false>"
    }
    fn get_description(&self) -> &'static str {
        "Get the committed transactions by version range. \
         Optionally also fetch events emitted by these transactions."
    }
    fn execute(&self, client: &mut ClientProxy, params: &[&str]) {
        println!(">> Getting committed transaction by range");
        match client.get_committed_txn_by_range(params) {
            Ok(comm_txns_and_events) => {
                // Note that this should never panic because we shouldn't return items
                // if the version wasn't able to be parsed in the first place
                let mut cur_version = params[1].parse::<u64>().expect("Unable to parse version");
                for txn_view in comm_txns_and_events {
                    println!("Transaction at version {}: {:#?}", cur_version, txn_view,);
                    cur_version += 1;
                }
            }
            Err(e) => report_error("Error getting committed transactions by range", e),
        }
    }
}

/// Sub command to query events from validator.
pub struct QueryCommandGetEvent {}

impl Command for QueryCommandGetEvent {
    fn get_aliases(&self) -> Vec<&'static str> {
        vec!["event", "ev"]
    }
    fn get_params_help(&self) -> &'static str {
        "<account_ref_id>|<account_address> <sent|received> <start_sequence_number> <limit>"
    }
    fn get_description(&self) -> &'static str {
        "Get events by account and event type (sent|received)."
    }
    fn execute(&self, client: &mut ClientProxy, params: &[&str]) {
        println!(">> Getting events by account and event type.");
        match client.get_events_by_account_and_type(params) {
            Ok((events, last_event_state)) => {
                if events.is_empty() {
                    println!("No events returned");
                } else {
                    for event in events {
                        println!("{:?}", event);
                    }
                }
                println!("Last event state: {:#?}", last_event_state);
            }
            Err(e) => report_error("Error getting events by access path", e),
        }
    }
}