diff --git a/.changelog/unreleased/features/973-namada-start-time.md b/.changelog/unreleased/features/973-namada-start-time.md new file mode 100644 index 0000000000..4a43cfeb12 --- /dev/null +++ b/.changelog/unreleased/features/973-namada-start-time.md @@ -0,0 +1,2 @@ +- Add a --time argument to the node to specify the time the node should start. + ([#973](https://github.com/anoma/namada/pull/973)) \ No newline at end of file diff --git a/apps/src/bin/namada-node/cli.rs b/apps/src/bin/namada-node/cli.rs index 48f67d3273..b9048ea312 100644 --- a/apps/src/bin/namada-node/cli.rs +++ b/apps/src/bin/namada-node/cli.rs @@ -1,6 +1,7 @@ //! Namada node CLI. use eyre::{Context, Result}; +use namada::types::time::Utc; use namada_apps::cli::{self, cmds}; use namada_apps::node::ledger; @@ -11,8 +12,25 @@ pub fn main() -> Result<()> { } match cmd { cmds::NamadaNode::Ledger(sub) => match sub { - cmds::Ledger::Run(_) => { + cmds::Ledger::Run(cmds::LedgerRun(args)) => { let wasm_dir = ctx.wasm_dir(); + + // Sleep until start time if needed + if let Some(time) = args.0 { + if let Ok(sleep_time) = + time.0.signed_duration_since(Utc::now()).to_std() + { + if !sleep_time.is_zero() { + tracing::info!( + "Waiting ledger start time: {:?}, time left: \ + {:?}", + time, + sleep_time + ); + std::thread::sleep(sleep_time) + } + } + } ledger::run(ctx.config.ledger, wasm_dir); } cmds::Ledger::Reset(_) => { diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index aa240b704b..08d6dfe722 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -766,7 +766,7 @@ pub mod cmds { let reset = SubCmd::parse(matches).map(Self::Reset); run.or(reset) // The `run` command is the default if no sub-command given - .or(Some(Self::Run(LedgerRun))) + .or(Some(Self::Run(LedgerRun(args::LedgerRun(None))))) }) } @@ -782,17 +782,21 @@ pub mod cmds { } #[derive(Clone, Debug)] - pub struct LedgerRun; + pub struct LedgerRun(pub args::LedgerRun); impl SubCmd for LedgerRun { const CMD: &'static str = "run"; fn parse(matches: &ArgMatches) -> Option { - matches.subcommand_matches(Self::CMD).map(|_matches| Self) + matches + .subcommand_matches(Self::CMD) + .map(|matches| Self(args::LedgerRun::parse(matches))) } fn def() -> App { - App::new(Self::CMD).about("Run Namada ledger node.") + App::new(Self::CMD) + .about("Run Namada ledger node.") + .add_args::() } } @@ -1519,6 +1523,7 @@ pub mod args { use namada::types::key::*; use namada::types::masp::MaspValue; use namada::types::storage::{self, Epoch}; + use namada::types::time::DateTimeUtc; use namada::types::token; use namada::types::transaction::GasLimit; use rust_decimal::Decimal; @@ -1590,6 +1595,7 @@ pub mod args { arg("max-commission-rate-change"); const MODE: ArgOpt = arg_opt("mode"); const NET_ADDRESS: Arg = arg("net-address"); + const NAMADA_START_TIME: ArgOpt = arg_opt("time"); const NO_CONVERSIONS: ArgFlag = flag("no-conversions"); const OWNER: ArgOpt = arg_opt("owner"); const PIN: ArgFlag = flag("pin"); @@ -1686,6 +1692,24 @@ pub mod args { } } + #[derive(Clone, Debug)] + pub struct LedgerRun(pub Option); + + impl Args for LedgerRun { + fn parse(matches: &ArgMatches) -> Self { + let time = NAMADA_START_TIME.parse(matches); + Self(time) + } + + fn def(app: App) -> App { + app.arg( + NAMADA_START_TIME + .def() + .about("The start time of the ledger."), + ) + } + } + /// Transaction associated results arguments #[derive(Clone, Debug)] pub struct QueryResult { diff --git a/core/src/types/time.rs b/core/src/types/time.rs index a508501d94..7288d88bab 100644 --- a/core/src/types/time.rs +++ b/core/src/types/time.rs @@ -3,8 +3,10 @@ use std::convert::{TryFrom, TryInto}; use std::fmt::Display; use std::ops::{Add, Sub}; +use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use chrono::ParseError; pub use chrono::{DateTime, Duration, TimeZone, Utc}; /// Check if the given `duration` has passed since the given `start. @@ -109,6 +111,14 @@ impl DateTimeUtc { } } +impl FromStr for DateTimeUtc { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + Ok(Self(s.parse::>()?)) + } +} + impl Add for DateTimeUtc { type Output = DateTimeUtc;