Reorganize ledger-tool run sub-command (#31572)
* Rename ledger-tool run subcommand to program subcommand * Reorganize ledger-tool program command to multiple subcommands
This commit is contained in:
parent
04425b81ce
commit
fb79e2bbb8
|
@ -1,6 +1,6 @@
|
||||||
#![allow(clippy::integer_arithmetic)]
|
#![allow(clippy::integer_arithmetic)]
|
||||||
use {
|
use {
|
||||||
crate::{args::*, bigtable::*, ledger_path::*, ledger_utils::*, output::*, run::*},
|
crate::{args::*, bigtable::*, ledger_path::*, ledger_utils::*, output::*, program::*},
|
||||||
chrono::{DateTime, Utc},
|
chrono::{DateTime, Utc},
|
||||||
clap::{
|
clap::{
|
||||||
crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App,
|
crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App,
|
||||||
|
@ -106,7 +106,7 @@ mod bigtable;
|
||||||
mod ledger_path;
|
mod ledger_path;
|
||||||
mod ledger_utils;
|
mod ledger_utils;
|
||||||
mod output;
|
mod output;
|
||||||
mod run;
|
mod program;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
enum LedgerOutputMethod {
|
enum LedgerOutputMethod {
|
||||||
|
@ -1286,7 +1286,7 @@ fn main() {
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["json", "json-compact"])
|
.possible_values(&["json", "json-compact"])
|
||||||
.help("Return information in specified output format, \
|
.help("Return information in specified output format, \
|
||||||
currently only available for bigtable and run subcommands"),
|
currently only available for bigtable and program subcommands"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("verbose")
|
Arg::with_name("verbose")
|
||||||
|
@ -2028,7 +2028,7 @@ fn main() {
|
||||||
If no file name is specified, it will print the metadata of all ledger files.")
|
If no file name is specified, it will print the metadata of all ledger files.")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.run_subcommand()
|
.program_subcommand()
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
info!("{} {}", crate_name!(), solana_version::version!());
|
info!("{} {}", crate_name!(), solana_version::version!());
|
||||||
|
@ -4058,8 +4058,8 @@ fn main() {
|
||||||
eprintln!("{err}");
|
eprintln!("{err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("run", Some(arg_matches)) => {
|
("program", Some(arg_matches)) => {
|
||||||
run(&ledger_path, arg_matches);
|
program(&ledger_path, arg_matches);
|
||||||
}
|
}
|
||||||
("", _) => {
|
("", _) => {
|
||||||
eprintln!("{}", matches.usage());
|
eprintln!("{}", matches.usage());
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{args::*, ledger_utils::*},
|
crate::{args::*, ledger_utils::*},
|
||||||
clap::{value_t, App, Arg, ArgMatches, SubCommand},
|
clap::{value_t, App, AppSettings, Arg, ArgMatches, SubCommand},
|
||||||
log::*,
|
log::*,
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
serde_json::Result,
|
serde_json::Result,
|
||||||
|
@ -131,18 +131,52 @@ fn load_blockstore(ledger_path: &Path, arg_matches: &ArgMatches<'_>) -> Arc<Bank
|
||||||
bank
|
bank
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RunSubCommand {
|
pub trait ProgramSubCommand {
|
||||||
fn run_subcommand(self) -> Self;
|
fn program_subcommand(self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunSubCommand for App<'_, '_> {
|
impl ProgramSubCommand for App<'_, '_> {
|
||||||
fn run_subcommand(self) -> Self {
|
fn program_subcommand(self) -> Self {
|
||||||
|
let program_arg = Arg::with_name("PROGRAM")
|
||||||
|
.help(
|
||||||
|
"Program file to use. This is either an ELF shared-object file to be executed, \
|
||||||
|
or an assembly file to be assembled and executed.",
|
||||||
|
)
|
||||||
|
.required(true)
|
||||||
|
.index(1);
|
||||||
|
let max_genesis_arg = Arg::with_name("max_genesis_archive_unpacked_size")
|
||||||
|
.long("max-genesis-archive-unpacked-size")
|
||||||
|
.value_name("NUMBER")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value("10485760")
|
||||||
|
.help("maximum total uncompressed size of unpacked genesis archive");
|
||||||
self.subcommand(
|
self.subcommand(
|
||||||
|
SubCommand::with_name("program")
|
||||||
|
.about("Run to test, debug, and analyze on-chain programs.")
|
||||||
|
.setting(AppSettings::InferSubcommands)
|
||||||
|
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("cfg")
|
||||||
|
.about("generates Control Flow Graph of the program.")
|
||||||
|
.arg(&max_genesis_arg)
|
||||||
|
.arg(&program_arg)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("disassemble")
|
||||||
|
.about("dumps disassembled code of the program.")
|
||||||
|
.arg(&max_genesis_arg)
|
||||||
|
.arg(&program_arg)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
SubCommand::with_name("run")
|
SubCommand::with_name("run")
|
||||||
.about(
|
.about(
|
||||||
r##"Run to test, debug, and analyze on-chain programs.
|
"The command executes on-chain programs in a mocked environment.",
|
||||||
|
)
|
||||||
The tool executes on-chain programs in a mocked environment.
|
.arg(
|
||||||
|
Arg::with_name("input")
|
||||||
|
.help(
|
||||||
|
r##"Input for the program to run on, where FILE is a name of a JSON file
|
||||||
|
with input data, or BYTES is the number of 0-valued bytes to allocate for program parameters"
|
||||||
|
|
||||||
The input data for a program execution have to be in JSON format
|
The input data for a program execution have to be in JSON format
|
||||||
and the following fields are required
|
and the following fields are required
|
||||||
|
@ -161,21 +195,6 @@ and the following fields are required
|
||||||
"instruction_data": [31, 32, 23, 24]
|
"instruction_data": [31, 32, 23, 24]
|
||||||
}
|
}
|
||||||
"##,
|
"##,
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("PROGRAM")
|
|
||||||
.help(
|
|
||||||
"Program file to use. This is either an ELF shared-object file to be executed, \
|
|
||||||
or an assembly file to be assembled and executed.",
|
|
||||||
)
|
|
||||||
.required(true)
|
|
||||||
.index(1)
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("input")
|
|
||||||
.help(
|
|
||||||
"Input for the program to run on, where FILE is a name of a JSON file \
|
|
||||||
with input data, or BYTES is the number of 0-valued bytes to allocate for program parameters",
|
|
||||||
)
|
)
|
||||||
.short("i")
|
.short("i")
|
||||||
.long("input")
|
.long("input")
|
||||||
|
@ -183,6 +202,7 @@ with input data, or BYTES is the number of 0-valued bytes to allocate for progra
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.default_value("0"),
|
.default_value("0"),
|
||||||
)
|
)
|
||||||
|
.arg(&max_genesis_arg)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("memory")
|
Arg::with_name("memory")
|
||||||
.help("Heap memory for the program to run on")
|
.help("Heap memory for the program to run on")
|
||||||
|
@ -193,19 +213,18 @@ with input data, or BYTES is the number of 0-valued bytes to allocate for progra
|
||||||
.default_value("0"),
|
.default_value("0"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("use")
|
Arg::with_name("mode")
|
||||||
.help(
|
.help(
|
||||||
"Method of execution to use, where 'cfg' generates Control Flow Graph \
|
"Mode of execution, where 'interpreter' runs \
|
||||||
of the program, 'disassembler' dumps disassembled code of the program, 'interpreter' runs \
|
the program in the virtual machine's interpreter, 'debugger' is the same as 'interpreter' \
|
||||||
the program in the virtual machine's interpreter, 'debugger' is the same as 'interpreter' \
|
but hosts a GDB interface, and 'jit' precompiles the program to native machine code \
|
||||||
but hosts a GDB interface, and 'jit' precompiles the program to native machine code \
|
before execting it in the virtual machine.",
|
||||||
before execting it in the virtual machine.",
|
|
||||||
)
|
)
|
||||||
.short("u")
|
.short("e")
|
||||||
.long("use")
|
.long("mode")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("VALUE")
|
.value_name("VALUE")
|
||||||
.possible_values(&["cfg", "disassembler", "interpreter", "debugger", "jit"])
|
.possible_values(&["interpreter", "debugger", "jit"])
|
||||||
.default_value("jit"),
|
.default_value("jit"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -216,14 +235,6 @@ before execting it in the virtual machine.",
|
||||||
.value_name("COUNT")
|
.value_name("COUNT")
|
||||||
.default_value("9223372036854775807"),
|
.default_value("9223372036854775807"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("max_genesis_archive_unpacked_size")
|
|
||||||
.long("max-genesis-archive-unpacked-size")
|
|
||||||
.value_name("NUMBER")
|
|
||||||
.takes_value(true)
|
|
||||||
.default_value("10485760")
|
|
||||||
.help("maximum total uncompressed size of unpacked genesis archive")
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("port")
|
Arg::with_name("port")
|
||||||
.help("Port to use for the connection with a remote debugger")
|
.help("Port to use for the connection with a remote debugger")
|
||||||
|
@ -240,6 +251,8 @@ before execting it in the virtual machine.",
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("FILE"),
|
.value_name("FILE"),
|
||||||
)
|
)
|
||||||
|
.arg(&program_arg)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,7 +324,18 @@ fn output_trace(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
pub fn program(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
||||||
|
enum Action {
|
||||||
|
Cfg,
|
||||||
|
Dis,
|
||||||
|
Run,
|
||||||
|
}
|
||||||
|
let (action, matches) = match matches.subcommand() {
|
||||||
|
("cfg", Some(arg_matches)) => (Action::Cfg, arg_matches),
|
||||||
|
("disassembler", Some(arg_matches)) => (Action::Dis, arg_matches),
|
||||||
|
("run", Some(arg_matches)) => (Action::Run, arg_matches),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
let bank = load_blockstore(ledger_path, matches);
|
let bank = load_blockstore(ledger_path, matches);
|
||||||
let loader_id = bpf_loader_upgradeable::id();
|
let loader_id = bpf_loader_upgradeable::id();
|
||||||
let mut transaction_accounts = Vec::new();
|
let mut transaction_accounts = Vec::new();
|
||||||
|
@ -410,7 +434,7 @@ pub fn run(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
||||||
program_id, // ID of the loaded program. It can modify accounts with the same owner key
|
program_id, // ID of the loaded program. It can modify accounts with the same owner key
|
||||||
AccountSharedData::new(0, 0, &loader_id),
|
AccountSharedData::new(0, 0, &loader_id),
|
||||||
));
|
));
|
||||||
let interpreted = matches.value_of("use").unwrap() != "jit";
|
let interpreted = matches.value_of("mode").unwrap() != "jit";
|
||||||
with_mock_invoke_context!(
|
with_mock_invoke_context!(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
transaction_context,
|
transaction_context,
|
||||||
|
@ -516,8 +540,8 @@ pub fn run(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
||||||
verified_executable.jit_compile().unwrap();
|
verified_executable.jit_compile().unwrap();
|
||||||
let mut analysis = LazyAnalysis::new(verified_executable.get_executable());
|
let mut analysis = LazyAnalysis::new(verified_executable.get_executable());
|
||||||
|
|
||||||
match matches.value_of("use") {
|
match action {
|
||||||
Some("cfg") => {
|
Action::Cfg => {
|
||||||
let mut file = File::create("cfg.dot").unwrap();
|
let mut file = File::create("cfg.dot").unwrap();
|
||||||
analysis
|
analysis
|
||||||
.analyze()
|
.analyze()
|
||||||
|
@ -525,13 +549,14 @@ pub fn run(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some("disassembler") => {
|
Action::Dis => {
|
||||||
let stdout = std::io::stdout();
|
let stdout = std::io::stdout();
|
||||||
analysis.analyze().disassemble(&mut stdout.lock()).unwrap();
|
analysis.analyze().disassemble(&mut stdout.lock()).unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
};
|
||||||
|
|
||||||
create_vm!(
|
create_vm!(
|
||||||
vm,
|
vm,
|
||||||
&verified_executable,
|
&verified_executable,
|
||||||
|
@ -541,7 +566,7 @@ pub fn run(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
||||||
);
|
);
|
||||||
let mut vm = vm.unwrap();
|
let mut vm = vm.unwrap();
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
if matches.value_of("use").unwrap() == "debugger" {
|
if matches.value_of("mode").unwrap() == "debugger" {
|
||||||
vm.debug_port = Some(matches.value_of("port").unwrap().parse::<u16>().unwrap());
|
vm.debug_port = Some(matches.value_of("port").unwrap().parse::<u16>().unwrap());
|
||||||
}
|
}
|
||||||
let (instruction_count, result) = vm.execute_program(interpreted);
|
let (instruction_count, result) = vm.execute_program(interpreted);
|
Loading…
Reference in New Issue