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 metrics = KeyValueStoreMetrics::new_for_tests();
48    let http_kv = Arc::new(HttpKVStore::new(&options.base_url, 100, metrics).unwrap());
49    let kv =
50        TransactionKeyValueStore::new("http_kv", KeyValueStoreMetrics::new_for_tests(), http_kv);
51
52    let seqs: Vec<_> = options
53        .seq
54        .into_iter()
55        .map(|s| {
56            CheckpointSequenceNumber::from_str(&s).expect("invalid checkpoint sequence number")
57        })
58        .collect();
59
60    // verify that type is valid
61    match options.type_.as_str() {
62        "tx" | "fx" => {
63            let digests: Vec<_> = options
64                .digest
65                .into_iter()
66                .map(|digest| {
67                    TransactionDigest::from_str(&digest).expect("invalid transaction digest")
68                })
69                .collect();
70
71            if options.type_ == "tx" {
72                let tx = kv.multi_get_tx(&digests).await.unwrap();
73                for (digest, tx) in digests.iter().zip(tx.iter()) {
74                    println!("fetched tx: {digest:?} {tx:?}");
75                }
76            } else {
77                let fx = kv.multi_get_fx_by_tx_digest(&digests).await.unwrap();
78                for (digest, fx) in digests.iter().zip(fx.iter()) {
79                    println!("fetched fx: {digest:?} {fx:?}");
80                }
81            }
82        }
83
84        "ckpt_contents" => {
85            let ckpts = kv.multi_get_checkpoints(&[], &seqs, &[]).await.unwrap();
86
87            for (seq, ckpt) in seqs.iter().zip(ckpts.1.iter()) {
88                // populate digest before printing
89                ckpt.as_ref().map(|c| c.digest());
90                println!("fetched ckpt contents: {seq:?} {ckpt:?}");
91            }
92        }
93
94        "ckpt_summary" => {
95            let digests: Vec<_> = options
96                .digest
97                .into_iter()
98                .map(|s| CheckpointDigest::from_str(&s).expect("invalid checkpoint digest"))
99                .collect();
100
101            let ckpts = kv
102                .multi_get_checkpoints(&seqs, &[], &digests)
103                .await
104                .unwrap();
105
106            for (seq, ckpt) in seqs.iter().zip(ckpts.0.iter()) {
107                // populate digest before printing
108                ckpt.as_ref().map(|c| c.digest());
109                println!("fetched ckpt summary: {seq:?} {ckpt:?}");
110            }
111            for (digest, ckpt) in digests.iter().zip(ckpts.2.iter()) {
112                // populate digest before printing
113                ckpt.as_ref().map(|c| c.digest());
114                println!("fetched ckpt summary: {digest:?} {ckpt:?}");
115            }
116        }
117
118        "ob" => {
119            let object_id = ObjectID::from_str(&options.digest[0]).expect("invalid object id");
120            let object = kv.get_object(object_id, seqs[0].into()).await.unwrap();
121            println!("fetched object {object:?}");
122        }
123
124        _ => {
125            println!(
126                "Invalid key type: {}. Must be one of 'tx', 'fx', or 'ev'.",
127                options.type_
128            );
129            std::process::exit(1);
130        }
131    }
132}