From 361bf28fcc1d1abab1a2f0b10b0c54fd7440042a Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 10 Aug 2022 13:26:43 -0400 Subject: [PATCH 01/13] Add wallet identify subcommand --- src/subcommand/wallet.rs | 3 +++ src/subcommand/wallet/identify.rs | 19 ++++++++++++++++ tests/wallet.rs | 37 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 src/subcommand/wallet/identify.rs diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs index 6804e25211..021080825c 100644 --- a/src/subcommand/wallet.rs +++ b/src/subcommand/wallet.rs @@ -2,6 +2,7 @@ use super::*; mod balance; mod fund; +mod identify; mod init; mod utxos; @@ -57,6 +58,7 @@ fn get_wallet(options: Options) -> Result> { pub(crate) enum Wallet { Balance, Fund, + Identify, Init, Utxos, } @@ -66,6 +68,7 @@ impl Wallet { match self { Self::Balance => balance::run(options), Self::Fund => fund::run(options), + Self::Identify => identify::run(options), Self::Init => init::run(options), Self::Utxos => utxos::run(options), } diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs new file mode 100644 index 0000000000..e1692b09cf --- /dev/null +++ b/src/subcommand/wallet/identify.rs @@ -0,0 +1,19 @@ +use super::*; + +pub(crate) fn run(options: Options) -> Result { + let index = Index::index(&options)?; + + let ranges = get_wallet(options)? + .list_unspent()? + .iter() + .map(|utxo| index.list(utxo.outpoint)) + .collect::>>, _>>()?; + + for range in ranges.into_iter().flatten() { + for (start, end) in range { + println!("[{}, {})", start, end); + } + } + + Ok(()) +} diff --git a/tests/wallet.rs b/tests/wallet.rs index bea1d48f65..e081912f8f 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -184,3 +184,40 @@ fn balance() { .expected_stdout("5000000000\n") .run() } + +#[test] +fn identify() { + let state = Test::new() + .command("--network regtest wallet init") + .expected_status(0) + .expected_stderr("Wallet initialized.\n") + .output() + .state; + + let output = Test::with_state(state) + .command("--network regtest wallet fund") + .stdout_regex("^bcrt1.*\n") + .output(); + + output + .state + .client + .generate_to_address( + 101, + &Address::from_str( + output + .stdout + .strip_suffix('\n') + .ok_or("Failed to strip suffix") + .unwrap(), + ) + .unwrap(), + ) + .unwrap(); + + Test::with_state(output.state) + .command("--network regtest wallet identify") + .expected_status(0) + .expected_stdout("[5000000000, 10000000000)\n") + .run() +} From af07421f640774c1d6fd62df69d7d71173587030 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 19 Aug 2022 16:56:11 -0400 Subject: [PATCH 02/13] Use purse --- src/subcommand/wallet/identify.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index e1692b09cf..4cafdc671f 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -3,15 +3,25 @@ use super::*; pub(crate) fn run(options: Options) -> Result { let index = Index::index(&options)?; - let ranges = get_wallet(options)? + let ranges = Purse::load(&options)? + .wallet .list_unspent()? .iter() .map(|utxo| index.list(utxo.outpoint)) - .collect::>>, _>>()?; + .collect::>, _>>()?; for range in ranges.into_iter().flatten() { - for (start, end) in range { - println!("[{}, {})", start, end); + match range { + List::Unspent(range) => { + for (start, end) in range { + println!("[{}, {})", start, end); + } + } + List::Spent(txid) => { + return Err(anyhow!( + "UTXO unspent in wallet but spent in index by transaction {txid}" + )) + } } } From a198b97a5694d5a1d3e8c3758e2181f4e9b7ba44 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 19 Aug 2022 17:53:02 -0400 Subject: [PATCH 03/13] Generate 1 block in test --- tests/wallet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wallet.rs b/tests/wallet.rs index 63eaa37804..e3d6d20a81 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -207,7 +207,7 @@ fn identify() { .state .client .generate_to_address( - 101, + 1, &Address::from_str( output .stdout From 6178cdad42ab8d738efbabf9385d365096ccbb2a Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 19 Aug 2022 19:57:04 -0400 Subject: [PATCH 04/13] Check starting ordinal --- src/subcommand/wallet/identify.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index 4cafdc671f..3dfbbc4ca3 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -3,18 +3,24 @@ use super::*; pub(crate) fn run(options: Options) -> Result { let index = Index::index(&options)?; - let ranges = Purse::load(&options)? - .wallet - .list_unspent()? + let utxos = Purse::load(&options)?.wallet.list_unspent()?; + + let ranges = utxos .iter() .map(|utxo| index.list(utxo.outpoint)) .collect::>, _>>()?; - for range in ranges.into_iter().flatten() { + for (utxo, range) in utxos.iter().zip(ranges.into_iter().flatten()) { + println!("{}", utxo.outpoint); + match range { List::Unspent(range) => { - for (start, end) in range { - println!("[{}, {})", start, end); + for (start, _) in range { + let ordinal = Ordinal(start); + + if ordinal.rarity() != "common" { + println!("{ordinal}"); + } } } List::Spent(txid) => { From 791d14ce681c863047b97b98c602dc9512233125 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 19 Aug 2022 20:12:14 -0400 Subject: [PATCH 05/13] Test it --- src/subcommand/wallet/identify.rs | 6 ++++-- tests/wallet.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index 3dfbbc4ca3..f07a7a9148 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -18,8 +18,10 @@ pub(crate) fn run(options: Options) -> Result { for (start, _) in range { let ordinal = Ordinal(start); - if ordinal.rarity() != "common" { - println!("{ordinal}"); + let rarity = ordinal.rarity(); + + if rarity != "common" { + println!("{ordinal} - {rarity}"); } } } diff --git a/tests/wallet.rs b/tests/wallet.rs index e3d6d20a81..433a0a5bf3 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -222,7 +222,7 @@ fn identify() { Test::with_state(output.state) .command("--network regtest wallet identify") .expected_status(0) - .expected_stdout("[5000000000, 10000000000)\n") + .stdout_regex("[[:xdigit:]]{64}:[[:digit:]]\n5000000000 - uncommon\n") .run() } From 03cd3d82d3868f3345de9dd6f99c275be9204dfd Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Aug 2022 11:33:29 -0400 Subject: [PATCH 06/13] Different format --- src/subcommand/wallet/identify.rs | 14 +++++++------- tests/wallet.rs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index f07a7a9148..da7410cc6f 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -10,26 +10,26 @@ pub(crate) fn run(options: Options) -> Result { .map(|utxo| index.list(utxo.outpoint)) .collect::>, _>>()?; - for (utxo, range) in utxos.iter().zip(ranges.into_iter().flatten()) { - println!("{}", utxo.outpoint); - + for (utxo, range) in utxos.iter().zip(ranges.into_iter()) { match range { - List::Unspent(range) => { + Some(List::Unspent(range)) => { for (start, _) in range { let ordinal = Ordinal(start); let rarity = ordinal.rarity(); if rarity != "common" { - println!("{ordinal} - {rarity}"); + println!("{ordinal} {rarity} {}", utxo.outpoint); } } } - List::Spent(txid) => { + Some(List::Spent(txid)) => { return Err(anyhow!( - "UTXO unspent in wallet but spent in index by transaction {txid}" + "UTXO {} unspent in wallet but spent in index by transaction {txid}", + utxo.outpoint )) } + None => {} } } diff --git a/tests/wallet.rs b/tests/wallet.rs index 433a0a5bf3..a5740e9d10 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -222,7 +222,7 @@ fn identify() { Test::with_state(output.state) .command("--network regtest wallet identify") .expected_status(0) - .stdout_regex("[[:xdigit:]]{64}:[[:digit:]]\n5000000000 - uncommon\n") + .stdout_regex("5000000000 uncommon [[:xdigit:]]{64}:[[:digit:]]\n") .run() } From bd5cad203608f04f2554207d8e83e500a0f2c8f7 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Aug 2022 13:21:56 -0400 Subject: [PATCH 07/13] Add more tests --- src/subcommand/wallet/identify.rs | 12 +-- tests/wallet.rs | 143 +++++++++++++++++++++++++++++- 2 files changed, 148 insertions(+), 7 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index da7410cc6f..9225c71569 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -3,14 +3,14 @@ use super::*; pub(crate) fn run(options: Options) -> Result { let index = Index::index(&options)?; - let utxos = Purse::load(&options)?.wallet.list_unspent()?; - - let ranges = utxos + let ranges = Purse::load(&options)? + .wallet + .list_unspent()? .iter() - .map(|utxo| index.list(utxo.outpoint)) - .collect::>, _>>()?; + .map(|utxo| (utxo.clone(), index.list(utxo.outpoint).unwrap())) + .collect::)>>(); - for (utxo, range) in utxos.iter().zip(ranges.into_iter()) { + for (utxo, range) in ranges { match range { Some(List::Unspent(range)) => { for (start, _) in range { diff --git a/tests/wallet.rs b/tests/wallet.rs index a5740e9d10..49dec15127 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -190,7 +190,7 @@ fn balance() { } #[test] -fn identify() { +fn identify_single_ordinal() { let state = Test::new() .command("--network regtest wallet init") .expected_status(0) @@ -226,6 +226,147 @@ fn identify() { .run() } +#[test] +fn identify_multiple_ordinals() { + let state = Test::new() + .command("--network regtest wallet init") + .expected_status(0) + .expected_stderr("Wallet initialized.\n") + .output() + .state; + + let output = Test::with_state(state) + .command("--network regtest wallet fund") + .stdout_regex("^bcrt1.*\n") + .output(); + + output + .state + .client + .generate_to_address( + 5, + &Address::from_str( + output + .stdout + .strip_suffix('\n') + .ok_or("Failed to strip suffix") + .unwrap(), + ) + .unwrap(), + ) + .unwrap(); + + Test::with_state(output.state) + .command("--network regtest wallet identify") + .expected_status(0) + .stdout_regex( + " + 5000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] + 15000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] + 20000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] + 25000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] + 10000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] + " + .unindent() + .trim_start(), + ) + .run() +} + +#[test] +fn identify_sent_ordinal() { + let state = Test::new() + .command("--network regtest wallet init") + .expected_status(0) + .expected_stderr("Wallet initialized.\n") + .output() + .state; + + let output = Test::with_state(state) + .command("--network regtest wallet fund") + .stdout_regex("^bcrt1.*\n") + .output(); + + let from_address = Address::from_str( + output + .stdout + .strip_suffix('\n') + .ok_or("Failed to strip suffix") + .unwrap(), + ) + .unwrap(); + + output + .state + .client + .generate_to_address(1, &from_address) + .unwrap(); + + output + .state + .client + .generate_to_address( + 100, + &Address::from_str("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw").unwrap(), + ) + .unwrap(); + + let output = Test::with_state(output.state) + .command("--network regtest wallet utxos") + .expected_status(0) + .stdout_regex("[[:xdigit:]]{64}:[[:digit:]] 5000000000\n") + .output(); + + let wallet = Wallet::new( + Bip84( + ( + Mnemonic::parse("book fit fly ketchup also elevator scout mind edit fatal where rookie") + .unwrap(), + None, + ), + KeychainKind::External, + ), + None, + Network::Regtest, + MemoryDatabase::new(), + ) + .unwrap(); + + let to_address = wallet.get_address(AddressIndex::LastUnused).unwrap(); + + let state = Test::with_state(output.state) + .command(&format!( + "--network regtest wallet send --address {to_address} --ordinal 5000000000", + )) + .expected_status(0) + .stdout_regex(format!( + "Sent ordinal 5000000000 to address {to_address}: [[:xdigit:]]{{64}}\n" + )) + .output() + .state; + + wallet + .sync(&state.blockchain, SyncOptions::default()) + .unwrap(); + + state.client.generate_to_address(1, &to_address).unwrap(); + + let output = Test::with_state(state) + .command(&format!( + "--network regtest list {}", + wallet.list_unspent().unwrap().first().unwrap().outpoint + )) + .expected_status(0) + .expected_stdout("[5000000000,9999999780)\n") + .output(); + + Test::with_state(output.state) + .command("--network regtest wallet identify") + .expected_status(0) + .expected_stdout("") + .run() +} + #[test] fn send_owned_ordinal() { let state = Test::new() From 0411cb12c49d0dcd6d6bbe414eb8fd3b83bf5bd8 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Aug 2022 14:13:08 -0400 Subject: [PATCH 08/13] Sort in increasing order --- src/subcommand/wallet/identify.rs | 47 ++++++++++++++++--------------- tests/wallet.rs | 2 +- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index 9225c71569..d4df67bd2a 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -3,33 +3,34 @@ use super::*; pub(crate) fn run(options: Options) -> Result { let index = Index::index(&options)?; - let ranges = Purse::load(&options)? - .wallet - .list_unspent()? + let utxos = Purse::load(&options)?.wallet.list_unspent()?; + + let lists = utxos .iter() - .map(|utxo| (utxo.clone(), index.list(utxo.outpoint).unwrap())) - .collect::)>>(); + .map(|utxo| index.list(utxo.outpoint)) + .collect::>, _>>()?; - for (utxo, range) in ranges { - match range { - Some(List::Unspent(range)) => { - for (start, _) in range { - let ordinal = Ordinal(start); + let mut ordinals = utxos + .iter() + .zip(lists.iter()) + .map(|(utxo, list)| match list { + Some(List::Unspent(ranges)) => Ok(( + utxo.clone(), + ranges.iter().map(|(start, _end)| Ordinal(*start)).collect(), + )), + Some(List::Spent(txid)) => Err(anyhow!( + "UTXO {} unspent in wallet but spent in index by transaction {txid}", + utxo.outpoint + )), + None => Ok((utxo.clone(), Vec::new())), + }) + .collect::)>, _>>()?; - let rarity = ordinal.rarity(); + ordinals.sort_by(|a, b| a.1.cmp(&b.1)); - if rarity != "common" { - println!("{ordinal} {rarity} {}", utxo.outpoint); - } - } - } - Some(List::Spent(txid)) => { - return Err(anyhow!( - "UTXO {} unspent in wallet but spent in index by transaction {txid}", - utxo.outpoint - )) - } - None => {} + for (utxo, ordinals) in ordinals { + for ordinal in ordinals { + println!("{ordinal} {} {}", ordinal.rarity(), utxo.outpoint); } } diff --git a/tests/wallet.rs b/tests/wallet.rs index 49dec15127..9892b9bf45 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -262,10 +262,10 @@ fn identify_multiple_ordinals() { .stdout_regex( " 5000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] + 10000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] 15000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] 20000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] 25000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] - 10000000000 uncommon [[:xdigit:]]{64}:[[:digit:]] " .unindent() .trim_start(), From 0d8ce89b10b7ad473e4099498165bc95e04bc6e8 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Aug 2022 14:18:04 -0400 Subject: [PATCH 09/13] Identify in test --- tests/wallet.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/wallet.rs b/tests/wallet.rs index 9892b9bf45..83dfd6a634 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -317,6 +317,12 @@ fn identify_sent_ordinal() { .stdout_regex("[[:xdigit:]]{64}:[[:digit:]] 5000000000\n") .output(); + let output = Test::with_state(output.state) + .command("--network regtest wallet identify") + .expected_status(0) + .stdout_regex("5000000000 uncommon [[:xdigit:]]{64}:[[:digit:]]\n") + .output(); + let wallet = Wallet::new( Bip84( ( From 30159581513fec8ebae7d0e217c4576dca5e356f Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Aug 2022 15:21:26 -0400 Subject: [PATCH 10/13] Add rarity enum --- src/main.rs | 2 + src/ordinal.rs | 45 +----------- src/rarity.rs | 92 +++++++++++++++++++++++++ src/subcommand/server/templates/home.rs | 2 +- src/subcommand/wallet/identify.rs | 40 +++++------ 5 files changed, 117 insertions(+), 64 deletions(-) create mode 100644 src/rarity.rs diff --git a/src/main.rs b/src/main.rs index da4ca54681..db3a0e047e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use { options::Options, ordinal::Ordinal, purse::Purse, + rarity::Rarity, sat_point::SatPoint, subcommand::Subcommand, }, @@ -87,6 +88,7 @@ mod ordinal; mod purse; mod sat_point; mod subcommand; +mod rarity; type Result = std::result::Result; diff --git a/src/ordinal.rs b/src/ordinal.rs index 83d6ca2583..dee240036e 100644 --- a/src/ordinal.rs +++ b/src/ordinal.rs @@ -44,27 +44,8 @@ impl Ordinal { format!("{}.{}", self.height(), self.third()) } - pub(crate) fn rarity(self) -> &'static str { - let Degree { - hour, - minute, - second, - third, - } = self.degree(); - - if hour == 0 && minute == 0 && second == 0 && third == 0 { - "mythic" - } else if minute == 0 && second == 0 && third == 0 { - "legendary" - } else if minute == 0 && third == 0 { - "epic" - } else if second == 0 && third == 0 { - "rare" - } else if third == 0 { - "uncommon" - } else { - "common" - } + pub(crate) fn rarity(self) -> Rarity { + self.into() } pub(crate) fn name(self) -> String { @@ -498,28 +479,6 @@ mod tests { assert_eq!(Ordinal(2067187500000000 + 1).cycle(), 1); } - #[test] - fn rarity() { - assert_eq!(Ordinal(0).rarity(), "mythic"); - assert_eq!(Ordinal(1).rarity(), "common"); - - assert_eq!(Ordinal(50 * 100_000_000 - 1).rarity(), "common"); - assert_eq!(Ordinal(50 * 100_000_000).rarity(), "uncommon"); - assert_eq!(Ordinal(50 * 100_000_000 + 1).rarity(), "common"); - - assert_eq!(Ordinal(50 * 100_000_000 * 2016 - 1).rarity(), "common"); - assert_eq!(Ordinal(50 * 100_000_000 * 2016).rarity(), "rare"); - assert_eq!(Ordinal(50 * 100_000_000 * 2016 + 1).rarity(), "common"); - - assert_eq!(Ordinal(50 * 100_000_000 * 210000 - 1).rarity(), "common"); - assert_eq!(Ordinal(50 * 100_000_000 * 210000).rarity(), "epic"); - assert_eq!(Ordinal(50 * 100_000_000 * 210000 + 1).rarity(), "common"); - - assert_eq!(Ordinal(2067187500000000 - 1).rarity(), "common"); - assert_eq!(Ordinal(2067187500000000).rarity(), "legendary"); - assert_eq!(Ordinal(2067187500000000 + 1).rarity(), "common"); - } - #[test] fn third() { assert_eq!(Ordinal(0).third(), 0); diff --git a/src/rarity.rs b/src/rarity.rs new file mode 100644 index 0000000000..a4bdc9b7eb --- /dev/null +++ b/src/rarity.rs @@ -0,0 +1,92 @@ +use super::*; + +#[derive(Debug, PartialEq, PartialOrd)] +pub(crate) enum Rarity { + Common, + Uncommon, + Rare, + Epic, + Legendary, + Mythic, +} + +impl Display for Rarity { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Common => "common", + Self::Uncommon => "uncommon", + Self::Rare => "rare", + Self::Epic => "epic", + Self::Legendary => "legendary", + Self::Mythic => "mythic", + } + ) + } +} + +impl From for Rarity { + fn from(ordinal: Ordinal) -> Self { + let Degree { + hour, + minute, + second, + third, + } = ordinal.degree(); + + if hour == 0 && minute == 0 && second == 0 && third == 0 { + Self::Mythic + } else if minute == 0 && second == 0 && third == 0 { + Self::Legendary + } else if minute == 0 && third == 0 { + Self::Epic + } else if second == 0 && third == 0 { + Self::Rare + } else if third == 0 { + Self::Uncommon + } else { + Self::Common + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn rarity() { + assert_eq!(Ordinal(0).rarity(), Rarity::Mythic); + assert_eq!(Ordinal(1).rarity(), Rarity::Common); + + assert_eq!(Ordinal(50 * 100_000_000 - 1).rarity(), Rarity::Common); + assert_eq!(Ordinal(50 * 100_000_000).rarity(), Rarity::Uncommon); + assert_eq!(Ordinal(50 * 100_000_000 + 1).rarity(), Rarity::Common); + + assert_eq!( + Ordinal(50 * 100_000_000 * 2016 - 1).rarity(), + Rarity::Common + ); + assert_eq!(Ordinal(50 * 100_000_000 * 2016).rarity(), Rarity::Rare); + assert_eq!( + Ordinal(50 * 100_000_000 * 2016 + 1).rarity(), + Rarity::Common + ); + + assert_eq!( + Ordinal(50 * 100_000_000 * 210000 - 1).rarity(), + Rarity::Common + ); + assert_eq!(Ordinal(50 * 100_000_000 * 210000).rarity(), Rarity::Epic); + assert_eq!( + Ordinal(50 * 100_000_000 * 210000 + 1).rarity(), + Rarity::Common + ); + + assert_eq!(Ordinal(2067187500000000 - 1).rarity(), Rarity::Common); + assert_eq!(Ordinal(2067187500000000).rarity(), Rarity::Legendary); + assert_eq!(Ordinal(2067187500000000 + 1).rarity(), Rarity::Common); + } +} diff --git a/src/subcommand/server/templates/home.rs b/src/subcommand/server/templates/home.rs index 2b3052f78f..ea7bcd15af 100644 --- a/src/subcommand/server/templates/home.rs +++ b/src/subcommand/server/templates/home.rs @@ -3,7 +3,7 @@ use super::*; #[derive(Display)] pub(crate) struct HomeHtml { last: u64, - blocks: Vec<(&'static str, BlockHash)>, + blocks: Vec<(Rarity, BlockHash)>, } impl HomeHtml { diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index d4df67bd2a..e322438c78 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -3,26 +3,26 @@ use super::*; pub(crate) fn run(options: Options) -> Result { let index = Index::index(&options)?; - let utxos = Purse::load(&options)?.wallet.list_unspent()?; - - let lists = utxos - .iter() - .map(|utxo| index.list(utxo.outpoint)) - .collect::>, _>>()?; - - let mut ordinals = utxos - .iter() - .zip(lists.iter()) - .map(|(utxo, list)| match list { - Some(List::Unspent(ranges)) => Ok(( - utxo.clone(), - ranges.iter().map(|(start, _end)| Ordinal(*start)).collect(), - )), - Some(List::Spent(txid)) => Err(anyhow!( - "UTXO {} unspent in wallet but spent in index by transaction {txid}", - utxo.outpoint - )), - None => Ok((utxo.clone(), Vec::new())), + let mut ordinals = Purse::load(&options)? + .wallet + .list_unspent()? + .into_iter() + .map(|utxo| { + index.list(utxo.outpoint).and_then(|list| match list { + Some(List::Unspent(ranges)) => Ok(( + utxo.clone(), + ranges + .iter() + .map(|(start, _end)| Ordinal(*start)) + .filter(|ordinal| ordinal.rarity() > Rarity::Common) + .collect(), + )), + Some(List::Spent(txid)) => Err(anyhow!( + "UTXO {} unspent in wallet but spent in index by transaction {txid}", + utxo.outpoint + )), + None => Ok((utxo.clone(), Vec::new())), + }) }) .collect::)>, _>>()?; From 77b2b5cb09ca34e2e0d9289903ddc63c1fc516f3 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Aug 2022 15:49:34 -0400 Subject: [PATCH 11/13] Better stuff --- src/subcommand/wallet/identify.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index e322438c78..09e5ce19c3 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -9,29 +9,30 @@ pub(crate) fn run(options: Options) -> Result { .into_iter() .map(|utxo| { index.list(utxo.outpoint).and_then(|list| match list { - Some(List::Unspent(ranges)) => Ok(( - utxo.clone(), + Some(List::Unspent(ranges)) => Ok( ranges - .iter() - .map(|(start, _end)| Ordinal(*start)) + .into_iter() + .map(|(start, _end)| Ordinal(start)) .filter(|ordinal| ordinal.rarity() > Rarity::Common) + .map(|ordinal| (ordinal, utxo.outpoint)) .collect(), - )), + ), Some(List::Spent(txid)) => Err(anyhow!( "UTXO {} unspent in wallet but spent in index by transaction {txid}", utxo.outpoint )), - None => Ok((utxo.clone(), Vec::new())), + None => Ok(Vec::new()), }) }) - .collect::)>, _>>()?; + .collect::>, _>>()? + .into_iter() + .flatten() + .collect::>(); - ordinals.sort_by(|a, b| a.1.cmp(&b.1)); + ordinals.sort_by(|(ordinal_a, _), (ordinal_b, _)| ordinal_a.cmp(&ordinal_b)); - for (utxo, ordinals) in ordinals { - for ordinal in ordinals { - println!("{ordinal} {} {}", ordinal.rarity(), utxo.outpoint); - } + for (ordinal, outpoint) in ordinals { + println!("{ordinal} {} {outpoint}", ordinal.rarity()); } Ok(()) From ea5575a121799d3bb233f3976eb5525fcb49a951 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Aug 2022 15:53:51 -0400 Subject: [PATCH 12/13] CLi[py] --- src/subcommand/wallet/identify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index 09e5ce19c3..9ae17e6f24 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -29,7 +29,7 @@ pub(crate) fn run(options: Options) -> Result { .flatten() .collect::>(); - ordinals.sort_by(|(ordinal_a, _), (ordinal_b, _)| ordinal_a.cmp(&ordinal_b)); + ordinals.sort_by(|(ordinal_a, _), (ordinal_b, _)| ordinal_a.cmp(ordinal_b)); for (ordinal, outpoint) in ordinals { println!("{ordinal} {} {outpoint}", ordinal.rarity()); From 1523efcd215fdbb6901f77ab7f193abc1f6562db Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Aug 2022 15:56:35 -0400 Subject: [PATCH 13/13] Format --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index db3a0e047e..60b4c5eedc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,9 +86,9 @@ mod nft; mod options; mod ordinal; mod purse; +mod rarity; mod sat_point; mod subcommand; -mod rarity; type Result = std::result::Result;