From 8b25c970878e80b628c9d09fd2c27f1b0db84dd8 Mon Sep 17 00:00:00 2001 From: Luis Aguilar Date: Wed, 24 Apr 2024 12:25:47 -0600 Subject: [PATCH 1/5] enable resuming a specific pending etching --- src/subcommand/wallet/resume.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/subcommand/wallet/resume.rs b/src/subcommand/wallet/resume.rs index 3cea3f0fa4..2ca0bda02c 100644 --- a/src/subcommand/wallet/resume.rs +++ b/src/subcommand/wallet/resume.rs @@ -8,6 +8,9 @@ pub struct ResumeOutput { pub(crate) struct Resume { #[arg(long, help = "Don't broadcast transactions.")] pub(crate) dry_run: bool, + + #[arg(long, help = "Rune commitment to resume.")] + pub(crate) commitment: Option, } impl Resume { @@ -18,7 +21,26 @@ impl Resume { break; } - for (rune, entry) in wallet.pending_etchings()? { + let mut pending_etchings = Vec::new(); + let commitment = self.commitment.clone(); + + if let Some(commitment) = commitment { + let pending_etching = wallet + .pending_etchings()? + .into_iter() + .find(|(_, entry)| entry.commit.txid().to_string() == commitment); + + ensure!( + pending_etching.is_some(), + "commitment `{commitment}` does not correspond to any pending rune etching." + ); + + pending_etchings.push(pending_etching.unwrap()); + } else { + pending_etchings.extend(wallet.pending_etchings()?.into_iter()); + } + + for (rune, entry) in pending_etchings { if self.dry_run { etchings.push(batch::Output { reveal_broadcast: false, From 4a7ad7a030a98b10dd1c8de3430824ab2024d683 Mon Sep 17 00:00:00 2001 From: Luis Aguilar Date: Mon, 6 May 2024 16:31:36 -0600 Subject: [PATCH 2/5] resume by rune name instead of commitment --- src/subcommand/wallet/resume.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/subcommand/wallet/resume.rs b/src/subcommand/wallet/resume.rs index d2b1634ba2..daecd844bf 100644 --- a/src/subcommand/wallet/resume.rs +++ b/src/subcommand/wallet/resume.rs @@ -8,9 +8,8 @@ pub struct ResumeOutput { pub(crate) struct Resume { #[arg(long, help = "Don't broadcast transactions.")] pub(crate) dry_run: bool, - - #[arg(long, help = "Rune commitment to resume.")] - pub(crate) commitment: Option, + #[arg(long, value_name = "PENDING•RUNE", help = "Rune to resume (spaced).")] + pub(crate) rune: Option, } impl Resume { @@ -22,22 +21,22 @@ impl Resume { } let mut pending_etchings = Vec::new(); - let commitment = self.commitment.clone(); + let spaced_rune = self.rune.clone(); - if let Some(commitment) = commitment { + if let Some(spaced_rune) = spaced_rune { let pending_etching = wallet .pending_etchings()? .into_iter() - .find(|(_, entry)| entry.commit.txid().to_string() == commitment); + .find(|(rune, _)| *rune == spaced_rune.rune); ensure!( pending_etching.is_some(), - "commitment `{commitment}` does not correspond to any pending rune etching." + "rune `{spaced_rune}` does not correspond to any pending etching." ); pending_etchings.push(pending_etching.unwrap()); } else { - pending_etchings.extend(wallet.pending_etchings()?.into_iter()); + pending_etchings.extend(wallet.pending_etchings()?); } for (rune, entry) in pending_etchings { From d277e79ba834a5704e6a312a7293cef27759765b Mon Sep 17 00:00:00 2001 From: Luis Aguilar Date: Tue, 7 May 2024 11:48:36 -0600 Subject: [PATCH 3/5] simplified resume etching --- src/subcommand/wallet/resume.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/subcommand/wallet/resume.rs b/src/subcommand/wallet/resume.rs index daecd844bf..0212b5b262 100644 --- a/src/subcommand/wallet/resume.rs +++ b/src/subcommand/wallet/resume.rs @@ -8,7 +8,7 @@ pub struct ResumeOutput { pub(crate) struct Resume { #[arg(long, help = "Don't broadcast transactions.")] pub(crate) dry_run: bool, - #[arg(long, value_name = "PENDING•RUNE", help = "Rune to resume (spaced).")] + #[arg(long, help = "Rune to resume.")] pub(crate) rune: Option, } @@ -20,24 +20,21 @@ impl Resume { break; } - let mut pending_etchings = Vec::new(); - let spaced_rune = self.rune.clone(); + let spaced_rune = self.rune; - if let Some(spaced_rune) = spaced_rune { + let pending_etchings = if let Some(spaced_rune) = spaced_rune { let pending_etching = wallet - .pending_etchings()? - .into_iter() - .find(|(rune, _)| *rune == spaced_rune.rune); + .load_etching(spaced_rune.rune)?; ensure!( pending_etching.is_some(), "rune `{spaced_rune}` does not correspond to any pending etching." ); - pending_etchings.push(pending_etching.unwrap()); + vec![(spaced_rune.rune, pending_etching.unwrap())] } else { - pending_etchings.extend(wallet.pending_etchings()?); - } + wallet.pending_etchings()? + }; for (rune, entry) in pending_etchings { if self.dry_run { From f37026a4e4c9ac6bd397c6d46c2667999dfb549d Mon Sep 17 00:00:00 2001 From: Luis Aguilar Date: Sun, 12 May 2024 14:43:59 -0600 Subject: [PATCH 4/5] Add wallet resume integration tests --- src/subcommand/wallet/resume.rs | 2 +- tests/wallet/resume.rs | 244 +++++++++++++++----------------- 2 files changed, 116 insertions(+), 130 deletions(-) diff --git a/src/subcommand/wallet/resume.rs b/src/subcommand/wallet/resume.rs index 0212b5b262..dc0ad8ec3e 100644 --- a/src/subcommand/wallet/resume.rs +++ b/src/subcommand/wallet/resume.rs @@ -28,7 +28,7 @@ impl Resume { ensure!( pending_etching.is_some(), - "rune `{spaced_rune}` does not correspond to any pending etching." + "rune {spaced_rune} does not correspond to any pending etching." ); vec![(spaced_rune.rune, pending_etching.unwrap())] diff --git a/tests/wallet/resume.rs b/tests/wallet/resume.rs index 3658b789e8..ce729b9c22 100644 --- a/tests/wallet/resume.rs +++ b/tests/wallet/resume.rs @@ -6,17 +6,8 @@ use { }, }; -#[test] -fn wallet_resume() { - let core = mockcore::builder().network(Network::Regtest).build(); - - let ord = TestServer::spawn_with_server_args(&core, &["--regtest", "--index-runes"], &[]); - - create_wallet(&core, &ord); - - core.mine_blocks(1); - - let batchfile = batch::File { +fn get_batchfile() -> batch::File { + batch::File { etching: Some(batch::Etching { divisibility: 0, rune: SpacedRune { @@ -33,53 +24,66 @@ fn wallet_resume() { ..default() }], ..default() - }; + } +} - let tempdir = Arc::new(TempDir::new().unwrap()); +fn inscribe_batch(batchfile: &batch::File, tempdir: &Arc, core: &mockcore::Handle, ord: &TestServer) { + let mut spawn = + CommandBuilder::new("--regtest --index-runes wallet batch --fee-rate 0 --batch batch.yaml") + .temp_dir(tempdir.clone()) + .write("batch.yaml", serde_yaml::to_string(&batchfile).unwrap()) + .write("inscription.jpeg", "inscription") + .core(core) + .ord(ord) + .expected_exit_code(1) + .spawn(); + + let mut buffer = String::new(); - { - let mut spawn = - CommandBuilder::new("--regtest --index-runes wallet batch --fee-rate 0 --batch batch.yaml") - .temp_dir(tempdir.clone()) - .write("batch.yaml", serde_yaml::to_string(&batchfile).unwrap()) - .write("inscription.jpeg", "inscription") - .core(&core) - .ord(&ord) - .expected_exit_code(1) - .spawn(); - - let mut buffer = String::new(); - - BufReader::new(spawn.child.stderr.as_mut().unwrap()) - .read_line(&mut buffer) - .unwrap(); - - assert_regex_match!( - buffer, - "Waiting for rune AAAAAAAAAAAAA commitment [[:xdigit:]]{64} to mature…\n" - ); - - core.mine_blocks(1); - - signal::kill( - Pid::from_raw(spawn.child.id().try_into().unwrap()), - Signal::SIGINT, - ) + BufReader::new(spawn.child.stderr.as_mut().unwrap()) + .read_line(&mut buffer) .unwrap(); - buffer.clear(); + assert_regex_match!( + buffer, + "Waiting for rune AAAAAAAAAAAAA commitment [[:xdigit:]]{64} to mature…\n" + ); - BufReader::new(spawn.child.stderr.as_mut().unwrap()) - .read_line(&mut buffer) - .unwrap(); + core.mine_blocks(1); - assert_eq!( - buffer, - "Shutting down gracefully. Press again to shutdown immediately.\n" - ); + signal::kill( + Pid::from_raw(spawn.child.id().try_into().unwrap()), + Signal::SIGINT, + ) + .unwrap(); - spawn.child.wait().unwrap(); - } + buffer.clear(); + + BufReader::new(spawn.child.stderr.as_mut().unwrap()) + .read_line(&mut buffer) + .unwrap(); + + assert_eq!( + buffer, + "Shutting down gracefully. Press again to shutdown immediately.\n" + ); + + spawn.child.wait().unwrap(); +} + +#[test] +fn wallet_resume() { + let core = mockcore::builder().network(Network::Regtest).build(); + let ord = TestServer::spawn_with_server_args(&core, &["--regtest", "--index-runes"], &[]); + + create_wallet(&core, &ord); + + core.mine_blocks(1); + + let batchfile = get_batchfile(); + let tempdir = Arc::new(TempDir::new().unwrap()); + + inscribe_batch(&batchfile, &tempdir, &core, &ord); core.mine_blocks(6); @@ -106,79 +110,79 @@ fn wallet_resume() { } #[test] -fn resume_suspended() { +fn wallet_resume_by_rune() { let core = mockcore::builder().network(Network::Regtest).build(); - let ord = TestServer::spawn_with_server_args(&core, &["--regtest", "--index-runes"], &[]); create_wallet(&core, &ord); core.mine_blocks(1); - let batchfile = batch::File { - etching: Some(batch::Etching { - divisibility: 0, - rune: SpacedRune { - rune: Rune(RUNE), - spacers: 0, - }, - supply: "1000".parse().unwrap(), - premine: "1000".parse().unwrap(), - symbol: '¢', - ..default() - }), - inscriptions: vec![batch::Entry { - file: Some("inscription.jpeg".into()), - ..default() - }], - ..default() - }; + let batchfile = get_batchfile(); + let tempdir = Arc::new(TempDir::new().unwrap()); + + inscribe_batch(&batchfile, &tempdir, &core, &ord); + + core.mine_blocks(6); + + let output = CommandBuilder::new("--regtest --index-runes wallet resume --rune AAAAAAAAAAAAA") + .temp_dir(tempdir) + .core(&core) + .ord(&ord) + .run_and_deserialize_output::(); + + assert_eq!( + output + .etchings + .first() + .unwrap() + .rune + .clone() + .unwrap() + .rune + .rune, + Rune(RUNE) + ); + + assert!(output.etchings.first().unwrap().reveal_broadcast); +} + +#[test] +fn wallet_resume_by_rune_not_found() { + let core = mockcore::builder().network(Network::Regtest).build(); + let ord = TestServer::spawn_with_server_args(&core, &["--regtest", "--index-runes"], &[]); + + create_wallet(&core, &ord); + core.mine_blocks(1); + + let batchfile = get_batchfile(); let tempdir = Arc::new(TempDir::new().unwrap()); - { - let mut spawn = - CommandBuilder::new("--regtest --index-runes wallet batch --fee-rate 0 --batch batch.yaml") - .temp_dir(tempdir.clone()) - .write("batch.yaml", serde_yaml::to_string(&batchfile).unwrap()) - .write("inscription.jpeg", "inscription") - .core(&core) - .ord(&ord) - .expected_exit_code(1) - .spawn(); - - let mut buffer = String::new(); - - BufReader::new(spawn.child.stderr.as_mut().unwrap()) - .read_line(&mut buffer) - .unwrap(); - - assert_regex_match!( - buffer, - "Waiting for rune AAAAAAAAAAAAA commitment [[:xdigit:]]{64} to mature…\n" - ); - - core.mine_blocks(1); - - signal::kill( - Pid::from_raw(spawn.child.id().try_into().unwrap()), - Signal::SIGINT, - ) - .unwrap(); + inscribe_batch(&batchfile, &tempdir, &core, &ord); + + core.mine_blocks(6); + + CommandBuilder::new("--regtest --index-runes wallet resume --rune BBBBBBBBBBBBB") + .temp_dir(tempdir) + .core(&core) + .ord(&ord) + .expected_stderr("error: rune BBBBBBBBBBBBB does not correspond to any pending etching."); +} - buffer.clear(); +#[test] +fn resume_suspended() { + let core = mockcore::builder().network(Network::Regtest).build(); + let ord = TestServer::spawn_with_server_args(&core, &["--regtest", "--index-runes"], &[]); - BufReader::new(spawn.child.stderr.as_mut().unwrap()) - .read_line(&mut buffer) - .unwrap(); + create_wallet(&core, &ord); - assert_eq!( - buffer, - "Shutting down gracefully. Press again to shutdown immediately.\n" - ); + core.mine_blocks(1); - spawn.child.wait().unwrap(); - } + let batchfile = get_batchfile(); + let tempdir = Arc::new(TempDir::new().unwrap()); + + inscribe_batch(&batchfile, &tempdir, &core, &ord); let mut spawn = CommandBuilder::new("--regtest --index-runes wallet resume") .temp_dir(tempdir) @@ -216,25 +220,7 @@ fn commitment_output_is_locked() { core.mine_blocks(1); - let batchfile = batch::File { - etching: Some(batch::Etching { - divisibility: 0, - rune: SpacedRune { - rune: Rune(RUNE), - spacers: 0, - }, - supply: "1000".parse().unwrap(), - premine: "1000".parse().unwrap(), - symbol: '¢', - ..default() - }), - inscriptions: vec![batch::Entry { - file: Some("inscription.jpeg".into()), - ..default() - }], - ..default() - }; - + let batchfile = get_batchfile(); let tempdir = Arc::new(TempDir::new().unwrap()); let mut spawn = From 16c47d53b76a7eb14a9366df3d048c01edf56248 Mon Sep 17 00:00:00 2001 From: raphjaph Date: Fri, 17 May 2024 17:27:13 +0200 Subject: [PATCH 5/5] small things --- src/subcommand/wallet/resume.rs | 5 ++--- tests/wallet/resume.rs | 9 +++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/subcommand/wallet/resume.rs b/src/subcommand/wallet/resume.rs index dc0ad8ec3e..8e95171e5c 100644 --- a/src/subcommand/wallet/resume.rs +++ b/src/subcommand/wallet/resume.rs @@ -8,7 +8,7 @@ pub struct ResumeOutput { pub(crate) struct Resume { #[arg(long, help = "Don't broadcast transactions.")] pub(crate) dry_run: bool, - #[arg(long, help = "Rune to resume.")] + #[arg(long, help = "Pending etching to resume.")] pub(crate) rune: Option, } @@ -23,8 +23,7 @@ impl Resume { let spaced_rune = self.rune; let pending_etchings = if let Some(spaced_rune) = spaced_rune { - let pending_etching = wallet - .load_etching(spaced_rune.rune)?; + let pending_etching = wallet.load_etching(spaced_rune.rune)?; ensure!( pending_etching.is_some(), diff --git a/tests/wallet/resume.rs b/tests/wallet/resume.rs index ce729b9c22..6d1b632f19 100644 --- a/tests/wallet/resume.rs +++ b/tests/wallet/resume.rs @@ -27,7 +27,12 @@ fn get_batchfile() -> batch::File { } } -fn inscribe_batch(batchfile: &batch::File, tempdir: &Arc, core: &mockcore::Handle, ord: &TestServer) { +fn inscribe_batch( + batchfile: &batch::File, + tempdir: &Arc, + core: &mockcore::Handle, + ord: &TestServer, +) { let mut spawn = CommandBuilder::new("--regtest --index-runes wallet batch --fee-rate 0 --batch batch.yaml") .temp_dir(tempdir.clone()) @@ -110,7 +115,7 @@ fn wallet_resume() { } #[test] -fn wallet_resume_by_rune() { +fn wallet_resume_by_rune_name() { let core = mockcore::builder().network(Network::Regtest).build(); let ord = TestServer::spawn_with_server_args(&core, &["--regtest", "--index-runes"], &[]);