http_kv_tool/
http_kv_tool.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{str::FromStr, sync::Arc};
6
7use clap::*;
8use iota_storage::{
9    http_key_value_store::*, key_value_store::TransactionKeyValueStore,
10    key_value_store_metrics::KeyValueStoreMetrics,
11};
12use iota_types::{
13    base_types::ObjectID,
14    digests::{CheckpointDigest, TransactionDigest},
15    messages_checkpoint::CheckpointSequenceNumber,
16};
17
18// Command line options are:
19// --base-url <url> - the base URL of the HTTP server
20// --digest <digest> - the digest of the key being fetched
21// --type <fx|tx|ev> - the type of key being fetched
22#[derive(Parser)]
23struct Options {
24    #[arg(short, long)]
25    base_url: String,
26
27    #[arg(short, long)]
28    digest: Vec<String>,
29
30    #[arg(short, long)]
31    seq: Vec<String>,
32
33    // must be either 'tx', 'fx','ob','events', or 'ckpt_contents'
34    // default value of 'tx'
35    #[arg(short, long, default_value = "tx")]
36    type_: String,
37}
38
39#[tokio::main]
40async fn main() {
41    let _guard = telemetry_subscribers::TelemetryConfig::new()
42        .with_env()
43        .init();
44
45    let options = Options::parse();
46
47    let http_kv = Arc::new(HttpKVStore::new(&options.base_url).unwrap());
48    let kv =
49        TransactionKeyValueStore::new("http_kv", KeyValueStoreMetrics::new_for_tests(), http_kv);
50
51    let seqs: Vec<_> = options
52        .seq
53        .into_iter()
54        .map(|s| {
55            CheckpointSequenceNumber::from_str(&s).expect("invalid checkpoint sequence number")
56        })
57        .collect();
58
59    // verify that type is valid
60    match options.type_.as_str() {
61        "tx" | "fx" => {
62            let digests: Vec<_> = options
63                .digest
64                .into_iter()
65                .map(|digest| {
66                    TransactionDigest::from_str(&digest).expect("invalid transaction digest")
67                })
68                .collect();
69
70            if options.type_ == "tx" {
71                let tx = kv.multi_get_tx(&digests).await.unwrap();
72                for (digest, tx) in digests.iter().zip(tx.iter()) {
73                    println!("fetched tx: {:?} {:?}", digest, tx);
74                }
75            } else {
76                let fx = kv.multi_get_fx_by_tx_digest(&digests).await.unwrap();
77                for (digest, fx) in digests.iter().zip(fx.iter()) {
78                    println!("fetched fx: {:?} {:?}", digest, fx);
79                }
80            }
81        }
82
83        "ckpt_contents" => {
84            let ckpts = kv.multi_get_checkpoints(&[], &seqs, &[]).await.unwrap();
85
86            for (seq, ckpt) in seqs.iter().zip(ckpts.1.iter()) {
87                // populate digest before printing
88                ckpt.as_ref().map(|c| c.digest());
89                println!("fetched ckpt contents: {:?} {:?}", seq, ckpt);
90            }
91        }
92
93        "ckpt_summary" => {
94            let digests: Vec<_> = options
95                .digest
96                .into_iter()
97                .map(|s| CheckpointDigest::from_str(&s).expect("invalid checkpoint digest"))
98                .collect();
99
100            let ckpts = kv
101                .multi_get_checkpoints(&seqs, &[], &digests)
102                .await
103                .unwrap();
104
105            for (seq, ckpt) in seqs.iter().zip(ckpts.0.iter()) {
106                // populate digest before printing
107                ckpt.as_ref().map(|c| c.digest());
108                println!("fetched ckpt summary: {:?} {:?}", seq, ckpt);
109            }
110            for (digest, ckpt) in digests.iter().zip(ckpts.2.iter()) {
111                // populate digest before printing
112                ckpt.as_ref().map(|c| c.digest());
113                println!("fetched ckpt summary: {:?} {:?}", digest, ckpt);
114            }
115        }
116
117        "ob" => {
118            let object_id = ObjectID::from_str(&options.digest[0]).expect("invalid object id");
119            let object = kv.get_object(object_id, seqs[0].into()).await.unwrap();
120            println!("fetched object {:?}", object);
121        }
122
123        _ => {
124            println!(
125                "Invalid key type: {}. Must be one of 'tx', 'fx', or 'ev'.",
126                options.type_
127            );
128            std::process::exit(1);
129        }
130    }
131}