Skip to content

Commit

Permalink
sui-tool (MystenLabs#3230)
Browse files Browse the repository at this point in the history
  • Loading branch information
mystenmark authored Jul 15, 2022
1 parent c9ba193 commit 1d1328e
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 0 deletions.
26 changes: 26 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ members = [
"crates/sui-quorum-driver",
"crates/sui-storage",
"crates/sui-swarm",
"crates/sui-tool",
"crates/sui-transactional-test-runner",
"crates/sui-types",
"crates/sui-verifier",
Expand Down
32 changes: 32 additions & 0 deletions crates/sui-tool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "sui-tool"
version = "0.6.0"
authors = ["Mysten Labs <[email protected]>"]
license = "Apache-2.0"
publish = false
edition = "2021"

[dependencies]
anyhow = { version = "1.0.58", features = ["backtrace"] }
tokio = { version = "1.18.2", features = ["full"] }
tracing = "0.1.35"
clap = { version = "3.1.17", features = ["derive"] }
telemetry-subscribers = { git = "https://github.com/MystenLabs/mysten-infra", rev = "40dae350a699f59f2e296152e02c78765db34e68" }
mysten-network = { git = "https://github.com/MystenLabs/mysten-infra", rev = "40dae350a699f59f2e296152e02c78765db34e68" }

sui-core = { path = "../sui-core" }
sui-framework = { path = "../sui-framework" }
sui-config = { path = "../sui-config" }
sui-types = { path = "../sui-types" }
sui-json = { path = "../sui-json" }
sui-gateway = { path = "../sui-gateway" }
sui-swarm = { path = "../sui-swarm" }
sui-json-rpc-api = { path = "../sui-json-rpc-api" }

rustyline = "9.1.2"
rustyline-derive = "0.6.0"
colored = "2.0.0"
unescape = "0.1.0"
shell-words = "1.1.0"

workspace-hack = { path = "../workspace-hack"}
152 changes: 152 additions & 0 deletions crates/sui-tool/src/commands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::time::Duration;
use sui_config::genesis::Genesis;

use sui_core::authority_client::{AuthorityAPI, NetworkAuthorityClient};
use sui_types::{base_types::*, messages::*};

use clap::*;

#[derive(Parser)]
#[clap(
name = "sui-tool",
about = "Debugging utilities for sui",
rename_all = "kebab-case",
author,
version
)]
pub enum ToolCommand {
/// Fetch the same object from all validators
#[clap(name = "fetch-object")]
FetchObject {
#[clap(long, help = "The object ID to fetch")]
id: ObjectID,

#[clap(long, help = "Fetch object at a specific sequence")]
version: Option<u64>,

#[clap(
long,
help = "Validator to fetch from - if not specified, all validators are queried"
)]
validator: Option<AuthorityName>,

#[clap(long = "genesis")]
genesis: PathBuf,
},
}

fn make_clients(genesis: PathBuf) -> Result<BTreeMap<AuthorityName, NetworkAuthorityClient>> {
let mut net_config = mysten_network::config::Config::new();
net_config.connect_timeout = Some(Duration::from_secs(5));
net_config.request_timeout = Some(Duration::from_secs(5));
net_config.http2_keepalive_interval = Some(Duration::from_secs(5));

let genesis = Genesis::load(genesis)?;

let mut authority_clients = BTreeMap::new();

for validator in genesis.validator_set() {
let channel = net_config.connect_lazy(&validator.network_address)?;
let client = NetworkAuthorityClient::new(channel);
let public_key_bytes = validator.public_key();
authority_clients.insert(public_key_bytes, client);
}

Ok(authority_clients)
}

struct ObjectOutput {
requested_id: ObjectID,
responses: Vec<(AuthorityName, ObjectInfoResponse)>,
}

impl std::fmt::Display for ObjectOutput {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Object: {}", self.requested_id)?;

for (name, resp) in &self.responses {
writeln!(f, "-- validator: {:?}", name)?;

let objref = resp
.requested_object_reference
.as_ref()
.map(|o| format!("{:?}", o))
.unwrap_or_else(|| "<no object>".into());
writeln!(f, "---- ref: {}", objref)?;

let cert = resp
.parent_certificate
.as_ref()
.map(|c| format!("{:?}", c.digest()))
.unwrap_or_else(|| "<genesis>".into());
writeln!(f, "---- cert: {}", cert)?;

if let Some(ObjectResponse { lock, .. }) = &resp.object_and_lock {
// TODO maybe show object contents if we can do so meaningfully.
writeln!(f, "---- object: <data>")?;
writeln!(
f,
"---- locked by : {}",
lock.as_ref()
.map(|l| format!("{:?}", l.digest()))
.unwrap_or_else(|| "<not locked>".into())
)?;
}
}
Ok(())
}
}

impl ToolCommand {
pub async fn execute(self) -> Result<(), anyhow::Error> {
match self {
ToolCommand::FetchObject {
id,
validator,
genesis,
version,
} => {
let clients = make_clients(genesis)?;

let clients = clients.iter().filter(|(name, _)| {
if let Some(v) = validator {
v == **name
} else {
true
}
});

let mut output = ObjectOutput {
requested_id: id,
responses: Vec::new(),
};

for (name, client) in clients {
let resp = client
.handle_object_info_request(ObjectInfoRequest {
object_id: id,
request_kind: match version {
None => ObjectInfoRequestKind::LatestObjectInfo(None),
Some(v) => ObjectInfoRequestKind::PastObjectInfo(
SequenceNumber::from_u64(v),
),
},
})
.await?;

output.responses.push((*name, resp));
}

println!("{}", output);
}
}

Ok(())
}
}
24 changes: 24 additions & 0 deletions crates/sui-tool/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
extern crate core;

use clap::*;
use colored::Colorize;
use sui_types::exit_main;

mod commands;
use commands::ToolCommand;

#[tokio::main]
async fn main() {
#[cfg(windows)]
colored::control::set_virtual_terminal(true).unwrap();

let bin_name = env!("CARGO_BIN_NAME");
let cmd: ToolCommand = ToolCommand::parse();
let _guard = telemetry_subscribers::TelemetryConfig::new(bin_name)
.with_env()
.init();

exit_main!(cmd.execute().await);
}

0 comments on commit 1d1328e

Please sign in to comment.